Implement the following plan:
Git-linked trace discovery
Context
The post-commit hook writes trace IDs to refs/notes/traces as lines like traces:<externalId> or traces:<externalId> <url>. Collaborators who fetch these notes have the IDs locally but can't see the traces in the TUI. This feature reads git notes on TUI startup, queries the API for traces in the same repo, syncs unknown ones into the local database, and shows them in the list.
Design decisions
Two discovery sources. Git notes give trace IDs tied to specific commits. The API filtered by gitRemoteUrl gives all namespace traces for the repo. Together they cover both explicit (note-attached) and implicit (same-repo) discovery.
Namespace-scoped API query. Filters by the user's active namespace only, so public forks don't flood you with strangers' traces.
TUI startup only, non-blocking. Runs once after the initial trace list loads, in the background. Doesn't block TUI rendering. Triggers a list refresh if new traces are found.
Metadata only, no message content. Discovery syncs trace metadata (title, agent, git fields, shared URL) but not full message content. The user can run traces sync <id> or open the trace in detail view to pull content later. This keeps startup fast.
Changes
1. API: internal query -- api/convex/internal/traces.ts
New query using the existing by_gitRemoteUrl index:
typescript
Index is on gitRemoteUrl only, so filter namespaceId in memory after the index scan. Result set is small (bounded by limit).
2. API: service layer -- api/convex/services/traces.ts
New function listTracesByRepo(ctx, auth, gitRemoteUrl, limit) that calls the internal query and maps results through mapTraceSummary.
3. API: HTTP route -- api/convex/http/v1/traces.ts
Extend GET /v1/traces to accept optional gitRemoteUrl query parameter. When present, delegates to listTracesByRepo. Otherwise falls through to existing listTraces.
4. CLI API client -- cli/src/services/api.ts
Add to Api type:
typescript
Calls GET /v1/traces?gitRemoteUrl=<encoded>&limit=<n>.
5. Git notes reader -- cli/src/core/git.ts
New exported function:
typescript
Runs git log --notes=traces --format="%H %N" -<maxRefs> (default 20). Parses lines matching traces:<id> or traces:<id> <url>. Deduplicates by externalId.
6. Discovery service -- cli/src/services/discovery.ts (new)
typescript
Flow:
resolveGitInfoCached(directory) to get remoteUrl
- Early return if no
remoteUrl or API not authenticated
- In parallel:
readTraceNotes(directory) + api.listTracesByRepo(remoteUrl)
- Collect all externalIds from both sources, deduplicate
- Check store for each -- skip already-known traces
- For each unknown trace, call
api.getTrace(externalId) to get metadata
- Upsert into store with
sharedUrl built from frontendUrl + /s/ + trace.id
- Return count of newly synced traces
7. TUI integration -- cli/src/tui/hooks/useAppState.ts
After initial load completes (after setLoading(false), around line 1197), add non-blocking background call:
typescript
8. Tests
cli/src/core/git.test.ts -- readTraceNotes:
- Parses lines with and without URLs
- Handles empty notes, malformed lines, deduplication
cli/src/services/discovery.test.ts (new) -- discoverRepoTraces:
- Mocks API and store; verifies upserts for unknown traces
- Skips already-known traces
- Returns early when no remote URL
- Handles API errors gracefully
Files
api/convex/internal/traces.ts # _listByGitRemoteUrl query
api/convex/services/traces.ts # listTracesByRepo
api/convex/http/v1/traces.ts # extend GET /v1/traces
cli/src/core/git.ts # readTraceNotes
cli/src/services/api.ts # listTracesByRepo on Api type
cli/src/services/discovery.ts # NEW
cli/src/tui/hooks/useAppState.ts # background discovery on startup
cli/src/core/git.test.ts # readTraceNotes tests
cli/src/services/discovery.test.ts # NEW
Verification
cd api && bun test -- all tests pass
cd cli && bun test -- all tests pass
- Manual: in a repo with trace notes, open TUI, confirm remote traces appear after a moment
- Manual:
traces sync <id> still works for pulling full content of a single trace
If you need specific details from before exiting plan mode (like exact code snippets, error messages, or content you generated), read the full transcript at: /Users/andrew/.claude/projects/-Users-andrew-code-traces-traces/bdc119d9-81ae-4a4a-8f7c-dba2fd4d3b97.jsonl