Skip to content

feat: add cross-project session cost tracking ledger#1487

Open
YoungMoneyInvestments wants to merge 2 commits intoruvnet:mainfrom
YoungMoneyInvestments:feat/cost-ledger-tracking
Open

feat: add cross-project session cost tracking ledger#1487
YoungMoneyInvestments wants to merge 2 commits intoruvnet:mainfrom
YoungMoneyInvestments:feat/cost-ledger-tracking

Conversation

@YoungMoneyInvestments
Copy link
Copy Markdown

Summary

Adds cost-ledger.cjs — a cross-project session cost tracking system that records and reports Claude Code API spend over time.

Problem: Claude Code shows per-session cost in the statusline ($X.XX), but this data is lost when the session ends. There's no way to see daily, weekly, monthly, or annual spend across projects.

Solution: A JSONL-based cost ledger that:

  • Automatically records session cost via the session-end hook
  • Stores entries at ~/.claude/cost-ledger.jsonl (global, cross-project)
  • Provides pretty-printed and JSON reports with multiple time granularities

Changes

  • helpers-generator.ts: Added generateCostLedger() function (new helper), wired cost recording into session-end handler, added to generateHelpers() map
  • executor.ts: Installs cost-ledger.cjs to both project .claude/helpers/ and global ~/.claude/helpers/ during init

Usage

# Automatic — records on every session end (no user action needed)

# Manual reports
node ~/.claude/helpers/cost-ledger.cjs report            # Last 30 days by project
node ~/.claude/helpers/cost-ledger.cjs report --daily     # Daily breakdown
node ~/.claude/helpers/cost-ledger.cjs report --weekly    # Weekly breakdown
node ~/.claude/helpers/cost-ledger.cjs report --monthly   # Monthly breakdown  
node ~/.claude/helpers/cost-ledger.cjs report --annual    # Annual breakdown
node ~/.claude/helpers/cost-ledger.cjs report --project myapp  # Filter by project
node ~/.claude/helpers/cost-ledger.cjs report --json      # JSON output

Ledger Format (JSONL)

{"date":"2026-03-30","timestamp":"2026-03-30T20:27:10.888Z","project":"matrix-lstm","session_id":"abc123","cost_usd":3.68,"duration_min":110.7,"model":"claude-opus-4-6","lines_added":552,"lines_removed":20}

Design Decisions

  • JSONL over SQLite — simpler, no dependencies, easy to grep/parse/backup
  • Global ledger (~/.claude/) — works across all projects on the machine
  • Non-fatal hook — if cost recording fails, session-end still completes normally
  • No new dependencies — pure Node.js, uses only fs, path, os, child_process

Test plan

  • Run npx @claude-flow/cli@latest init --only-claude --force in a project
  • Verify cost-ledger.cjs appears in both .claude/helpers/ and ~/.claude/helpers/
  • End a Claude Code session and verify a JSONL entry is appended to ~/.claude/cost-ledger.jsonl
  • Run node ~/.claude/helpers/cost-ledger.cjs report and verify output
  • Test --daily, --weekly, --monthly, --annual, --json flags
  • Test --project <name> filtering
  • Verify session-end still works if cost-ledger.cjs is missing (graceful fallback)

🤖 Generated with claude-flow

Adds cost-ledger.cjs that tracks Claude Code session costs across all
projects on a machine. Records cost, duration, model, and lines changed
to a global JSONL ledger at ~/.claude/cost-ledger.jsonl.

Features:
- Automatic recording via session-end hook integration
- Reports: --daily, --weekly, --monthly, --annual
- Filter by --project <name>
- JSON output for programmatic use
- Installed globally during init so it works cross-project

The hook handler's session-end now calls cost-ledger.cjs record with
the session data from Claude Code's stdin, then the report command
provides spend visibility that was previously unavailable.

Co-Authored-By: claude-flow <ruv@ruv.net>
Copy link
Copy Markdown

@xkonjin xkonjin left a comment

Choose a reason for hiding this comment

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

Code Review: Cost Ledger Feature

Overall this is a well-designed addition. A few observations:

Strengths:

  • Clean separation between record and report modes
  • Good defensive programming with try/catch around the hook invocation (cost tracking should never break session end)
  • Nice touch with the color-coded cost thresholds in reports ($50+ yellow warning)
  • JSON output option for programmatic consumption

Minor considerations:

  1. The readStdinSync() function reads in 4KB chunks but the expected input is small JSON. Could simplify to a single read, but current approach is safe.

  2. In record(), when both cost and duration are 0, the function returns early. Consider logging this case for debugging since it might indicate the hook isn't receiving proper cost data from Claude Code.

  3. The project name extraction from git remote uses a simple regex. Consider handling SSH-style URLs - the pattern should catch these but worth verifying.

  4. The ledger grows unbounded (JSONL append). For long-term use, consider a rotation/compaction strategy. Not blocking for this PR.

The feature is well-tested in concept and the implementation follows good practices. LGTM pending any tests you want to add.

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