How the /caveman-stats Command Calculates Lifetime Token Savings

The /caveman-stats command calculates lifetime token savings by first capturing per-session snapshots that attribute output tokens to active modes and estimate savings using benchmark-derived compression ratios, then aggregating these entries from the .caveman-history.jsonl log file to produce cumulative totals across all sessions.

The open-source Caveman tool for Claude Code provides transparent token usage analytics through its /caveman-stats command. Understanding how this command calculates lifetime token savings reveals the sophisticated attribution logic that turns raw session transcripts into meaningful cost estimates. This deep dive examines the actual implementation in src/hooks/caveman-stats.js to explain the two-phase calculation process that powers your lifetime savings metrics.

The Two-Phase Architecture of Lifetime Token Savings

Phase 1: Per-Session Snapshot Generation

When executed inside a Claude Code session, the command parses the session JSONL file using parseSession (src/hooks/caveman-stats.js lines 78-106). This function extracts critical metrics including outputTokens, cacheReadTokens, turns, and the model ID from the transcript.

The function attributeByMode (lines 86-130) then distributes these output tokens across different modes based on the transition log stored in .caveman-mode-log.jsonl. This attribution ensures that token counts map to the specific mode active during generation.

Next, deriveSavings (lines 41-50) applies the benchmark compression ratios defined in the COMPRESSION constant. For modes with established benchmarks (currently only 'full' at 0.65), it calculates estimated saved tokens using the formula:

estSavedTokens = round(tokens / (1 - ratio)) - tokens

The results are written to .caveman-history.jsonl via appendFlag in the main() function (lines 92-108), storing session_id, mode, model, output_tokens, est_saved_tokens, and est_saved_usd as a JSON line.

Phase 2: Lifetime Aggregation from History Log

When invoked with --all or --since flags, the command bypasses live session parsing and reads the accumulated history. The aggregateHistory function (lines 62-84) loads .caveman-history.jsonl, optionally filters entries by date windows, and collapses the log to retain only the latest entry per session.

It then sums the output_tokens and est_saved_tokens fields across all retained entries. These summed values constitute the lifetime totals displayed by the command.

Core Implementation Details and File Paths

Primary Calculation Functions in caveman-stats.js

The src/hooks/caveman-stats.js file contains the full implementation:

  • parseSession (lines 78-106): Reads .jsonl transcripts and extracts token counts and model identifiers.
  • attributeByMode (lines 86-130): Uses the mode transition log or file modification times to partition tokens by active mode.
  • deriveSavings (lines 41-50): Applies compression ratios to estimate potential token savings.
  • aggregateHistory (lines 62-84): Collapses history to latest-per-session and sums totals for lifetime reporting.
  • formatHistory (lines 9-24): Renders the human-readable output including "Lifetime ... Est. tokens saved" and USD equivalents.

Supporting Infrastructure

Several adjacent files enable the calculation:

Practical Usage Examples

Generate a per-session snapshot and update the lifetime log:

/caveman-stats

Display lifetime totals without parsing a live session:

caveman-stats --all

Expected output includes aggregated statistics:

Sessions:   12
Output tokens: 1 234 567
Est. tokens saved: 456 789

Filter lifetime totals to the last 7 days:

caveman-stats --all --since 7d

Generate a shareable summary for the current session:

/caveman-stats --share

This produces a formatted line like:

🪨 Saved 12 345 output tokens (~$0.19) across 34 turns this session — caveman.sh

Summary

  • The caveman-stats command calculates lifetime token savings through a two-phase process: per-session estimation followed by historical aggregation.
  • Per-session calculations use attributeByMode and deriveSavings in src/hooks/caveman-stats.js to apply benchmark compression ratios (0.65 for 'full' mode) to attributed output tokens.
  • Lifetime aggregation relies on aggregateHistory reading from .caveman-history.jsonl, keeping only the latest entry per session to avoid double-counting.
  • The calculation writes intermediate data via appendFlag and reads via utility functions in src/hooks/caveman-config.js.
  • All figures represent estimates derived from benchmark ratios rather than precise measurements, as documented in docs/HONEST-NUMBERS.md.

Frequently Asked Questions

What file stores the lifetime token savings data?

The .caveman-history.jsonl file in your project root stores the persistent log. Each line contains a JSON object with session_id, mode, model, output_tokens, est_saved_tokens, and est_saved_usd. The aggregateHistory function reads this file to compute lifetime totals.

How does the command avoid double-counting sessions in the lifetime total?

The aggregateHistory function (lines 62-84 in src/hooks/caveman-stats.js) collapses the history log to only the latest entry for each unique session_id before summing. This ensures that if a session is snapshotted multiple times, only the most recent data contributes to the lifetime calculation.

Why is the token savings figure labeled as an "estimate"?

The savings calculation uses benchmark-derived compression ratios stored in the COMPRESSION constant. Currently, only the 'full' mode has a defined ratio (0.65). The formula round(tokens/(1-ratio)) - tokens projects what token usage might have been without the mode's compression, rather than measuring actual API call differences. See docs/HONEST-NUMBERS.md for detailed methodology limitations.

Can I calculate savings for specific date ranges?

Yes. Use the --since flag with the --all option to filter the lifetime aggregation. For example, caveman-stats --all --since 7d processes only entries from the last seven days, applying the same aggregateHistory logic to the filtered subset.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →