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

> Track token savings with Caveman by analyzing Claude session logs. Understand cost avoidance and monetary savings using this CLI and API guide.

- Repository: [Julius Brussee/caveman](https://github.com/JuliusBrussee/caveman)
- Tags: how-to-guide
- Published: 2026-07-07

---

**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`](https://github.com/JuliusBrussee/caveman/blob/main/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.

```javascript
// 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.

```javascript
// 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:

```javascript
// 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:

```bash
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:

```bash
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:

```bash

# 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`](https://github.com/JuliusBrussee/caveman/blob/main/src/hooks/caveman-stats.js).

```javascript
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:

- **[`src/hooks/caveman-stats.js`](https://github.com/JuliusBrussee/caveman/blob/main/src/hooks/caveman-stats.js)** – Core logic for parsing, attribution, savings estimation, and formatting.
- **[`src/hooks/caveman-config.js`](https://github.com/JuliusBrussee/caveman/blob/main/src/hooks/caveman-config.js)** – Safe flag I/O and mode-log management.
- **[`src/hooks/caveman-mode-tracker.js`](https://github.com/JuliusBrussee/caveman/blob/main/src/hooks/caveman-mode-tracker.js)** – Emits mode-change entries to the transition log.
- **[`src/hooks/caveman-activate.js`](https://github.com/JuliusBrussee/caveman/blob/main/src/hooks/caveman-activate.js)** – Command handler for mode toggling.
- **`benchmarks/`** – Contains benchmark data that generates the `COMPRESSION` ratios.
- **[`commands/caveman-stats.md`](https://github.com/JuliusBrussee/caveman/blob/main/commands/caveman-stats.md)** – Documentation for CLI flags (`--share`, `--all`, `--since`).

## 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.