I had a number I could not explain.
ccusage told me what I spent. Good tool, does its job. But the biggest line in it was cache_read — the charge for re-reading the whole conversation on every single turn — and nothing told me what I kept re-reading.
So I wrote nenpi (燃費, Japanese for "fuel economy") to find out. Zero dependencies, reads the JSONL transcripts already sitting in ~/.claude/projects/, uploads nothing.
The first run reframed the whole problem.
Residency cost
## Residency cost (tokens injected x turns that followed) = what cache_read really is
resid share calls injected avg imgs tool
1669M 81.4% 5586 2.4M 432 0 Bash
231M 11.3% 229 0.3M 1474 163 Read
43M 2.1% 64 0.1M 950 34 mcp__claude-in-chrome__computer
17M 0.8% 372 0.0M 55 0 Write
Bash output was 2.4M tokens of actual text. Its residency cost was 1669M — 81% of everything I spent.
Residency cost = tokens injected × turns that came after. A tool result is not charged once. It is charged once per turn that follows it. Dumping a log file on turn 5 of a 300-turn session is a completely different purchase from doing it on turn 299, and no cost-per-day chart will ever tell you that.
Once you can sort by that column, the thing worth fixing stops being a guess.
The counting bug that makes most of these numbers wrong
This is the part I would want to know if I were writing my own token tool.
Claude Code splits one API response into a separate JSONL line per thinking / text / tool_use block — and copies the same usage object onto every one of them.
Sum per line and you count the same charge several times over. Measured on my machine: +82%.
The same split breaks parallel-call detection. From a single line you cannot tell how many tools one response called, so a per-line count pins your bundling rate at 0.0% forever, no matter what the model does.
nenpi deduplicates by message.id and regroups by requestId before it counts anything.
Then it told me my own hook was useless
nenpi is also three Claude Code hooks — the point where measuring turns into a smaller bill.
| Hook | Event | What it does |
|---|---|---|
nenpi hook pre |
PreToolUse |
A full-file Read of a large file gets cut to the first 400 lines, with a note to Grep first. Full text would sit in the context and be re-sent every turn. |
nenpi hook prompt |
UserPromptSubmit |
Shows what re-reading the current context costs per turn. It never says "your context is too long" — that claim did not hold up in the measurements. |
nenpi hook post |
PostToolUse |
When the same tool has run one call at a time for several turns straight, says so once, at the moment it happens. |
And nenpi effect exists to check whether a nudge like that does anything at all.
Week-to-week comparison confounds — spend fell, but was that your change or an easier week? So effect compares, inside the same session, the turns immediately after a nudge fired against ordinary turns. Whatever the work was, it applies to both sides and cancels out.
## "bundle them" (hook post) — did the next turn actually bundle?
fired 80 times
bundled on the next turn 8 / 79 10.1%
normal turns, same sessions 201 / 6401 3.1%
difference +7.0pt
→ It does not work. Reword it, or take it out.
My own tool, telling me to rewrite my own nudge.
That turned out to be the feature I use most. Not "how much did I spend" — "the thing I was sure about is not true."
What is measured and what is estimated
Being straight about this matters more than the numbers looking precise.
Measured, from usage: token counts, tool call counts, timestamps, hook durations, is_error flags, compaction events. Dollar figures come from Claude Code's own costUSD, not from a model of mine.
Estimated: BYTES_PER_TOK = 3.5 for the byte→token conversion, IMG_TOK = 1600 per image block, and the weights that turn token classes into input-token equivalents. quality prints a calibration residual against the real costUSD so you can see how far off the weights are on your plan. Mine runs about 1%.
So: charges are measured, attribution is estimated. Residency cost sits on the estimated side. It is still the most useful number here, because nothing else points at which output is the expensive one — but read it as an estimate.
Try it
npx @hyuga/nenpi report
Node 18 or newer. MIT. Source: https://github.com/hyuga611/nenpi
There are two more commands I lean on:
-
quality— cutting tokens is easy if you are allowed to make the agent worse. It puts fuel, intelligence and speed on one screen (rework rate, tool failure rate, user correction rate, wasted-Readrate, turns per prompt, wall time per prompt) so a "win" has to hold on all three. -
errors— a rising tool failure rate is not evidence the model regressed. Permission denials,EPERM, a human pressing stop all raise it. This splits environment-caused failures from model-caused ones, broken down by model × effort.
One caveat worth repeating: the transcript format is undocumented and it changes. nenpi pins its counting to message.id and requestId, which have been stable, but a format change can silently make a metric wrong. If a number looks impossible, it probably is — please open an issue.
Top comments (0)