Repository navigation
🤖 fix: keep the cached system prompt when AGENTS.md changes mid-session - #7304
Conversation
Inside a context segment, the <custom-instructions> block (AGENTS.md files and project instructions) now stays at the text the segment first sent, read from the ledger (MuxMetadata.customInstructions on the turn's assistant row). A changed block goes in one system row after the newest user message, and every rebuild puts that row back in place, so the cached system block and history stay byte-identical. The next compaction folds the current block into the system prompt. Same mechanism, gating and old-data rules as the volatile system tail (prompt-cache mechanism 10, #6687). --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
… CRAP floor Moves the section-row gating and the merge of the two section plans into small helpers, so the custom-instructions freeze does not grow either function. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
🟢 e2e stories (Haiku): 14 passed27 agent steps · 7 replayed from cache · 31 model calls · 218.4k tokens (73% cached) All 14 tests in 9 files
e2e 0.20.0 · 3m 7s · web · run artifacts 🟢 e2e Electron stories (Haiku): 3 passed3 agent steps · 3 model calls · 8.1k tokens (21% cached) All 3 tests in 3 files
e2e 0.20.0 · 23.0s · electron · run artifacts 🟢 e2e agent repros (Haiku): no tests selectedSpend: $0.00 of the $1.00 cap (proxy ledger) e2e 0.20.0 · 5.3s · 2 targets (web, phone) · run artifacts |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e184d3e3c6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex P2 on #7304. buildSystemMessageFromSources now returns where its instruction-file blocks are: <custom-instructions> plus the <model-...> and <mode-...> sections scoped in those files, one contiguous span. The assembler freezes that span instead of parsing the final prompt for the closing tag, so a later "</custom-instructions>" line can no longer widen the span over the additional instructions, and a Mode:/Model: section edit in .xum/AGENTS.md goes in the row instead of rewriting the cached system prompt. Middleware that edits the prompt before the span end leaves the prompt as sent (no record). Replay sends the recorded prompt as is and lets the records decide the rows. The row header now says the blocks come from Xum and must be followed: live on Haiku 5.5 the old "Update:" header was followed in 1 of 3 runs, this one in 4 of 4. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
…al as a row Codex P2 on #7304. When the instruction files stop producing any block mid- segment (the only AGENTS.md was deleted or emptied), the system prompt keeps the frozen block and a row tells the model the custom instructions were removed, until the next compaction. A history without a frozen record sends no block and records nothing, as before. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
The fixture grew E by rewriting AGENTS.md between turns. Inside a context segment that change is now sent as a row with the whole new block while the system prompt keeps the old one, so E grew by more than the pad and the "instruction growth" and "after a restart" cases left their bands (with an empty HOME, as in CI). The pad and the growth go in the workspace scratchpad, which stays in the live system prompt. Passes on main too. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 78fcfb2b63
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… tags --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ <!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
A segment that started without an AGENTS.md (or a Model:/Mode: section)
recorded nothing, so the first block added later went straight into the
system prompt and rewrote the cached prefix. Supported routes now record
an empty baseline ({ text: "", placement: "system" }) at the segment
start, one record per segment, so the first addition becomes a
replacement row. An unchanged empty block sends no removal row.
Addresses Codex PRRT_kwDOPxxmWM6vgBAc.
---
_Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
<!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
|
Codex Review: Didn't find any major issues. Chef's kiss. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
Summary
A mid-session change to a workspace's AGENTS.md no longer rewrites the whole cached Anthropic history. Inside a context segment (between compactions), the instruction-file blocks (
<custom-instructions>and the<model-...>/<mode-...>sections scoped in AGENTS.md) now stay at the text the segment first sent, and Xum reads that text from the ledger (chat.jsonl), not from the live files. When the live blocks differ, Xum sends the new blocks as one system row after the newest user message, so the model follows the new instructions on that turn. Every later rebuild puts the row back in the same place, so the next turn's prefix still matches. The next compaction folds the current block into the system prompt.Background
Measured on one host (10-22 08:12 to 10-23 01:28 UTC, 1,548 Anthropic turns, a build with #7027 and #7029): 26
cache.prefix_breakevents in the system section, 1.45 rewritten histories per 100 turns, the largest class left. Each break's length change equals adocs/AGENTS.mdchange on main (+168 chars = #7117, +378 = #7176, about +1,214 = #7234). Agents merge main into their worktree, and the next turn read the new AGENTS.md into the stable system prompt. Turn envelopes showed the volatile-tail length unchanged at every break, so the change was in the stable part.The history already comes from the ledger. The system prompt did not: it was rebuilt from live files on every turn (
turnContextAssembler.ts,buildSystemMessageFromSources). This PR makes the cached instructions come from the ledger too.Implementation
MuxMetadata.customInstructions = { text, placement: "system" | "row" }on the turn's assistant row, the same shape and rule asvolatileSystemTail(🤖 fix: send a volatile system-tail change as a system row, keep the history cached #6687). Xum writes it only at a segment start and when the blocks change, not on every turn.buildSystemMessageFromSourcesnow returns the system message plus the exact instruction-file span (the text before it and the blocks). The assembler freezes that span only while the prompt still starts with the reported text, so it never parses the final prompt for tags.volatileSystemTail.tsgeneralizes its planner to "system sections" (planSystemSection): the volatile tail and the instruction blocks are two channels with their own field, row header and row id. Instructions plan first, so their rows come first.Validation
## Mode:edit, a removed AGENTS.md and a first AGENTS.md added mid-segment behave the same way. A</custom-instructions>line in later instructions does not widen the frozen span. Each test fails with its fix reverted.tests/ipc/tokenBudgetStages.fixture.integration.test.tsgrew the prompt by rewriting AGENTS.md. With this PR the request really carries both the old and the new block, so the larger estimate is correct. The fixture now grows the prompt through the workspace scratchpad, which stays live; its expected numbers are unchanged.Risks
Medium. It changes how the system prompt is assembled for Anthropic turns.
~/.xum/AGENTS.mdthat is about 10.8k extra tokens until the next compaction. They are written to the cache once and read after that.Tool: <name>sections from AGENTS.md go into tool descriptions and are not frozen here: an edit to one still rewrites the cached tool block (follow-up).agent_skill_readskill list.<model-...>/<mode-...>sections in the frozen prompt and sends the new ones in the row. A likely better rule re-freezes on a model or agent change (follow-up).system, which costs one extra cache rewrite (follow-up).Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:high• Cost:$585.33