Before submitting
Closest existing reports: #10600 (closed by #10689, which only fixed the idle-reaper clock and says "Claude cache invalidation after a genuine restart is unchanged"), #7338 (closed, asked for hard evidence), #8997 (the interrupt-instead-of-close fix, closed unmerged). This is the Stop half of #10600 that the triage there listed as still forcing a --resume.
Area
apps/server
Steps to reproduce
- Start a Claude Code thread and let it run a few tool calls so the context is a few tens of thousands of tokens.
- Press Stop while a tool call is running.
- Within the cache lifetime (I waited two minutes) send a follow-up in the same thread.
- Open
~/.claude/projects/<project>/<session-id>.jsonl and compare cache_read_input_tokens / cache_creation_input_tokens on the assistant messages before and after the Stop.
Expected behavior
Stop interrupts the in-flight turn and keeps the CLI process, so the follow-up continues with the same prompt prefix and hits the cache. This is what native Claude Code does on Esc: it appends [Request interrupted by user] and the process stays up.
Actual behavior
Stop goes through interruptTurn → stopSessionInternal → query.close() in apps/server/src/provider/Layers/ClaudeAdapter.ts (the code comment calls Stop a hard session boundary). The next message --resumes a new process and the whole prompt is re-sent as a cache write.
Per-turn usage from the transcript, deduplicated by message id:
| Time |
Event |
cache_read |
cache_creation |
| 14:59:33 |
last turn before Stop |
66,247 |
1,839 |
| 15:01:34 |
Continue from where you left off. meta + <synthetic> reply |
0 |
0 |
| 15:01:44 |
first turn after follow-up |
0 |
75,181 |
| 15:02:01 |
next turn |
75,181 |
628 |
One Stop rewrote 75k tokens that were cached two minutes earlier. That single turn cost more than the rest of the six-minute session combined, and it scales with thread length. The idle reaper was not involved (two-minute gap), so #10689 does not touch this path.
An extra trigger beyond the git status one in anthropics/claude-code#78720: with the follow-up message the resumed process received a deferred_tools_delta adding claude.ai connector tools (Gmail) and a mcp_instructions_delta appending Linear / Notion / PostHog instruction blocks. Connectors reconnecting late in the fresh process change the system prompt by themselves, so the miss happens even in an untouched repo.
Impact
Major degradation or frequent failure
Version or commit
0.0.41-nightly.20260909.1439 (includes #10689)
Environment
macOS 27.0.0, T3 Code Nightly desktop. Bundled Claude Code 2.1.266 (entrypoint: sdk-ts). Model claude-fable-5-1. Claude subscription, 1-hour prompt cache.
Logs or stack traces
14:59:33 assistant cache_read=66247 cache_creation=1839
15:01:34 user (isMeta) "Continue from where you left off."
15:01:34 assistant model=<synthetic> "No response requested."
15:01:38 user "fetch latest from gh, ..."
15:01:38 attachment deferred_tools_delta addedNames=[mcp__claude_ai_Gmail__..., ...]
15:01:38 attachment mcp_instructions_delta addedNames=["claude.ai Linear","claude.ai Notion","claude.ai PostHog"]
15:01:44 assistant cache_read=0 cache_creation=75181
15:02:01 assistant cache_read=75181 cache_creation=628
Full transcript lines available on request.
Workaround
Don't press Stop. Disabling cloud connectors in Claude Code settings (disableClaudeAiConnectors: true) removes one source of prompt mutation but not the restart itself.
Before submitting
Closest existing reports: #10600 (closed by #10689, which only fixed the idle-reaper clock and says "Claude cache invalidation after a genuine restart is unchanged"), #7338 (closed, asked for hard evidence), #8997 (the interrupt-instead-of-close fix, closed unmerged). This is the Stop half of #10600 that the triage there listed as still forcing a
--resume.Area
apps/server
Steps to reproduce
~/.claude/projects/<project>/<session-id>.jsonland comparecache_read_input_tokens/cache_creation_input_tokenson the assistant messages before and after the Stop.Expected behavior
Stop interrupts the in-flight turn and keeps the CLI process, so the follow-up continues with the same prompt prefix and hits the cache. This is what native Claude Code does on Esc: it appends
[Request interrupted by user]and the process stays up.Actual behavior
Stop goes through
interruptTurn→stopSessionInternal→query.close()inapps/server/src/provider/Layers/ClaudeAdapter.ts(the code comment calls Stop a hard session boundary). The next message--resumes a new process and the whole prompt is re-sent as a cache write.Per-turn usage from the transcript, deduplicated by message id:
Continue from where you left off.meta +<synthetic>replyOne Stop rewrote 75k tokens that were cached two minutes earlier. That single turn cost more than the rest of the six-minute session combined, and it scales with thread length. The idle reaper was not involved (two-minute gap), so #10689 does not touch this path.
An extra trigger beyond the
git statusone in anthropics/claude-code#78720: with the follow-up message the resumed process received adeferred_tools_deltaadding claude.ai connector tools (Gmail) and amcp_instructions_deltaappending Linear / Notion / PostHog instruction blocks. Connectors reconnecting late in the fresh process change the system prompt by themselves, so the miss happens even in an untouched repo.Impact
Major degradation or frequent failure
Version or commit
0.0.41-nightly.20260909.1439 (includes #10689)
Environment
macOS 27.0.0, T3 Code Nightly desktop. Bundled Claude Code 2.1.266 (
entrypoint: sdk-ts). Model claude-fable-5-1. Claude subscription, 1-hour prompt cache.Logs or stack traces
Full transcript lines available on request.
Workaround
Don't press Stop. Disabling cloud connectors in Claude Code settings (
disableClaudeAiConnectors: true) removes one source of prompt mutation but not the restart itself.