cachewhy reads the Claude Code and Codex session logs already on your machine and finds every request where the prompt cache broke: the conversation prefix had to be processed again instead of read from cache. Each event gets a cause, an evidence level and an API list-price cost. Subagents and workflow agents included, fully offline.
One real week of the author's own Claude Code logs. Claude Code's /usage explains the last miss of the main conversation; subagents and past sessions are out of its view.
Real output from the author's Codex logs, session ids removed. Codex does not log why a cache missed, so cachewhy works the cause out from timing, model changes and context size, and marks each one with its confidence.
npx cachewhy rebuilds --since 7d # Claude Code and Codex together
npx cachewhy rebuilds --since 7d --agent claude # Claude Code only
npx cachewhy rebuilds --since 7d --agent codex # Codex onlyNo install, no config, no account. Requires Node 22 or newer. cachewhy finds ~/.claude/projects and ~/.codex on its own.
| Claude Code | Codex CLI | |
|---|---|---|
| Logs read | ~/.claude/projects, main sessions, subagents, workflow agents |
~/.codex/sessions and archived_sessions, including compressed .jsonl.zst |
| Threads | main conversation, each subagent linked to the tool call that spawned it, workflow agents | main threads, subagents, forks that inherit a parent prefix |
| Causes | logged cache miss reason (confirmed), model switch, idle past TTL, compaction, effort or version change | model switch, idle past TTL, compaction, settings change (hypothesis; Codex logs carry no miss reason) |
| Prices | Anthropic API list prices, 5 minute and 1 hour cache writes | OpenAI API list prices, cached input |
Checked against the published npm package on a real machine: 4,931 Claude Code files and 1,909 Codex files (532 live, 1,377 archived), none unreadable.
A coding agent resends the whole conversation on almost every request. When the prefix matches the previous request, the provider reads it from cache at about a tenth of the input price. When something changes the prefix, or the cache expires, the whole prefix is processed and written again at full price or more. One miss on a long session costs as much as a hundred hits.
Usage dashboards tell you how much you spent. cachewhy tells you which requests threw the cache away, and why.
- Read. Every Claude Code session, subagent and workflow agent file, and every Codex rollout, live or archived. Nothing leaves the machine and no message text enters the report.
- Rebuild the threads. Responses are deduplicated by request id, so replayed and copied lines count once. Subagents are linked to the tool call that spawned them. Each thread is put in request order.
- Flag rebuilds. A request is a suspected rebuild when it reads back less than half of the prefix the previous request in the same thread had cached.
- Explain. Each event gets one cause and an evidence level:
| Evidence | Meaning |
|---|---|
| confirmed | Claude Code logged a cache miss reason for that request |
| hypothesis | A signal in the logs fits, with a confidence: model switch, idle gap past the cache TTL, a context that shrank (compaction or /clear), an effort change, a version change |
| unknown | Nothing in the logs explains it. Shown, never hidden |
- Price. The extra cost is the rebuilt tokens at the write or input price minus the cache read price, from a pinned table of public API list prices. It is an estimate at API rates, not your bill.
| cachewhy | Claude Code /usage |
Token and cost counters | |
|---|---|---|---|
| Token and cost totals | ✓ | ✓ | ✓ |
| Explains why the cache missed | every event | last miss | ✗ |
| Past sessions | ✓ | ✗ | ✓ |
| Subagents and workflow agents, per thread | ✓ | ✗ | totals only |
| Codex | ✓ | ✗ | some |
| Evidence level on each finding | ✓ | ✗ | ✗ |
| Fully offline, no message content | ✓ | ✓ | ✓ |
Token and cost counters means tools such as ccusage and codeburn, which are great for totals and complement cachewhy. Compared as of October 2026.
cachewhy rebuilds # suspected cache rebuilds, causes, cost
cachewhy rebuilds --top 50 # list more events
cachewhy rebuilds --json # machine readable (schema cachewhy-rebuilds/1)
cachewhy # token and cost accounting per provider and model
cachewhy doctor # log sources and parse coverage| Option | |
|---|---|
--since 7d, --until 2026-10-01 |
Time window: a date or a duration (24h, 7d, 2w) |
--agent claude|codex|all |
Which provider to print |
--project <dir> |
One Claude Code project |
--claude-dir, --codex-dir |
Non default log locations |
--no-color |
Plain output (NO_COLOR is respected too) |
Set CACHEWHY_NETGUARD=1 to install a guard that fails any network call during a run.
A cost tool that guesses loses trust on the first wrong number. cachewhy was built the other way around: the rules first, then two implementations that have to agree.
| 1,122 tests | about 24,700 lines of tests for 10,700 lines of source |
| Written spec | a 1,085 line methodology and an accounting checklist; every rule is testable |
| Two implementations | an independent recompute (scripts/recompute) re-derives every total from raw logs; differential fuzzing over 1,000 seeds per generator found 0 divergences |
| Metamorphic tests | shuffling file order, duplicating lines or splitting files must not change any number |
| Adversarial review | 18 review rounds (11 on the spec, 7 on the code) by an independent AI auditor model; every finding and its fix is in the audit log |
| Private by design | zero runtime dependencies, a network guard, CI runs the suite with the network removed, and a privacy lint keeps real paths and ids out of the repo |
| Cross platform | CI on Linux, macOS and Windows, Node 22 and 24; releases publish with npm provenance |
The accounting is strict on purpose. A chain the summary cannot verify end to end keeps its tokens but gets no dollars, and the report says so instead of filling the gap with a guess.
- Causes other than confirmed are inferred from timing and counters. Treat them as strong leads, not proof.
- Codex logs carry no cache miss reason, so Codex events are never confirmed.
- Costs use public API list prices. Subscription plans bill differently.
- On Node 22 a truncated archived Codex log (
.jsonl.zst) reads as a shorter file instead of being flagged unreadable, because Node 22 does not report cut zstd frames. Node 24 does.
Does it send my logs anywhere?
No. cachewhy has no runtime dependencies and makes no network calls. Run it with CACHEWHY_NETGUARD=1 to make any attempt fail loudly. Message text is never read into the report; sessions appear only as short ids.
What should I do about "idle past cache TTL"?
The cache expired between two requests of the same thread. Common sources are subagents waiting on a long tool call and sessions left open over a break. Claude Code can use a 1 hour cache TTL; whether it pays off depends on how often you come back within the hour.
Why are some events "unknown"?
Because the logs do not say. cachewhy shows them instead of forcing a cause. If you can reproduce one, a wrong cause report helps turn it into a rule.
npm ci
npm test
npm run build
node dist/cli.js rebuilds --since 7dSee CONTRIBUTING.md. Test fixtures are synthetic; never commit real logs. README images are generated by node scripts/make-assets.mjs.
MIT. cachewhy is an independent project, not affiliated with or endorsed by Anthropic or OpenAI. Claude Code and Codex are trademarks of their owners.