How to Track Token Savings with Caveman: CLI and API Guide

Caveman tracks token savings by analyzing Claude Code session logs, attributing output tokens to the active compression mode at the time of generation, and applying benchmark-derived compression ratios to estimate avoided costs and monetary savings.

Caveman is an open-source context-compression tool for Claude Code that reduces token usage through specialized modes like full and lite. To track token savings with Caveman, the system intercepts session transcripts, maps token generation timestamps to mode transitions, and calculates savings using real compression benchmarks stored in the benchmarks/ directory.

How Token Tracking Works in Caveman

The token tracking workflow is implemented in src/hooks/caveman-stats.js and spans nine distinct steps from session discovery to aggregated reporting.

Session Discovery and Parsing

Caveman begins by locating the most recent Claude Code session. The findRecentSession() function walks the Claude configuration directory to identify the newest *.jsonl transcript file.

// From caveman-stats.js:71-75
const sessionPath = findRecentSession();

Once located, parseSession() reads each line of the transcript, extracting output_tokens and cache_read_input_tokens while recording per-message timestamps for later attribution.

// From caveman-stats.js:78-105
const session = parseSession(sessionPath);
// Returns: { messages, outputTokens, cacheReadTokens, ... }

Mode Attribution and Logging

Accurate savings calculation requires knowing which Caveman mode was active during each token generation window. The system maintains a mode transition log at ~/.claude/.caveman-mode-log.jsonl, populated by recordModeChange() in src/hooks/caveman-config.js:30-34 whenever the caveman-activate hook toggles modes.

The current mode flag is read safely via readFlag() from ~/.claude/.caveman-active (src/hooks/caveman-config.js:11-38), which handles symlinks and path whitelisting.

Savings Calculation and Estimation

The attributeByMode() function (src/hooks/caveman-stats.js:172-229) joins per-message timestamps with the mode transition log to produce a mapping of {mode → tokens}. Tokens generated during periods without clear mode attribution are marked as "unknown" and excluded from savings estimates to prevent inaccurate projections.

For attributed tokens, deriveSavings() (src/hooks/caveman-stats.js:38-46) calculates the token gap using the COMPRESSION benchmark map:

// From caveman-stats.js:19-20
const COMPRESSION = {
  full: 0.65,  // 65% reduction in output tokens
  lite: 0.0    // No benchmark estimate available
};

The formula tokens / (1 - ratio) determines how many tokens would have been generated without Caveman. Monetary estimates use priceForModel() (src/hooks/caveman-stats.js:25-45) to map model prefixes to Anthropic's public output-token pricing.

Persistence and Reporting

When a session contains at least one turn, appendFlag() (src/hooks/caveman-stats.js:95-107) persists a snapshot to ~/.claude/.caveman-history.jsonl. The formatStats() function renders human-readable reports, while formatShare() generates concise, social-ready summaries.

For historical analysis, aggregateHistory() (src/hooks/caveman-stats.js:64-84 ) reads the history file, deduplicates session entries, and reports cumulative savings across all sessions.

Using the caveman-stats CLI

Track token savings directly within Claude Code using the caveman-stats command.

View Current Session Statistics

Run the default command to see a detailed breakdown of the current session:

caveman-stats

Sample output:


Caveman Stats
──────────────────────────────────
Turns:    12
──────────────────────────────────
Output tokens:         2,100
Cache-read tokens:     650
──────────────────────────────────
Mode changed mid-session — output attributed per mode:
  full: 1,500 tokens (est. 1,500 saved)
  lite: 600 tokens (no benchmark estimate)
  unattributed: 0 tokens (mode unknown — excluded from estimate)
Est. tokens saved:     1,500
Est. saved (USD):      ~$0.0225

Generate Shareable Summaries

For concise, share-ready statistics:

caveman-stats --share

Result:


🪨 Saved 1,500 output tokens (~$0.0225) across 12 turns this session — caveman.sh

View Lifetime Aggregates

Access historical data across all sessions or filter by time period:


# All sessions

caveman-stats --all

# Last 7 days only

caveman-stats --since 7d

Sample output:


Caveman Stats — Lifetime (last 7d)
──────────────────────────────────
Sessions:   4
──────────────────────────────────
Output tokens:         9,400
Est. tokens saved:     4,500
Est. saved (USD):      ~$0.067

Tracking Token Savings Programmatically

Integrate Caveman statistics into custom workflows using the Node.js API exposed in src/hooks/caveman-stats.js.

const {
  parseSession,
  attributeByMode,
  deriveSavings,
  formatStats,
  readFlag,
  readModeLog
} = require('./src/hooks/caveman-stats');
const fs = require('fs');

// 1. Load a specific transcript
const session = parseSession('/path/to/session.jsonl');

// 2. Load the mode transition log
const modeLog = readModeLog('/home/user/.claude/.caveman-mode-log.jsonl');

// 3. Read current mode flag for fallback attribution
const currentMode = readFlag('/home/user/.claude/.caveman-active');
const flagMtimeMs = fs.statSync('/home/user/.claude/.caveman-active').mtimeMs;

// 4. Attribute tokens to modes
const attribution = attributeByMode({
  messages: session.messages,
  modeLog,
  mode: currentMode,
  flagMtimeMs: flagMtimeMs,
  outputTokens: session.outputTokens,
});

// 5. Generate report
console.log(formatStats({
  ...session,
  mode: currentMode,
  attribution,
}));

Key Source Files

Understanding these files helps debug attribution issues or extend functionality:

Summary

  • Track token savings with Caveman using the caveman-stats CLI or programmatic API.
  • Mode attribution relies on timestamped transition logs at ~/.claude/.caveman-mode-log.jsonl to map tokens to active compression modes.
  • Compression ratios (e.g., full: 0.65) are derived from real benchmarks in the benchmarks/ directory.
  • Unknown tokens are explicitly excluded from savings estimates to ensure accuracy.
  • Historical data persists to ~/.claude/.caveman-history.jsonl for lifetime aggregation across sessions.

Frequently Asked Questions

How does Caveman handle mode switches during a session?

Caveman uses attributeByMode() in src/hooks/caveman-stats.js:172-229 to join per-message timestamps with the mode transition log. If a session contains multiple mode changes, tokens are partitioned by the active mode at the time of generation. Tokens that cannot be safely attributed to a specific mode are marked as "unknown" and excluded from savings calculations.

What compression ratios does Caveman use for savings estimates?

According to src/hooks/caveman-stats.js:19-20, Caveman currently applies a 65% reduction factor (full: 0.65) for the full mode based on benchmark data in the benchmarks/ directory. The lite mode has no benchmark entry (0.0), so tokens used in lite mode are tracked but not counted toward estimated savings.

How accurate are the USD cost estimates in Caveman stats?

The USD estimates use priceForModel() (src/hooks/caveman-stats.js:25-45) to match model prefixes against Anthropic's public output-token pricing. The calculation only considers output tokens (not input or cache tokens) and reflects the actual model detected in the session transcript, making the estimate reliable for billing comparisons.

Where does Caveman store historical token savings data?

Caveman appends session snapshots to ~/.claude/.caveman-history.jsonl via appendFlag() (src/hooks/caveman-stats.js:95-107). The aggregateHistory() function reads this file to compute lifetime totals, keeping only the latest entry per session ID to avoid double-counting when sessions are re-parsed.

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 →