Repository navigation
feat(analytics): GitHub-backed code source registry for codebase analytics #1133
Description
Activity
Additional Requirement: Per-Source Access Control
Code sources need to support multi-user sharing. A source registered by one user can be shared with specific other users or made accessible to all users.
Access Model
Each
CodeSourcerecord gets an access field:Field Description owner_idUser who created the source accessprivate|shared|publicshared_withList of user IDs (for sharedaccess)Rules
private— only the owner can see, sync, and analyze this source (default)shared— owner can grant specific users read/sync accesspublic— all authenticated users can use this source (admin-set only)
UI
- Source management panel shows an access badge per source (
Private,Shared,Public) - Owner can click "Share" → pick users from a list → grant/revoke access
- Shared users see the source in their project selector but cannot edit/delete it
- Credential is resolved server-side — shared users do NOT see the underlying GitHub token
API additions
POST /api/analytics/codebase/sources/{id}/share body: { user_ids: [...], access: "shared" | "private" | "public" } GET /api/analytics/codebase/sources — already filters by: owned by me OR shared with me OR publicThis also means the
/sourceslist endpoint must filter by the requesting user's identity.Add to implementation tasks:
- Backend:
access+shared_withfields onCodeSourcemodel - Backend: Filter
GET /sourceslist by user access - Backend:
POST /sources/{id}/shareendpoint - Frontend: Access badge on source list
- Frontend: Share modal with user picker
Additional Requirement: Analysis Job Queue
Currently
indexing.pyrejects a second index request if one is already running (status: already_running). Instead, new requests should be queued and executed automatically after the running job finishes.Behaviour
- Only one analysis job runs at a time (unchanged)
- Additional
POST /api/analytics/codebase/indexrequests are queued, not rejected - When a job finishes (completed, failed, or cancelled), the next queued job starts automatically
- Queue is FIFO per source — if the same source is already queued, deduplicate (don't add it twice)
- Queue survives in-process (no persistence needed for now — restart clears it)
Queue State
running: { task_id, source_id, started_at } queue: [ { source_id, queued_at, requested_by }, ... ]API additions/changes
GET /api/analytics/codebase/index/queue → { running: {...} | null, queue: [...], queue_length: N } DELETE /api/analytics/codebase/index/queue/{source_id} → remove a source from the queue (cancel before it starts)POST /api/analytics/codebase/indexresponse changes:- If nothing running →
{ status: "started", task_id: "..." }(same as today) - If another job running →
{ status: "queued", position: 2, message: "Queued behind current job" }(NEW — no longer an error)
Frontend
- Progress/status area shows both the running job AND the queue
- "X jobs queued" indicator
- Ability to remove a source from the queue before it starts
- When a queued job starts, the UI transitions automatically (same polling mechanism)
Implementation notes
- Auto-dequeue logic goes in the existing
_create_cleanup_callback— when a task finishes, pop the next item from the queue and start it - Queue stored as
asyncio.Queueor a plaindequewith the existing_tasks_lock - Deduplication check on enqueue: if
source_idalready in queue, return existing position instead of adding again
Add to implementation tasks:
- Backend: In-memory FIFO queue (
deque) with deduplication bysource_id - Backend: Auto-start next job in
_create_cleanup_callback - Backend:
GET /index/queuestatus endpoint - Backend:
DELETE /index/queue/{source_id}cancel-before-start endpoint - Backend: Update
POST /indexresponse —queuedstatus instead of error - Frontend: Queue status display (running + queued jobs)
- Frontend: Remove-from-queue button
Additional Requirement: Repo Sync / Update
The
POST /api/analytics/codebase/sources/{id}/syncendpoint already covers initial clone, but needs to be explicit about update behaviour:- If clone path exists →
git pull --rebase(pick up latest commits on the configured branch) - If clone path missing → full
git clone --depth=1 - If branch changed since last sync → re-clone (shallow clone does not support branch switch via pull)
- Sync result stored on the source:
last_synced,last_commit_sha,status
Auto-sync options (future, not MVP)
Add
auto_syncflag andsync_interval_minutestoCodeSourcemodel so sources can be configured to pull on a schedule. MVP = manual sync only.Sync-then-analyse flow
Common workflow: "update the repo, then run analysis." Support chaining in one request:
POST /api/analytics/codebase/sources/{id}/sync-and-indexEquivalent to: sync → on completion → enqueue index job. Returns a
sync_task_idand aqueued_index_positionso the frontend (and skill) can track both steps.Add to implementation tasks:
- Backend:
git pull --rebasepath in sync handler (detect existing clone) - Backend:
sync_and_indexchained endpoint - Frontend: "Update & Analyse" button alongside existing "Sync" and "Analyse" buttons
- If clone path exists →
Additional Requirement: Code Analytics Skill (AutoBot Chat Integration)
A builtin skill so users can trigger code analysis conversationally and receive results back in chat.
Skill:
code-analysisLocation:
autobot-backend/skills/builtin/code_analysis.pyFollows the same pattern as
CodeReviewSkill(BaseSkill+SkillManifest).Actions
Action Description analyze_sourceRun analysis on a registered source by name or ID analyze_repoRegister-and-analyze an ad-hoc repo URL (no pre-registration needed) get_resultsFetch results for a completed analysis job list_sourcesList available code sources the user has access to Example conversation
User: Analyse the AutoBot Production repo and tell me about code quality. AutoBot: I'll run a code analysis on AutoBot Production. Syncing the repo first... ✓ Repo synced (branch: Dev_new_gui, commit: a1b2c3d) ⏳ Analysis queued (position 1 in queue) [30 seconds later...] ✅ Analysis complete — here's the summary: 📊 Code Quality Report — AutoBot Production ───────────────────────────────────────── Files analysed: 1,247 Lines of code: 89,432 Languages: Python (68%), TypeScript (28%), Other (4%) 🔴 Issues requiring attention (23) • 8 functions exceed 65-line limit • 12 bare except clauses • 3 hardcoded IP addresses 🟡 Warnings (41) • 29 missing UTF-8 encoding declarations • 12 direct Redis connections (use get_redis_client) 🟢 Health score: 74/100 Full report available at /analytics/codebase (source: AutoBot Production, job: abc123...)Ad-hoc repo (no pre-registration)
User: Run analysis on github.com/customerX/api-service branch main, use the github_token_customerX credential. AutoBot: Creating a temporary code source for customerX/api-service... [follows same sync → queue → results flow]Skill parameters
SkillManifest( name="code-analysis", tools=["analyze_source", "analyze_repo", "get_results", "list_sources"], triggers=["manual"], # chat-invoked only config={ "default_source_id": SkillConfigField(type="string", default=None), "include_in_knowledge_base": SkillConfigField(type="bool", default=False), "report_detail_level": SkillConfigField( type="string", default="summary", choices=["summary", "detailed", "full"] ), } )
Implementation notes
- Skill polls
/api/analytics/codebase/index/status/{task_id}(existing endpoint) until complete - Results fetched from
/api/analytics/codebase/statsand/report(existing endpoints) - Skill formats the JSON report into a human-readable chat message
include_in_knowledge_base=Truetriggers knowledge ingestion post-analysis- For ad-hoc repos: creates a
privatesource scoped to the requesting user, auto-cleans after analysis (or keeps if user says "save this source")
Add to implementation tasks:
- Backend:
skills/builtin/code_analysis.py—CodeAnalysisSkill - Backend:
analyze_sourceaction (resolve source → sync if stale → queue index → poll → format result) - Backend:
analyze_repoaction (register temp source → same flow) - Backend:
list_sourcesaction (proxy to registry filtered by user access) - Backend: Result formatter (JSON stats → readable chat markdown)
- Backend: Register skill in skill registry
- Skill polls
✅ Implemented in commits eba722b (frontend) + 95844d0 (backend) on Dev_new_gui.
Changes:
Backend:
source_models.py—CodeSourcePydantic model with GitHub/local types, status, access controlsource_storage.py— Redis CRUD layer (analytics DB) with visibility-filtered listingendpoints/sources.py— CRUD + async sync (clone/pull) + share endpoints at/sourcesendpoints/queue.py—GET /index/queue,DELETE /index/queue/{source_id}scanner.py— Added_index_queue: dequefor FIFO job queuingendpoints/indexing.py— Acceptssource_id, queues requests when busy, auto-dequeues on completionrouter.py— Registered sources + queue routers
Frontend:
SourceManager.vue— Source list panel with CRUD, status/access badges, queue display, auto-refreshAddSourceModal.vue— Create/edit modal with GitHub/local toggle, credential picker, access selectorShareSourceModal.vue— Access control dialog with user picker for shared modeAnalyticsHeader.vue— Source selector dropdown + Manage Sources button (backward-compatible)CodebaseAnalytics.vue— Wired source management,source_idin index POST, KB opt-in post-index
Verification:
- ✅ All pre-commit checks passed (black, isort, flake8, bandit, no hardcoded values)
- ✅ No print()/console.* violations
- ✅ Function length compliant
- ✅ Redis client uses canonical
get_redis_client(database="analytics")
Summary
Add a Code Source Registry to codebase analytics so the system can pull code from GitHub (or other VCS) repositories using stored credentials, rather than relying on local filesystem paths. Supports multiple repos/projects, customer code analysis, automation reuse, and optional knowledge base ingestion.
Problem
The current
/analytics/codebasepage requires a local file path (/opt/autobot/...). In distributed infrastructure you cannot rely on local folders — code must be pulled from the authoritative source (GitHub) with proper credentials. Multiple projects/customers also need project-switching support.Design
Code Source Registry
Each registered source is stored persistently (Redis or DB):
idnamesource_typegithub|localrepoowner/repo(GitHub mode)branchDev_new_guicredential_nameclone_path/opt/autobot/data/code-sources/<id>/last_syncedstatusconfigured|syncing|ready|errorBackend API
POST /api/analytics/codebase/indexupdated to acceptsource_idin addition toroot_path(backward compatible).Clone Strategy
git clone --depth=1 --branch <branch> https://<token>@github.com/<repo> <clone_path>git pullif clone path exists, else re-clone/opt/autobot/data/code-sources/<source-id>/source_id→ local pathFrontend
Knowledge Base (opt-in)
Credentials
SecretType.TOKEN/SecretType.API_KEYfromapi/secrets.pyImplementation Tasks
CodeSourcemodel + Redis/DB storage layer/api/analytics/codebase/sources)GitRepoSyncpattern fromskills/sync/git_sync.pyindexing.pyto acceptsource_id(resolve to clone path)Notes
/opt/autobot/data/code-sources/— never hardcode dev machine pathsGitRepoSyncinskills/sync/git_sync.pyalready handles clone logic — extend it for persistent paths and private reposroot_pathinIndexCodebaseRequeststill workssource_idor resolved path)