Your Claude Agent Re-Reads Its Whole Prompt Every Turn. Here's the 10× You're Leaving On the Table.
Every turn your agent takes, it re-sends the same thing: a big system prompt, a frozen tool list, a growing transcript. A 10,000-token system prompt that doesn't change between turns gets re-processed, at full price, on turn 1, turn 2, turn 20. Prompt caching exists to stop exactly that — and on a repeated prefix it makes the repeat cost one tenth of full price. Most teams have it switched on and still pay nearly full freight, because one byte in the wrong place silently turns it off. This is the whole game, and the part nobody measures.
One invariant, and three numbers
Prompt caching is a prefix match. Any change anywhere in the prefix invalidates everything after it. The cache key is the exact bytes of the rendered prompt up to each cache_control breakpoint. The render order is fixed: tools → system → messages. A single differing byte at position N kills the cache for everything at or after N.
The economics are three multipliers of a model's base input price:
| multiplier | when | |
|---|---|---|
| uncached input | 1.00× | every token, every request |
| cache write | 1.25× | first request (5-minute TTL; 2.00× for 1-hour) |
| cache read | 0.10× | every later request that hits |
So on a cached prefix you pay a 25% premium once, then 90% off forever after. Break-even is the second request: 1.25 + 0.10 = 1.35× for two cached requests versus 2.00× uncached. Everything past that is gravy. For a 1-hour TTL the write is doubled, so you need three requests to come out ahead — worth it only when traffic is bursty enough that the longer-lived entry survives the gaps.
The field everyone reads wrong
The response usage object tells you what actually happened:
cache_creation_input_tokens— tokens written this request (you paid 1.25×)cache_read_input_tokens— tokens served from cache (you paid 0.10×)input_tokens— tokens processed at full price
The trap: input_tokens is only the uncached remainder. Total prompt size is input_tokens + cache_creation_input_tokens + cache_read_input_tokens. We've watched people conclude "caching isn't doing anything, input_tokens is still 4,000" — while 60,000 tokens quietly flowed through cache_read_input_tokens next to it. Read the sum, not the one field. And if cache_read_input_tokens is zero across repeated requests with the "same" prefix, you don't have a pricing problem — you have a silent invalidator.
The silent invalidators (grep your prompt-building code for these)
This is the actionable part. Every one of these sits in the prefix and changes its bytes per request, so nothing after it ever caches:
| Pattern | Why it kills caching |
|---|---|
datetime.now() / Date.now() in the system prompt | the prefix changes every request |
uuid4() / request IDs early in content | every request is byte-unique |
json.dumps(d) without sort_keys=True, or iterating a set | non-deterministic serialization |
| f-stringing a session/user ID into the system prompt | per-user prefix; zero cross-user sharing |
if flag: system += "..." conditional system sections | every flag combo is a distinct prefix |
tools=build_tools(user) where the set varies | tools render at position 0 — nothing caches across users |
The fix is always the same shape: keep the system prompt and tool list frozen, and move anything volatile to the end, after the last breakpoint. A "current date: …" line belongs in a user message at turn 5, not in the system header where it poisons everything downstream. Serialize tools deterministically (sort by name). A message at turn 5 invalidates nothing before turn 5; a byte in the system header invalidates the entire conversation.
Two gotchas that look like bugs
Minimum cacheable prefix is model-dependent — and bigger than you think. Below the floor, the marker is silently ignored: no error, just cache_creation_input_tokens: 0.
| Model | Minimum |
|---|---|
| Opus 4.8 / 4.7 / 4.6, Haiku 4.5 | 4096 tokens |
| Sonnet 4.6 | 2048 tokens |
| Sonnet 4.5 | 1024 tokens |
A 3,000-token preamble caches fine on Sonnet 4.5 and silently won't on Opus 4.8. If you switched models and your hit rate cratered, this is why.
The 20-block lookback. Each breakpoint walks back at most 20 content blocks to find a prior entry. An agentic turn that appends 30 tool_use/tool_result blocks pushes the previous cache out of range, and the next request misses silently. Fix: drop an intermediate breakpoint every ~15 blocks in long turns. (Related: on a fan-out, send one request, await its first streamed token, then fire the rest — a cache entry only becomes readable once the first response starts streaming, so N parallel requests all pay full price.)
Putting a number on it
We wrote a tiny, dependency-free tool, cachecost, that reads a usage object and tells you what caching did — in model-agnostic base-input-token units, so the answer doesn't depend on today's price sheet. On a cache read of a ~10,000-token prefix:
$ cachecost explain read-usage.json
cache state : READ (served from cache at 0.10x)
uncached : 30 tok
cache write : 0 tok x1.25
cache read : 10,000 tok x0.1
cacheable prefix this request: 10,000 tok
---
input cost (eq tokens) : 1,030
same prompt, caching OFF : 10,030
>> saved 9,000 eq-tokens on this request (89.7% off the input).
And amortized the way agents actually run — one write, then many reads:
$ cachecost amortize write-usage.json read-usage.json --reads 10
cached : 1 write (12,500) + 9 reads (1,000 each) = 21,500 eq-tok
uncached: 10 x 10,000 = 100,000 eq-tok
>> 78.5% cheaper on the prefix across 10 requests (78,500 eq-tokens saved).
The cost arithmetic is locked down with tests (11/11). The multipliers above are the published ones; to see your real token counts, point measure-cache.sh at a funded API key — it fires two identical-prefix calls and prints the cache_creation/cache_read split so you can confirm the cache actually engaged before trusting any savings estimate.
The real lesson
Prompt caching isn't a feature you turn on; it's a property of how you assemble the prefix. Get the ordering right — frozen system, deterministic tools, volatile content last — and the 90% is automatic. Get one datetime.now() in the system header and no quantity of cache_control markers will save you. The single highest-leverage thing you can do for an agent's bill is grep the six patterns above out of your prompt-building path, then watch cache_read_input_tokens climb.
We build and run autonomous agent fleets on Claude in production. If you're hardening — or trying to afford — a multi-agent setup, talk to us.
Get the tool → cachecost in agent-ops — open source (MIT), a single dependency-free script, part of our toolkit for running coding agents in production.
Found this useful?
- You're Running Five Agents on One Repo. Who Stops Them Overwriting Each Other?
- Your Agent Did the Work, Then It Vanished. Here's How to Get It Back.
- Your Claude Code Session Is Permanently Stuck on a 400. Don't /clear — Do This.
- The One Kind of Agent Work You Can't Recover — and How to Stop Losing It
- Your Agent Will Eventually Run git reset --hard. Stop It at the Door.
- Your Agent Reads Text You Can't See. Frisk It First.
- You're Running a Dozen Agents. Which One Is Stuck?
- What's Actually In Your Claude Code Session File (and a Tool to Read It)
- Your Agent Fleet's Worktrees Are a Minefield. Here's How to See It.
- The Agent Wrote the Code in Minutes. Reviewing It Takes Hours. Here's Why.
- Your Agent Can Read Everything Your Shell Can. Have You Looked?
- The Loosest Line in Your Repo Is in .claude/settings.json
- The Most Expensive File in Your Repo Runs on Every Single Turn
- Your Skill's Description Is the Whole Ballgame
- Your Repo Already Knows How To Build Itself. Put That In the CLAUDE.md.
Related posts
The boring part: governance that enforces, not displays
Most "AI governance" is a dashboard. It shows you what an agent spent, what it touched, what it decided — after the fact, in a panel nobody refreshes until the bill arrives. A display is not a control. A control is the t…
Your Launch Deserves a Real Demo Video, Not a Screen Recording With Captions
Most product launches skip the demo video entirely, and the ones that don't ship one usually reach for the fastest option: a raw screen recording, maybe some auto-generated captions, posted as-is. It's better than nothin…
The MCP Ecosystem Is Growing Fast — and Quietly Becoming a Directory of Hosted Services
We [recently measured](/insights/in-the-registry-is-not-runs-2) whether the servers in the official MCP registry actually *run* (short version: 84% are remote-only, and under half of the installable ones boot clean). Whi…
Installing a Skill Usually Means Running a Stranger's Code
The pitch for Claude Code "skills" is that they're just *instructions* — a `SKILL.md` file with some markdown telling the agent how to do a task. That framing makes them feel safe to install. A prompt can't hurt you; wor…