What's Wrong?
Claude Code embeds the per-session console URL inside the Bash tool's description:
- Command output … <https://claude.ai/code/session_01Rq9o…> (appears twice in the description text)
Tool definitions are part of the cached prompt prefix, at its very front. Because this URL is unique per session, tools[] differs byte-wise between any two sessions that are otherwise identical — same repo, same settings, same system prompt. Consequences:
- A new session can never warm-start on the prompt cache of a previous one, even though everything else in the ~20k-token prefix (tools + system prompt) is byte-identical. Every session pays a full cache write for a prefix that differs only by its own URL.
- Headless runs (
claude -p) in CI/automation pay this on every invocation.
This is the CLI sibling of #27786 (Agent SDK: random UUID in the Bash tool description, closed/fixed). The SDK fix did not carry over to the CLI's session URL.
Environment
Claude Code 2.1.220, linux. Verified by diffing captured /v1/messages bodies from two sessions through a local proxy: the Bash description is the only divergence carrying session identity; our proxy strips it (toolFingerprint normalization) precisely because of this.
What Should Happen?
Tool descriptions should be byte-stable across sessions. The session console URL belongs outside the cached prefix — e.g. in a tail system-reminder (like other per-session context CC already injects), or omitted from the model-visible description entirely; the model rarely needs its own console URL, and when it does, a stable placeholder ({{SESSION_URL}}) resolved client-side would keep the bytes fixed.
Steps to Reproduce
- Capture request bodies from two CC sessions in the same repo (any MITM proxy).
- Diff the first request's
tools[] between the sessions.
- The Bash tool description differs only by the embedded
https://claude.ai/code/session_… URL — and that difference sits inside the cached prefix.
Related work: we mitigate several prefix-invalidation classes in a proxy fork (see cnighswonger/claude-code-cache-fix#272, #273, which address the mid-history reminder rewrites of #76606 and the tools[] mutation of #81967 respectively).
🤖 Generated with Claude Code
Update (same day): the capture + replay toolchain used for the verification above is now PR'd upstream (cnighswonger/claude-code-cache-fix#275, #276), so the reproduction steps are runnable end-to-end on anyone's own traffic.
What's Wrong?
Claude Code embeds the per-session console URL inside the Bash tool's description:
Tool definitions are part of the cached prompt prefix, at its very front. Because this URL is unique per session,
tools[]differs byte-wise between any two sessions that are otherwise identical — same repo, same settings, same system prompt. Consequences:claude -p) in CI/automation pay this on every invocation.This is the CLI sibling of #27786 (Agent SDK: random UUID in the Bash tool description, closed/fixed). The SDK fix did not carry over to the CLI's session URL.
Environment
Claude Code 2.1.220, linux. Verified by diffing captured
/v1/messagesbodies from two sessions through a local proxy: the Bash description is the only divergence carrying session identity; our proxy strips it (toolFingerprintnormalization) precisely because of this.What Should Happen?
Tool descriptions should be byte-stable across sessions. The session console URL belongs outside the cached prefix — e.g. in a tail system-reminder (like other per-session context CC already injects), or omitted from the model-visible description entirely; the model rarely needs its own console URL, and when it does, a stable placeholder (
{{SESSION_URL}}) resolved client-side would keep the bytes fixed.Steps to Reproduce
tools[]between the sessions.https://claude.ai/code/session_…URL — and that difference sits inside the cached prefix.Related work: we mitigate several prefix-invalidation classes in a proxy fork (see cnighswonger/claude-code-cache-fix#272, #273, which address the mid-history reminder rewrites of #76606 and the tools[] mutation of #81967 respectively).
🤖 Generated with Claude Code
Update (same day): the capture + replay toolchain used for the verification above is now PR'd upstream (cnighswonger/claude-code-cache-fix#275, #276), so the reproduction steps are runnable end-to-end on anyone's own traffic.