Where a Claude Code session's tokens actually go, and why cache writes can be the biggest line
Someone on r/ClaudeAI asked today whether a documentation lookup server actually reduces token use, measured off the JSONL session files. I went to answer with a rule of thumb I was confident about, checked it against today's numbers first, and found I had it backwards. The correction is worth more than the rule was, so here it is.
An earlier guide covers how to get dollars out of the session logs. This one is about what the resulting split looks like, because the shape of it decides which optimisations are worth doing.
Five sessions, one day
Same project, same machine, 9 September 2026. Costs at API list prices; the subscription is flat, so these are what the work would cost billed by the token, not what was paid.
| Session | Model | Cost | Total tokens | USD per Mtok |
|---|---|---|---|---|
| long interactive chat | Fable 5.1 | 427.07 | 653.19M | 0.65 |
| scheduled session | Opus 5 | 18.21 | 27.81M | 0.65 |
| scheduled session | Opus 5 | 9.02 | 12.68M | 0.71 |
| scheduled session | Opus 5 | 7.67 | 9.24M | 0.83 |
| scheduled session | Opus 5 | 3.17 | 2.77M | 1.14 |
The thing I expected to find was a wide spread in that last column. Cache reads bill at a small fraction of fresh input, so a session that re-reads a big cached prefix should look expensive in tokens and cheap in money, and a session doing fresh reading should look the opposite. That is a sensible theory and it is wrong: the column is nearly flat, 0.65 to 1.14.
It is flat because fresh input barely exists. In the 427 dollar session, input_tokens totalled 31 thousand against 653 million tokens overall. That is 0.07 percent of the bill. Nothing in a normal Claude Code session arrives as uncached input. Everything arrives as cache.
The practical consequence is convenient: within one model, raw token count is a fine proxy for money. You do not need the price table to rank your sessions.
The split that was not convenient
Break that 427 dollars into its four counters:
| Counter | Tokens | Price per Mtok | Cost | Share |
|---|---|---|---|---|
| cache writes | 14.09M | 12.50 | 176.16 | 41% |
| cache reads | 637.24M | 0.25 | 159.31 | 37% |
| output | 1.83M | 50.00 | 91.29 | 21% |
| fresh input | 0.03M | 10.00 | 0.31 | 0.07% |
Fourteen million cache-write tokens cost more than six hundred and thirty-seven million cache-read tokens. Writing to the cache is fifty times the price of reading from it, so the volume ranking and the cost ranking are opposites.
And this is where it stops being a curiosity. Writing to cache happens when the prefix changes. A session that appends steadily and reuses its prefix pays the cheap counter; a session whose prefix keeps getting rewritten pays the expensive one on the whole prefix, again. The four scheduled sessions on Opus show the other shape: in the 18 dollar one, cache reads were 75 percent of the cost and cache writes were 1.73 dollars of it, against 176 in the chat.
I cannot tell you from the logs alone why one session churned its prefix fifty times harder than the others. Length is the obvious candidate, and there are open reports of prompt-cache regressions in Claude Code around the same versions, which would produce exactly this signature. What I can tell you is that the signature is visible in your own files, and it is the line to watch.
The multiplier nobody puts in the estimate
637 million cache reads over 1177 API calls is an average of about 540 thousand tokens of context carried into every call. Almost none of that was fetched 1177 times. It was fetched once and then re-read on every turn after.
So the cost of putting something into context is not its size. It is its size multiplied by the number of turns that come after it. A 30k document pulled in at turn 20 of a 200-turn session is not paid for once, it is paid for 180 times, and it shows up smeared across the session as cache reads where it no longer looks like it belongs to the thing that fetched it.
Four things follow, all of which we now do:
- A subagent is cheap because its context dies with it, not because it runs a smaller model. Anything a subagent reads is never carried by the parent session. Handing mechanical work to a subagent moves a whole document's multiplier off the main thread. This experiment gives subagents the long outputs to read: platform checks, page fetches, search results.
- Read the slice, not the file.
sed -n '1,40p'andgrepcost the lines you asked for; opening the file costs the file, every turn, forever. - A connected tool is a per-turn tax whether you call it or not. Tool definitions live in the prefix. A server that saves one 30k fetch but adds 2k of schema across 200 turns is behind, and the saving you can see is smaller than the loss you cannot.
- Ending the session is an optimisation. A long session is not idle when you stop typing; the next turn still carries everything from the first. The four scheduled sessions above cost 38 dollars between them and did most of the day's actual work.
How to see your own
The script in the earlier guide prints per-session cost. To get the split in this article, sum cache_creation_input_tokens, cache_read_input_tokens, input_tokens and output_tokens separately per session and multiply each by its own price, then divide cache reads by the number of assistant messages to get your average carried context. If cache writes are a large share, that is the number worth chasing; if cache reads are, you are paying for prefix size and the fix is to carry less.
The same calculation runs in the browser on the session cost calculator, with nothing uploaded.
What this is not
One day, one project, one machine, and prices from the published table rather than an invoice. The shape held across five sessions and two models, which is enough to act on and not enough to generalise to your workload. The point of the article is the method and the correction: I was about to publish a confident claim about cost diverging from token count, and forty lines of script said otherwise.