[BUG] new sessions will **never** hit a (full)cache
What's Wrong?
relaunching claude / clearing the session costs 6505 cache-create tokens
even after "just seconds" and super short messages (so this is not about the ongoing 5 minutes vs 1 hour discussion!)
What Should Happen?
assuming no changes where made (looking at you CLAUDE_CODE_DISABLE_GIT_INSTRUCTIONS destroying the system-prompt...)
relaunch/clear should be a 99% cachehit.
but neither skills nor project/CLAUDE.md get cached:
Error Messages/Logs
Traffic-inspection shows
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "<system-reminder>\nThe following skills are available ...."
},
{
"type": "text",
"text": "<system-reminder>\nAs you answer the user's questions, you can use the following context:\n# claudeMd\n...."
},
{
"type": "text",
"text": "alive?",
"cache_control": {
"type": "ephemeral"
}
}
]
}
],
Steps to Reproduce
Have a statusline show/log you usage.
claude
> alive?
> -> Yes, alive and ready. What do you need?
# (11k cache read, 6k cache write)
> nice
> -> What are we working on?
# (18k cache read, 19 cache write)
> /exit
claude
> alive?
> -> Yes, I'm here. What can I help you with?
# (18k cache read)
> /exit
claude
> are you here?
> -> Yes, I'm here. What can I help you with?
# (11k cache read, 6k cache write)
-> note that the two string-matched "alive?"´s do hit,
so one can start every claude session with a claude "Hello" and then do the actual work to get the full cache hits ? 🤔
but the "two different questions" gets a 6k token penalty
EDIT: as of 2.1.113 - "cch= started ticking" - ANTHROPIC_BASE_URL-users must set CLAUDE_CODE_ATTRIBUTION_HEADER=0
-> the "initial 11k" is likely some publicly shared tool cache that is hit.
there is no cache marker between system-prompt-part1 (base-prompt + user/CLAUDE.md) and the first user message.
but a whole lot of tokens for skills, and system-prompt-part2 (memory + project/CLAUDE.md)
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.104
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Xterm
Additional Information
also came across the discussion here https://news.ycombinator.com/item?id=47740381
"keeping your context small" (and clearing often) is(used to?) be the way to go - but without cachepoint the reverse would be true? -> more compute for you, less expensive for users - what sounds wrong...
Note that this is especially NOT about the 5-minute vs 1 hour discussion,
the claude launches above where all within 15 seconds ;)
Showing cached comments. Read the full discussion on GitHub ↗
12 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
not a dupe, resume is not involved here.
also fix is practically included: "move that
cache_controlone message up."Confirming same issue on macOS M1, Claude Max, Sonnet 4.6, v2.1.104. Fresh sessions hitting 23%+ context used after 2-3 exchanges. Was not happening before today's auto-update.
This is a distinct mechanism from the 5m/1h TTL discussion and worth tracking separately — nice catch.
Your traffic inspection shows the key structural issue: skills and project/CLAUDE.md content land in
messages[0]user-content blocks, not in thesystem[]prefix. Anthropic's prompt caching is prefix-based — it matches from the beginning of the request forward. Content inmessages[0]sits AFTER the system prompt and tool definitions, so any change to it (or even reordering within it) invalidates the cache for everything that follows, even if the system prompt and tools are byte-identical.We've been measuring this from a different angle with our claude-code-cache-fix interceptor. Our
CACHE_FIX_DEBUG=1mode logs per-call prompt-size breakdowns:The
injected=1626is the skills block you're seeing — it's inmessages[0]and contributes to per-session cache instability. On a fresh session //clear, the skills block content is regenerated and may differ from the prior session's version even if your actual skills haven't changed (ordering, whitespace, deferred-tool registration timing).Your #47107 finding about
git statusin the system prompt is the other half of this — the system prompt itself changes on every file edit becauseincludeGitInstructions(default: true) injects livegit statusoutput. So you have cache busting from BOTH ends: system prompt changes from git status at the front, and skills/CLAUDE.md changes frommessages[0]regeneration at the back.Our interceptor addresses part of this — we sort and stabilize the skills, deferred-tools, and MCP blocks within
messages[0]to reduce ordering jitter. But we don't currently address thegit statussystem-prompt instability from #47107. That's a good lead for a future fix.For anyone wanting to measure this on their own sessions:
npm install -g claude-code-cache-fix@1.7.1withCACHE_FIX_DEBUG=1will log the per-section sizes and prefix diffs that make these cache busts visible.Datapoint across 159 local sessions (v2.1.71 – 2.1.104):
First-turn
cache_read == 0rate by version:| version | sessions | zero_read_rate |
|---|---|---|
| 2.1.94 | 11 | 90.9% |
| 2.1.97 | 10 | 50.0% |
| 2.1.100 | 32 | 40.6% |
| 2.1.101 | 35 | 40.0% |
| 2.1.104 | 7 | 28.6% |
Trend is improving on newer versions, though 40% zero-hit on 2.1.100+ is still a meaningful amount.
Caveat: uncontrolled sampling (skills and CLAUDE.md content vary across sessions), so weaker than the controlled "no changes made" repro in the OP. Sharing as a rough corroboration that first-turn cache misses are common enough to be worth investigating, even if not strictly "never."
For anyone wanting to measure this on their own sessions, I published the analysis script:
https://gist.github.com/ZWhiteTrace/7f23ee2920ba6e1dd8eacd79478e90ae
It reports first-turn
cache_readby version out of the box, so reproducing the table above (or finding different trends) is just running one command.Cache misses on relaunch are expensive. We open-sourced Cozempic which prunes session bloat so the context payload is smaller and more cache-friendly between sessions. Less content changing between turns = higher cache hit rates.
The guard daemon runs automatically and keeps sessions lean with 18 lossless pruning strategies.
\
pip install cozempic && cozempic init\Would be curious if you see cache hit rates improve — \
cozempic diagnose\shows your current cache read vs creation ratio.FYI if you are an
ANTHROPIC_BASE_URLuser:This will not entirely make this problem here go away,
-- but should get you from cache hitting only on the
tools,-- to hit
toolsandsystem-prompt (+~/.claude/claude.md).->
skillsandsystem-messages (+projects-claude.md)will still miss if not using theclaude "Hello"thing,EDIT: as of 2.1.113 - "cch= started ticking" - BASE_URL-users must set
CLAUDE_CODE_ATTRIBUTION_HEADER=0so this here is is still its own issue that needs an extra
cache_controlin the code to get fixed...(or one of the claude-code-cache-fix-interceptors ran userside)
---
Still getting inflated numbers? check:
https://github.com/anthropics/claude-code/issues/47107
/clearing 😢https://github.com/anthropics/claude-code/issues/47756
Good breakdown of the cache layers. To confirm what the interceptor covers in that stack:
tool_sortpins deterministic order,tool_use_input_normalizecanonicalizes field orderfingerprint_stripremoves the attribution hash (same effect asCLAUDE_CODE_ATTRIBUTION_HEADER=0but automatic)relocatepins these tomessages[0]in stable order,reminder_stripdrops volatile bookkeeping reminders,smoosh_split/smoosh_normalizehandle the content-folding driftSo layers 1-3 are all addressed, plus several per-turn drift classes (
cache_control_normalize,cache_control_sticky,session_start_normalize,continue_trailer_strip).The attribution header issue (#50085) is worth fixing upstream regardless — users on
ANTHROPIC_BASE_URLwithout the interceptor are getting silently burned.Confirming this is still observable in 2.1.131. New sessions show the same pattern @wadabum described — skills and project
CLAUDE.mdremain cache-miss territory across relaunches, even seconds apart on identical context.The interceptor work in cache-fix closes some of the surface (tools order, system-prompt, top-level
CLAUDE.mdvia fingerprint strip) but not the skill / project-CLAUDE.mdpath @wadabum specifically called out — those still need an upstream fix at the prefix construction step. This contributes meaningfully to the per-turn cache_read figures several of us have been measuring on heavy sessions.Worth keeping open as a reference for ongoing community work.
— AI Team Lead
still relevant in >=2.1.150
Besides the theory that cache is simply not checked, I'm informed that the system prompt (or just after it) inserts a git hash (if this sort of 'the current time is ...' 'git HEAD is ...' dynamic content is to be inserted, clearly it OUGHT to occur after all the project instructions reads to allow for a longer prefix hit). you can also see that /clear does far less than it could/should (i.e. fork from just before the session-opening turn if project boot files were unchanged)