Skip to content

feat: add shelltime cc backfill and shelltime codex backfill - #312

Merged
AnnatarHe merged 3 commits into
mainfrom
claude/gracious-goodall-nf2xin
Oct 5, 2026
Merged

AnnatarHe merged 3 commits into
mainfrom
claude/gracious-goodall-nf2xin

Conversation

@AnnatarHe

Copy link
Copy Markdown
Contributor

Summary

Adds two commands that upload past Claude Code and Codex usage from the transcripts both tools keep on disk. They fill gaps live OTEL tracking missed: usage from before cc install / codex install, or from while the daemon was down. Events are uploaded as the same kinds the live pipeline sends (user_prompt, api_request, tool_result, Codex sse_event/response.completed, conversation_starts), so dashboards, session summaries and MCP tools pick them up.

Requires shelltime/server#494. Against an older server the command stops with "server does not support backfill yet".

shelltime cc backfill --dry-run     # preview per day, upload nothing
shelltime cc backfill               # upload Claude Code sessions
shelltime codex backfill --since 2026-09-01 --no-prompts

How it works

  1. Parse local transcripts. The approach follows ryoppippi/ccusage, with these choices:
    • Claude Code reads ~/.claude/projects, ~/.config/claude/projects, or the CLAUDE_CONFIG_DIR list.
      • One API response is written as several lines that repeat its usage, so api_request is deduplicated globally by message.id:requestId, keeping the most complete usage.
      • Prompts come only from human lines. Meta, subagent, compaction, local-command, interruption and notification lines are excluded.
      • Each tool call is paired with its result. Only file_path / path from the parameters is kept; commands and file contents are never uploaded.
      • Subagent transcripts add to their parent session. History copied into resumed sessions is counted once.
    • Codex reads ~/.codex/sessions, archived_sessions, or CODEX_HOME.
      • Token counts come from last_token_usage, or from the change in the cumulative total. Null and repeated counts are skipped.
      • Tool results carry exit code and duration.
      • History copied into forked rollouts is dropped.
      • Old rollouts with no user_message events fall back to the conversation's own user messages.
  2. Ask the server which sessions it already has. Sessions it tracked live, archived, or already received in full are skipped. Sessions still running (activity in the last 30 min) are held back.
  3. Upload batches of up to 500 events, 50 completed sessions and 8 MiB. Long prompts and tool arguments are capped. A session is listed as completed only in the request carrying its last event, so the server builds its summary once everything is stored. 5xx, 429 and network errors are retried with backoff; other 4xx errors stop the run.
  4. Call /complete so the server refreshes the activity heatmap and caches for the uploaded range.

Event ids are bf1: plus a sha256 of a natural key (message/request id, prompt uuid, tool call id, and so on). They don't depend on the session, so re-runs and copied history are idempotent.

Other changes

  • SendHTTPRequestJSON returns a typed HTTPStatusError, so callers can tell retryable errors from fatal ones. The error text is unchanged.
  • Backfill events use their own wire type with pointer fields. The live AICodeOtelEvent has success,omitempty on a bool, which drops failed tool calls; backfill sends "success": false.
  • aiCodeResourceIdentity() is extracted, so backfilled events carry the same user.name / machine.name / team.id as live ones.
  • README: "Backfilling AI Usage" section and command table rows.

Test plan

  • Unit tests for the Claude parser:
    • partial streamed usage and repeated usage lines
    • resumed copy credited to the original session; subagent file
    • every skipped prompt kind, slash-command normalisation, is_error sent as false
    • --no-prompts, prompt cap, CLAUDE_CONFIG_DIR list, stable ids
  • Unit tests for the Codex parser:
    • null and repeated counts, last vs delta usage
    • fork dedup when the copy appears before any turn context
    • model fallback, both tool output formats, legacy rollouts
  • Unit tests for helpers: batch packing (event, byte and completed caps), session selection, a 10 MB JSONL line, file discovery with a symlinked root, a golden event id checked against Python.
  • Command tests against an httptest server:
    • only new or partly uploaded sessions are sent
    • large backfills are split; --ai-summary is passed through; --dry-run only checks status
    • a 503 or 429 is retried; a 400 aborts; a 404 explains the server is too old; a missing token is reported
    • Codex end to end; flag parsing
  • go vet ./... and go test ./... pass.
  • End-to-end run against shelltime/server#494 locally (Postgres + Redis), using a real Claude Code 2.1.289 transcript with 4 subagent files:
    • the dry run showed 1 session, 519 events, 2 prompts, 222 requests
    • the upload sent 2 batches; all 222 requests were costed and the summary matched (tokens, 295 tool calls with 5 failed, cwd, version)
    • a second run reported "already uploaded" and stored nothing new
    • Claude token totals matched an independent Python implementation of ccusage's dedup exactly

🤖 Generated with Claude Code

https://claude.ai/code/session_01LMCwtubXzBYhQTnX44vhzF


Generated by Claude Code

claude added 3 commits October 5, 2026 11:24
- SendHTTPRequestJSON now returns a typed HTTPStatusError for non-2xx
  responses so callers can tell retryable errors from client errors.
  The error text is unchanged.
- Wire types and senders for the server's /api/v1/cc/backfill
  endpoints. Backfill events use pointer fields so a failed tool call
  is sent as "success": false instead of being dropped by omitempty.
- Shared helpers for the transcript parsers: stable "bf1:" event ids
  from natural keys, a JSONL reader without a line length cap, file
  discovery, session selection, and request packing that keeps whole
  sessions together and marks a session completed on its last batch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LMCwtubXzBYhQTnX44vhzF
Rebuild historical sessions from local transcripts as backfill events
matching what the live OTEL pipeline records.

Claude Code (~/.claude/projects, ~/.config/claude/projects or
CLAUDE_CONFIG_DIR): one api_request per message id + request id, keeping
the most complete usage of a streamed response; human prompts only
(no meta, subagent, compaction, local-command or notification lines);
tool results paired with their tool calls, keeping only file paths of
the parameters. Items copied into resumed sessions are credited once,
to the session that started first.

Codex (~/.codex/sessions, archived_sessions or CODEX_HOME):
conversation_starts, user prompts, response.completed token counts from
last_token_usage or the cumulative delta (skipping null and repeated
counts), and tool results with exit code and duration. Items copied
into forked rollouts are dropped.

Batches are also bounded by encoded size, and long prompts and tool
arguments are capped, so a batch stays under the server's body limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LMCwtubXzBYhQTnX44vhzF
…fill`

Upload past Claude Code and Codex usage from local transcripts that live
OTEL tracking missed (before `cc install` or while the daemon was down).

The command asks the server which sessions it already has, skips those
tracked live, archived or already uploaded, and uploads the rest in
batches with retries on server errors. Sessions still running are held
back. When it finishes it asks the server to refresh activity data and
caches for the uploaded range.

Flags: --since/--until, --dry-run (per-day preview), --no-prompts and
--ai-summary (opt-in, uses AI credits).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LMCwtubXzBYhQTnX44vhzF
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@claude

claude Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@codecov

codecov Bot commented Oct 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.42308% with 99 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
model/aicode_backfill_codex.go 85.76% 39 Missing ⚠️
model/aicode_backfill_claude.go 89.43% 26 Missing ⚠️
commands/aicode_backfill.go 90.99% 20 Missing ⚠️
model/aicode_backfill_common.go 91.72% 12 Missing ⚠️
model/api_aicode_backfill.go 95.00% 2 Missing ⚠️
Flag Coverage Δ
unittests 84.57% <89.42%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
commands/cc.go 78.57% <ø> (+10.82%) ⬆️
commands/codex.go 100.00% <ø> (ø)
model/aicode_otel_claude_settings.go 85.35% <100.00%> (+11.82%) ⬆️
model/api.base.go 92.20% <100.00%> (+3.74%) ⬆️
model/api_aicode_backfill.go 95.00% <95.00%> (ø)
model/aicode_backfill_common.go 91.72% <91.72%> (ø)
commands/aicode_backfill.go 90.99% <90.99%> (ø)
model/aicode_backfill_claude.go 89.43% <89.43%> (ø)
model/aicode_backfill_codex.go 85.76% <85.76%> (ø)

... and 108 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@AnnatarHe
AnnatarHe merged commit 8feb0bc into main Oct 5, 2026
4 checks passed
@AnnatarHe
AnnatarHe deleted the claude/gracious-goodall-nf2xin branch October 5, 2026 12:36
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