Claude Code compacted my session for the fourth time this week, and my first reaction was the normal one: annoyance. It just erased everything and I have to re-explain half of it.
Then I pointed Claude Code at its own transcript files and did the arithmetic instead of the complaining. The transcripts are just JSONL on disk — every request, every token count, timestamped. Three sessions, 5,288 requests, a few minutes of parsing.
The reframe that came out of it: compaction isn't the tax. It's the tax getting paid off. The tax is every turn before that.
TL;DR
There's no persistent working memory across a conversation. Each API call is stateless — the model sees whatever text is in the request, and nothing else. So a coding session's "memory" is an illusion built entirely out of re-sending: every prior file read, every tool result, every message, concatenated and shipped again, every single turn.
Prompt caching is the thing that makes this survivable — I've written before about the mechanics of that discount for teams billing the Messages API directly. This post isn't about that bill. It's about what the discount doesn't erase: a coding agent's context isn't a system prompt that sits still for five minutes: it grows every tool call, and it's the agent itself — not your app's request pattern — deciding how much gets re-sent on turn 500.
"A fraction of full price" is not "free." It's a discount on a bill that still arrives every turn. The number of tokens in context is not a one-time cost you paid when you pasted that file in — it's a recurring line item for every remaining turn in the session.
I pulled this from three Claude Code project transcripts — .jsonl
files sitting in ~/.claude/projects/
, one line per event, a usage
object on every assistant message.
| Session | Requests | Cache read | Cache write | Output |
|---|---|---|---|---|
| A | 498 | 132M | 2.2M | 0.34M |
| B | 2,138 | 670M | 24M | 1.5M |
| C | 2,652 | 1,191M | 36M | 2.3M |
| Total | ||||
| 5,288 | ||||
| 1,993M | ||||
| 62M | ||||
| 4.2M |
The read:write ratio — how many times a token gets billed for being re-seen versus the one time it's billed for being newly added — sits at 32:1 overall, and climbs inside any single long session as context grows.
Session C is the sharper case. It hit four automatic compactions:
| Trigger | Context size at compaction | Duration |
|---|---|---|
| auto | 968,704 tokens | — |
| auto | 996,078 tokens | 108.7s |
| auto | 999,313 tokens | 139.5s |
| manual | 771,369 tokens | 140.5s |
Every one clusters right at the ~1M ceiling — the auto-compactor is doing exactly what it should, firing before the window overflows. And every one shows the same signature in the raw usage data: cache-read tokens at ~990K on the request immediately before, then 0 on the first request after. The entire accumulated context — everything that made every subsequent turn progressively more expensive — gets discarded and replaced with a summary. Turn 901 is cheap again.
That's the reframe. The compaction isn't losing your context. It's the moment the recurring bill resets to zero — at the cost of a two-minute and whatever the summary didn't preserve.
At published list-price API rates, running the actual token mix from these three sessions through the cached-price and never-cached-price formulas gives:
That's an 86% reduction from caching alone — before compaction ever fires.
Two caveats, because getting this wrong would be exactly the kind of unverified number I've written about before: Isn't this just... how caching is supposed to work? Yes. That's the point, and it's worth stating plainly instead of implying context bloat is a bug: caching is what makes long sessions economically viable at all, and it's doing its job well — 86% off is not a rounding error.
But "there's a discount" and "there's no cost" get quietly treated as the same thing when you're forty tool calls into a debugging session, and they aren't. A discounted recurring charge is still a recurring charge. The fact that it's 90% off doesn't change that it's billed again next turn, and the turn after, for as long as that token stays in the window.
Nothing exotic — the levers were already sitting in Claude Code's own design, this just explains why they matter more than they look like they do:
None of this is news framed as "AI context windows are expensive." It's closer to a hosting-bill instinct engineers already have for anything metered per-request — it just hadn't been pointed at a coding agent's own conversation before, mostly because nobody's context window ships with a bill attached. This one does. It's just sitting in a JSONL file, one line per turn, waiting to be added up.