What it reads
Codex records two figures per event.
last_token_usage is that turn; total_token_usage is cumulative, so only one of them can be summed. cached_input_tokens is a subset of input_tokens, not an addition to it — counting both would inflate every total.
Nothing is written back to either directory, and nothing is sent anywhere.
Prices
Cost comes from a built-in table of Anthropic rates, plus anything you add yourself inprices.json.
A model with no rate reports its tokens and a dash. It never reports a guessed figure.
prices.json re-prices your whole history immediately — there is no cache to clear.
Keeping rates current
Published prices move, and a stale rate is worse than a missing one because it looks right.--price-routine writes a script that checks the public price lists and proposes an update:
The charts
Cost and tokens by week sit between the totals and the tables, drawn in a singleCanvas rather than through a charting library. That keeps the app dependency-free and gives full control over how a line reads on a dark background.
The tiles answer “the last 30 days” and the charts want your whole history, so the view builds the ledger twice. The second build is nearly free, because the per-file cache already holds it. Both modes draw the same chart.
Headless
Checking it
scripts/check-ledger.py checks the arithmetic against hand-computed costs — 22 checks, covering cache invalidation, re-pricing from prices.json, and the cache-write premium.
The three caveats
Intuitive mode states these on the card itself, because a number this easy to misread should carry them:Not a bill
API-equivalent cost, not what you were charged.
Prices have an age
Rates are only as current as the last time the routine ran.
Nothing was sent
Every figure is rebuilt from files already on your Mac.
