anthropics / anthropics/claude-code
[BUG] A persisting `cd` in a Bash tool call re-resolves project context and rewrites the system prompt, invalidating the entire prompt cache (5 captures, ~580k tokens each)
- Langage dominant
- Python
- Étoiles
- 145k
- Forks
- 23.1k
- Métriques de merge des PR
- Métriques de PR en attente
Description
**Version:** 2.1.259, macOS, OAuth (Max), `claude-fable-5-1[1m]`, `promptCacheTtl: "1h"`, one large monorepo with subagents.
## What happens
Claude Code tracks the shell's working directory across Bash tool calls. When the model runs a bare `cd apps/ios/Ceeya && …`, the cwd persists after the command. On the next system-prompt rebuild, the client re-resolves project context from the *new* cwd: it walks up looking for `.claude/` trees, and picks a different agent-memory root and memory index if one exists on that path. The first system block changes. The system prompt is the first cache breakpoint, so everything after it is rewritten at cache-write price.
In a monorepo this happens constantly, because the model `cd`s into a package to run its build or tests, and Claude Code's own project-memory feature plants `/.claude/agent-memory//` wherever a subagent is spawned from. This repo had 25 such nested trees, all created that way, none intentional.
## Receipt (recorded request bodies at the proxy boundary)
Two consecutive requests, 645k-token session. Tools identical, `messages[0]` identical, history identical. The only difference:
```
prev system[3] (55,010 chars):
…file-based memory system at `/…/Ceeya/.claude/agent-memory/ceeya-dev/`…
curr system[3] (38,291 chars):
…file-based memory system at `/…/Ceeya/apps/ios/Ceeya/.claude/agent-memory/ceeya-dev/`…
usage: cache_read 645,328 → 63,755 cache_creation 579,317 (1h tier)
```
The Bash call two turns earlier was `cd /…/Ceeya/apps/ios/Ceeya; for f in CeeyaTests/…`. Two minutes later the model `cd`'d back to the repo root and the block flipped again, 38,291 → 55,010 chars, 583,801 tokens written. Two `cd` commands, ~1.16M tokens rewritten, roughly $24 at Fable 5.1's 1h write rate.
Five of the six full-history cache collapses in that session had exactly this signature. The sixth was an edit to a `MEMORY.md` that feeds the system prompt, which has the same effect for the same reason.
## Why it's easy to miss
The cost shows up as an expensive turn, not an error. `cache_read` collapsing to the system+tools floor is only visible in the API response usage. And the `cd` and the rewrite are separated by one or two turns, so nothing in the UI connects them. I only found it by putting a recording proxy in front of the session and diffing consecutive bodies at each collapse.
## Expected
Any of these would fix it:
1. Resolve project context once at session start and pin it for the session. A `cd` inside a tool call should not change which memory root or CLAUDE.md set the *conversation* is bound to.
2. If cwd-sensitive context is wanted, deliver the delta as a tool result or a user-turn note (both are replayed byte-for-byte) rather than by mutating the system prompt.
3. At minimum, warn when a Bash command ends in a different directory than it started, since the next turn will pay a full rewrite.
Separately: creating `.claude/agent-memory//` at the spawning cwd rather than the project root seems unintended. It silently seeds the nested trees that make (1) bite.
## Workaround (applied, zero collapses since)
- Consolidated every nested `.claude/agent-memory/` tree into the repo root and gitignored `**/.claude/agent-memory/` below it.
- A PreToolUse hook that denies a bare persisting `cd`; subshells `( cd … && … )`, `git -C`, `pnpm -C`, and absolute paths pass.
- A rule in the agent's system prompt saying the same.
## Related
Same family as #83913 (history mutated on rebuild); full dissection with the other causes: #91707.
Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Piste de recherche
No source file or test is named. Start by reproducing the persistent Bash cwd change and inspecting the next system-prompt rebuild, comparing consecutive request bodies and cache usage at the proxy boundary as described. Done means the conversation-bound project context no longer changes after a tool-call cd, or the chosen alternative behavior is documented and verified without full-history cache collapses.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- bash
- Domaine
- cli, performance, tooling
- Type d'issue
- Bug
- Difficulté
- 5/5
- Temps estimé
- Plus d'une semaine
- Activité
- Active
- Clarté
- Plutôt claire
- Accessibilité débutants
- 35/100