feat(claude): scan ~/.claude-internal and subagent sessions#11
Conversation
The Claude provider previously only scanned ~/.claude/projects/ for top-level JSONL files, missing two sources of token usage data: 1. ~/.claude-internal/projects/ was completely ignored 2. <session-uuid>/subagents/agent-*.jsonl files in both directories were skipped Extract collectPaths() helper from CollectSessions() to walk a single base directory. When no --claude-dir override is set, scan both default directories and merge results. During the walk, probe subdirectories for subagents/ children and collect their JSONL files as independent sessions. Subagent messageIds do not overlap with parent sessions (verified on real data), so no dedup changes are needed. The existing --claude-dir flag continues to work as a single-directory override. Co-Authored-By: Claude Opus 4.6 <[email protected]>
There was a problem hiding this comment.
Pull request overview
This PR updates the Claude provider’s session discovery so it can scan both the standard Claude projects directory and the ~/.claude-internal projects directory, and it adds support for treating subagent JSONL files as independent sessions (including E2E coverage via new testdata).
Changes:
- Update Claude provider session collection to scan multiple default base directories and discover subagent JSONL sessions under
<session>/subagents/. - Add unit + E2E tests and new E2E Claude session fixtures to validate subagent discovery and JSON outputs.
- Add an
openspec/config.yamlfile (not referenced elsewhere in the repo).
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| provider/claude/parser.go | Scan both ~/.claude/projects and ~/.claude-internal/projects, and collect subagent JSONL session paths via collectPaths. |
| provider/claude/parser_test.go | Add unit tests for multi-base-dir scanning, subagent discovery, and missing directory handling. |
| e2e/e2e_test.go | Add E2E tests asserting subagent sessions appear in session --json and daily --json output. |
| e2e/testdata/claude-sessions/project-test/session-main.jsonl | New Claude main session fixture for E2E. |
| e2e/testdata/claude-sessions/project-test/session-main/subagents/agent-sub1.jsonl | New Claude subagent fixture for E2E. |
| openspec/config.yaml | New OpenSpec config template file added. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| projectDirs, err := os.ReadDir(baseDir) | ||
| if err != nil { | ||
| return nil, err | ||
| return // skip non-existent or unreadable directories | ||
| } |
There was a problem hiding this comment.
collectPaths currently returns on any ReadDir error (including permission/IO errors), which changes CollectSessions behavior from returning an error to silently producing no sessions. Consider only skipping os.IsNotExist(err) (to handle ~/.claude-internal missing) and propagating other errors back to CollectSessions so misconfigurations/permission issues are visible.
| func TestCollectClaudeSessions_MissingDirectoryGraceful(t *testing.T) { | ||
| // Point to a non-existent directory — collectPaths should skip it | ||
| baseDir := filepath.Join(t.TempDir(), "nonexistent") | ||
|
|
||
| prov := &Provider{} | ||
| result, err := prov.CollectSessions(baseDir) | ||
| if err != nil { | ||
| t.Fatalf("unexpected error: %v", err) | ||
| } | ||
| if len(result) != 0 { | ||
| t.Errorf("got %d sessions, want 0", len(result)) | ||
| } |
There was a problem hiding this comment.
This test asserts that an explicitly provided baseDir that does not exist should be silently skipped. That’s a behavioral change from the previous implementation (which returned an error) and could hide a mistyped --claude-dir. If the silent-skip behavior is only meant for the default ~/.claude-internal path, consider updating the test to expect an error when the user explicitly passes a missing directory.
| schema: spec-driven | ||
|
|
||
| # Project context (optional) |
There was a problem hiding this comment.
openspec/config.yaml is introduced in this PR but isn't mentioned in the PR description. If this file is required for tooling, consider documenting that in the PR summary; otherwise it may be accidental/unrelated and should be split into a separate PR or removed.
…pec/config.yaml Address PR review feedback: - collectPaths now returns error; only os.ErrNotExist is silently skipped for default directories. Permission/IO errors are propagated. - Explicit --claude-dir pointing to a non-existent path returns an error instead of silently producing empty results. - Remove accidentally included openspec/config.yaml from this PR. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Summary
~/.claude/projects/and~/.claude-internal/projects/by default (previously only~/.claude/projects/)<session-uuid>/subagents/agent-*.jsonlfiles in both directories, treating each subagent as an independent sessioncollectPaths()helper for reusable directory walking with graceful handling of missing directoriesDetails
--claude-dirflag override continues to work (backward compatible)~/.claude-internal/may not exist for all users)Test plan
session --jsonanddaily --jsonoutputmake testpasses with-race -covergo vetpasses🤖 Generated with Claude Code