[Bug]: Stop still kills the Claude CLI and `--resume`s, so every Stop rewrites the full prompt cache (not covered by #10689)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 23k
- Forks
- 5.9k
- Avg merge
- 11h 14m
- Merged PRs (30d)
- 357
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
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>.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() 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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in apps/server/src/provider/Layers/ClaudeAdapter.ts and trace interruptTurn through stopSessionInternal to query.close(), then inspect how the next message uses --resume. Reproduce the Stop and follow-up sequence with the transcript cache metrics; done means Stop interrupts the turn without closing the CLI process and the follow-up preserves the cached prompt prefix.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 64/100