anthropics / anthropics/claude-code
[BUG] Auto-compaction re-injects the CLAUDE.md/MEMORY.md copy from the last user prompt, not the on-disk file; disk re-read only happens at the next prompt
- Dominant language
- Python
- Stars
- 145k
- Forks
- 23.1k
- PR merge metrics
- PR metrics pending
Description
## Summary
After an **auto**-compaction, the `CLAUDE.md` / `MEMORY.md` content re-injected into context is **not read from disk**. It is the copy captured at the **last user prompt**. Disk is consulted only when the *next* user prompt arrives, which is when the "Instruction files were re-read after the conversation was compacted; these differ from their earlier copies" system-reminder appears.
The docs ("Context window" → *What survives compaction*) say project-root `CLAUDE.md` and auto memory are "Re-injected from disk". In practice they are re-injected from an in-memory snapshot, so any edit made **during a long autonomous turn** (many tool calls, no user prompt) that spans an auto-compaction is silently reverted in the model's context until the user types something.
## Environment
- Claude Code 2.1.260 → 2.1.261, macOS (Darwin 25.4), desktop app "Code" tab; model `claude-fable-5-1`
- `CLAUDE_CODE_AUTO_COMPACT_WINDOW=300000` (project settings), 5 auto-compactions in one session
## Evidence (from the session transcript JSONL)
Every compaction writes an `attachment` record of `type: "instructions"` next to the `compact_boundary`; every user prompt after a compaction may write another one with `changed: true, reason: "compaction"`. Hashing the `files[].content` of each record and matching it against the git history of the project `CLAUDE.md` gives (all times UTC, same day):
| time | event | project CLAUDE.md injected | on disk at that moment |
|---|---|---|---|
| 20:42 | session start | version **A** | A |
| 20:55 / 21:11 / 21:29 | auto-compact ×3 (`instructions`, `changed` absent) | **A** | A / **B** (edited 21:03) / B |
| 21:37 | user prompt (`changed:true reason:compaction`) | **C** (= disk) | C |
| 21:55 | auto-compact | **C** | **D** (edited 21:44) |
| 22:00 | user prompt (`changed:true reason:compaction`) | **D** (= disk) | D |
| 22:49 | auto-compact | **D** | **F** (edited 22:09 → E, 22:46 → F) |
| 22:52 | user prompt (`changed:true reason:compaction`) | **F** (= disk) | F |
So at 22:49 the compaction re-injected a copy that was 40 minutes and two edits behind disk; the model then kept working on it for the rest of that turn. The same pattern holds for `~/.claude/CLAUDE.md` (edited 21:45 and 21:53; the 21:55 compaction still injected the 21:37 copy, 3060 chars; the 22:00 refresh delivered the current 2610-char file) and for the auto-memory `MEMORY.md`.
Note the refresh mechanism itself works: the `changed:true reason:compaction` record is correct every time. It just runs at the next user prompt instead of at the compaction.
## Steps to reproduce
1. Start a session; give one long task that will run through an auto-compaction (lower `CLAUDE_CODE_AUTO_COMPACT_WINDOW` to reach it quickly).
2. During that turn, have the model append a marker line to the project `CLAUDE.md` with a tool call.
3. Let auto-compaction happen inside the same turn.
4. In the transcript JSONL, compare the `instructions` attachment written at the `compact_boundary` with the previous one: same content hash, no marker. The marker first appears in the `instructions` record with `changed: true, reason: "compaction"` written at the next user prompt.
## Expected
At compaction, re-read `CLAUDE.md` / rules / `MEMORY.md` from disk (as documented), or at least run the same "re-read and inject what changed" step that currently runs at the next user prompt.
## Workaround
A `SessionStart` hook with matcher `compact` that lists instruction files whose mtime is newer than the session start (first timestamp in `transcript_path`) and tells the model to read them from disk.
Related: #91243 (docs question about which files `/compact` reloads), #88886 (same snapshot-at-session-start behaviour for subagents).
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by tracing the auto-compaction path that writes the `compact_boundary` and `instructions` attachment in transcript JSONL, then compare it with the next-user-prompt refresh that records `changed: true, reason: "compaction"`. Reproduce with a reduced `CLAUDE_CODE_AUTO_COMPACT_WINDOW` and a marker edit to project `CLAUDE.md`; done when compaction itself re-reads disk and injects current CLAUDE.md/MEMORY.md content.
Written by the indexing model from the issue text.
Assessment
- Domain
- cli, developer-experience, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100