Skip to content

Derive project/session stats from transcripts instead of history.jsonl - #2

Open
vvzvlad wants to merge 1 commit into
jhammant:mainfrom
vvzvlad:fix/transcript-based-project-stats
Open

Derive project/session stats from transcripts instead of history.jsonl#2
vvzvlad wants to merge 1 commit into
jhammant:mainfrom
vvzvlad:fix/transcript-based-project-stats

Conversation

@vvzvlad

@vvzvlad vvzvlad commented Jun 9, 2026

Copy link
Copy Markdown

Problem

list_projects, find_patterns, get_project_context and by-project lookup in get_session_summary all read conversation statistics from ~/.claude/history.jsonl through parseHistoryFile().

I use Claude Code almost only through VS Code extension / Agent SDK, and in this setup ~/.claude/history.jsonl is almost never written — mine had captured only few slash commands — even there was hundreds of real session transcripts under ~/.claude/projects/. So list_projects showed 5 projects / 6 sessions, but actually i had 17 projects and 300+ sessions. Full-text search tools were fine, because they already index the transcripts; only history.jsonl-based tools undercount.

Fix

I add src/parsers/transcript-history.ts, which build the same HistoryEntry[] shape from per-session transcripts instead of history.jsonl, so all downstream helpers and tool bodies stay unchanged — only the data source swaps:

  • parseSessionUserPrompts(content, sessionId, fallbackProject) — pure, IO-free, unit-testable. Turns one transcript into one HistoryEntry per genuine user prompt. Skips meta turns (isMeta), tool-result turns (toolUseResult), empty turns, and Claude Code injected non-prompt user turns (<task-notification>, <ide_opened_file>, <ide_selection>, slash-command wrappers, <local-command-stdout>, ...). The project is resolved from in-transcript cwd (with fallback to the encoded project dir, which extractProjectName already handle).
  • parseTranscriptHistory() — enumerates all session files (reuse enumerateSessionFiles) with per-file cache keyed on mtime + size, so on next calls only changed files are re-read; entries for deleted files are pruned.

Then switch the four tools to parseTranscriptHistory(). parseHistoryFile() is left intact (still used by its test). Added tests/parsers/transcript-history.test.ts.

Result

  • list_projects: 5 → 17 projects, with correct session/message counts and real cwd paths.
  • find_patterns: now reports 325 sessions with meaningful topic / activity / issue breakdowns instead of almost empty sample.
  • Filtering out injected turns removes ~36% of false "messages" which otherwise inflate counts and pollute topic analysis.

npx tsc compiles clean and full vitest suite passes (86 tests, including new parser tests). No behavior change for search/index/sync paths.

list_projects, find_patterns, get_project_context and get_session_summary read
conversation stats from ~/.claude/history.jsonl, which is barely populated under
VSCode-extension / Agent-SDK usage (only slash commands land there). They reported
~5 projects / 6 sessions while the real per-session transcripts in ~/.claude/projects
hold hundreds of sessions across dozens of projects.

Add src/parsers/transcript-history.ts:
- parseSessionUserPrompts(): pure parser -> HistoryEntry[], one entry per genuine
  user prompt; skips meta turns, tool-result turns, empty turns and Claude Code
  injected non-prompt turns (<task-notification>, <ide_opened_file>, slash-command
  wrappers, ...). Project resolved from the in-transcript cwd (encoded dir fallback).
- parseTranscriptHistory(): enumerates all session files with a per-file cache
  (mtime+size) so only changed files are re-read; prunes deleted files.

Switch the four tools to parseTranscriptHistory(); HistoryEntry shape and all
downstream helpers are unchanged. parseHistoryFile() is left intact.

Add tests/parsers/transcript-history.test.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@jhammant jhammant left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies for the very slow response — two months is not the turnaround you deserved.

Reviewed and approving. Deriving from the session transcripts instead of history.jsonl is correct, and the undercount you describe is real: under the VSCode extension and Agent SDK that file barely gets written, so list_projects and find_patterns were reporting a fraction of actual usage.

Resolving the project from the first cwd in the file rather than decoding the dashed directory name is the better call too — it handles worktrees, which the encoded form can't do unambiguously. Nice touch keeping HistoryEntry[] as the boundary so the tool bodies didn't have to change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants