CLAUDE.md / auto-memory block is never shared across sessions: it sits in messages[0] after the system breakpoint, with no cache_control of its own

Status Closed — duplicate
Reported on v2.1.270
Maintainer reply None cached
Activity 1 comment · opened Sep 15, 2026 · closed Sep 20, 2026

Summary

The prompt-caching docs and the "Prompt caching is everything" post describe project context (CLAUDE.md, auto memory) as its own cached layer, shared by parallel sessions in the same directory. In practice the block is emitted as the first content block of the first user message, with the user's prompt as a later block of that same message, and the next cache_control marker is on a session-context message that contains session-specific text. No request ever writes a cache entry ending at the CLAUDE.md block, so no other session can read it. Measured over 703 session starts: zero cross-session hits beyond the system prompt layer.

Environment

  • Claude Code 2.1.270 (also observed on 2.1.266), Windows 11, Opus 5, Claude subscription (1h TTL on the main conversation)
  • Both cc_entrypoint=cli and the desktop app (claude-desktop)
  • Tool search enabled (18 tools in the prefix, rest deferred)

What the docs say

code.claude.com/docs/en/prompt-caching, layer table: System prompt → Project context (CLAUDE.md, auto memory, unscoped rules) → Conversation, and under Cache scope: "Sessions you run in parallel in the same directory build matching prefixes and read each other's cache."

Blog: "Static system prompt & Tools (globally cached), CLAUDE.md (cached within a project), Session context (cached within a session), Conversation messages".

What the request actually looks like

Captured with a local pass-through proxy (ANTHROPIC_BASE_URL), request body of the first turn of a fresh session:

tools[18]                       (no cache_control; DeferredToolPlaceholder present)
system[0]  billing header
system[1]  "You are Claude Code, ..."
system[2]  core instructions                     cache_control
system[3]  static instructions + memory path      cache_control   <- per-directory (auto memory path)
messages[0] role=user
   [0] <system-reminder> CLAUDE.md (global + project) + MEMORY.md
   [1] <system-reminder> userEmail
   [2] <system-reminder> commit attribution
   [3..] the user's prompt (or /command + skill body)
messages[1] role=system                           cache_control
   SessionStart hook output, Environment block (cwd, OS, and
   "Scratchpad directory: ...\<session uuid>\scratchpad"),
   deferred tool list, agent list, MCP instructions, skill list, date

So between the last system breakpoint and the next one there are: the CLAUDE.md block, the user's first prompt, and a block with a per-session UUID and hook output that includes elapsed time ("há 0.2 h"). The prefix ending at messages[1] can never match another session's, and nothing ever writes an entry that ends right after messages[0].content[0].

Measurement

For every session JSONL under ~/.claude/projects/*/, take the first main-conversation assistant message and its usage, and the time gap to the most recent request of any other session in the same directory. 703 sessions, 474 of them started while another session in the same directory had been active within the last 60 minutes.

| cache_read_input_tokens on the first call | where it shows up |
|---|---|
| 46,328 | every directory, including a directory's first session ever and one whose previous session was 1,303 min earlier (another directory had kept the layer warm) |
| 49,760 / 49,769 / 50,595 / 52,548 | constant per directory (system[3] differs only by the auto-memory path) |
| anything larger | only on --resume (full history hit) |

Zero of the 474 warm starts read beyond the system[3] layer. cache_creation_input_tokens on those first calls is 23–36k, of which the CLAUDE.md+MEMORY block is roughly 4–7k tokens that would be byte-identical between sessions of the same directory.

Expected

Parallel sessions in the same directory read the CLAUDE.md / auto-memory block from cache, as documented.

Possible fixes

  1. Put a cache_control marker on the CLAUDE.md block (messages[0].content[0]), or
  2. Move the block to system[4] with its own marker, ahead of the first user prompt.

Either way the session-context message (messages[1]) stays per-session, which matches what the blog already says about it. If neither is intended, the doc's layer table and the "read each other's cache" sentence should say that only the system prompt and tool definitions are shared.

Cost note

For one user this is small: ~4–7k tokens rewritten at the 1h write rate once per session. The reason to report it is that the documented design and the emitted request differ, and the /usage "likely cause" logic and the docs both reason from the documented layout.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗