[BUG] Session-specific scratchpad path early in the context stops cache reuse across sessions
Environment
- Claude desktop app (Code tab), bundled Claude Code 2.1.281; also reproduces with headless
claude -pfrom the same binary - macOS (Darwin 25.6.0)
- Model:
claude-opus-5-5
Summary
The environment context block includes the session scratchpad path:
scratchpadDirectory: /private/tmp/claude-<uid>/<project>/<session-id>/scratchpad
That path contains the session ID and appears before the project instructions (CLAUDE.md), the memory index, the skill listing, the agent listing and the deferred-tool list. So two sessions started in the same directory with the same configuration never reuse any cached context after the system prompt and tool schemas. Every new session writes the whole remainder to cache again at the cache-write rate. For recurring scheduled tasks this is most of what an idle run costs.
Reproduction
In one directory, run this three times back to back:
claude -p "Reply with exactly the word: ok" --max-turns 1 --output-format json --settings '{"disableAllHooks":true}'
Compare usage.cache_creation_input_tokens and usage.cache_read_input_tokens across the runs.
Observed
| Run | cache_creation_input_tokens | cache_read_input_tokens |
|---|---|---|
| 1 | 46,468 | 22,915 |
| 2 | 46,462 | 22,915 |
| 3 | 46,464 | 22,915 |
The cache read stays at ~23k, which is the system prompt and tool schemas only. None of the remaining ~46k is reused, even though the runs are seconds apart and well within the cache lifetime.
Diffing the persisted transcripts of two such runs shows exactly one difference in the model-visible context: the scratchpadDirectory field of the environment attachment (…/<session-A>/scratchpad vs …/<session-B>/scratchpad).
Expected
Identical sessions started within the cache lifetime should reuse the cached project instructions and listings. Only the parts that actually change per session should be written fresh.
Impact
A scheduled review routine that fires 44 times per weekday writes ~53k tokens to cache on every run, even when it finds nothing to do. That is ~2.3M cache-write tokens per day and about 82% of the routine's idle cost. With a stable prefix, every run after the first in an hour could read that from cache instead.
Suggested fix
- Move session-specific values (the scratchpad path and any other per-session IDs) to the end of the context, after the stable instructions and listings.
- Or make the path session-independent, for example one directory per project with per-session subfolders created lazily and not named in the prompt.
Related (lower priority)
These also give otherwise-identical sessions different starting context:
- The output of SessionStart hooks that run in parallel is added to the context in completion order, so it varies from run to run.
- When a hook's output is too large, the preview message names
<session-id>/tool-results/hook-<uuid>-stdout.txt, which puts per-session IDs near the start of the context.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗