Skip to content

feat: cost/token tracking for Claude and Codex sessions#20

Merged
Wintersta7e merged 10 commits intomainfrom
feature/cost-tracking
Mar 30, 2026
Merged

feat: cost/token tracking for Claude and Codex sessions#20
Wintersta7e merged 10 commits intomainfrom
feature/cost-tracking

Conversation

@Wintersta7e
Copy link
Copy Markdown
Owner

Summary

  • Log adapters parse JSONL session logs for Claude Code and Codex CLI, extracting per-turn token usage
  • CostTracker discovers log files via WSL, tails them on a 3s poll, and pushes cumulative usage to the renderer over IPC
  • Cost badge in PaneTopbar shows USD cost + total processed tokens with Zap icon, accent-colored for visibility
  • Tooltip breaks down input, output, cache read, and cache write tokens

Key design decisions

  • Claude input_tokens excludes cache; Codex input_tokens includes cache — adapters normalize both to non-cached inputTokens, with cache read/write tracked separately
  • Claude JSONL logs streaming partials + final entries for same API call — adapter filters on stop_reason to prevent double-counting
  • Cost computed from model pricing maps (Claude: opus/sonnet/haiku tiers with 1.25× cache write, 0.1× cache read; Codex: per-model map)
  • Badge shows total processed tokens (all types) alongside cost so both numbers tell the same story

Introduces TokenUsage type, ZERO_USAGE constant, LogAdapter interface,
formatTokens/formatCost helpers, and createClaudeAdapter/createCodexAdapter
factories with 32 passing tests.

Co-Authored-By: Rooty
Discovers and tails agent log files via WSL polling, parsing token
usage through LogAdapter and pushing cost:update IPC to the renderer.

- Discovery phase: polls candidate dirs every 2s for up to 30s
- Tailing phase: polls bound file every 3s, handles partial lines and truncation
- 12 tests covering bind/unbind/destroy, discovery, tailing, partial lines, truncation, and IPC guard

Co-Authored-By: Rooty
Adds per-session token/cost tracking (inputTokens, outputTokens,
cacheReadTokens, cacheWriteTokens, totalCostUsd) with setSessionUsage
action and cleanup on removeSession.

Co-Authored-By: Rooty
- TerminalPane: bind cost tracking after PTY spawn, unbind on session dispose
- App.tsx: listen for cost:update IPC events, unbind on all close paths
- PaneTopbar: display cost/token badge with hover tooltip breakdown

Co-Authored-By: Rooty
bindSession receives Windows paths from renderer (e.g., E:\H\LocalAI).
Convert to WSL paths via toWslPath before building Claude log directory
slug. Also store projectPath separately from cwd for Claude's
project-indexed log structure.

Co-Authored-By: Rooty
Codex JSONL uses payload.info.total_token_usage (not payload directly).
Model comes from turn_context events, not token_count events.
First token_count has info: null (just rate limits) — now skipped.
Added gpt-5.3/5.4 to pricing map.

Co-Authored-By: Rooty
…default

When a session is opened with a specific agent (e.g., Codex on a
project whose default is Claude), the topbar now shows the actual
agent name instead of always showing the project default.

Co-Authored-By: Rooty
Codex input_tokens includes cached_input_tokens as a subset, unlike
Claude where input_tokens already excludes cache reads. Badge was
showing inflated totals (e.g. 12k for a simple message). Now both
adapters report non-cached input only — badge shows meaningful count.

Co-Authored-By: Rooty
…e writes

Three fixes for Claude cost tracking:
- Compute cost from model pricing (Claude JSONL has no costUSD field)
  with proper cache rates (writes 1.25×, reads 0.1×)
- Skip streaming partials (stop_reason: null) to prevent double-counting
- Badge now shows inputTokens + cacheWriteTokens + outputTokens so
  first-turn cache writes (real processing) are visible, not hidden

Also adds Zap icon and accent color to cost badge for visibility.

Co-Authored-By: Rooty
Token count now includes all types (input + cache read + cache write +
output) so it tracks proportionally with cost. No more mismatch where
$0.18 sits next to "87 tokens".

Co-Authored-By: Rooty
@Wintersta7e Wintersta7e merged commit 7ae5a3f into main Mar 30, 2026
1 check passed
@Wintersta7e Wintersta7e deleted the feature/cost-tracking branch March 30, 2026 13:21
Wintersta7e added a commit that referenced this pull request Mar 30, 2026
Worktree isolation (PR #19) + cost/token tracking (PR #20).
614 tests.

Co-Authored-By: Rooty
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.

1 participant