[BUG] The external-file-change system note asserts an unverifiable cause ("by the user or by a linter") and the user's awareness — the model relays it as fact

Open 💬 2 comments Opened Jun 26, 2026 by milobird

Preflight

  • [x] I have searched existing issues and this specific angle isn't reported
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (2.1.193)

Summary

When a tracked file changes between a Read and the agent's next read/edit — from a cause other than the agent's own tool call — Claude Code injects a <system-reminder> describing the change. The note asserts a specific cause ("either by the user or by a linter") and that the user is "already aware." Both are guesses the harness can't verify: the change can equally come from a concurrent background task the same session started (a backgrounded Bash command or Agent/Task), an external tool, or any other process. The model has no reason to distrust a system note, so it treats the guess as fact — relaying a false provenance to the user ("you edited X", "a linter changed Y") and staying silent about a change the user never made.

The injected note (verbatim)

Note: <file> was modified, either by the user or by a linter. This change was intentional, so make sure to take it into account as you proceed (ie. don't revert it unless the user asks you to). Don't tell the user this, since they are already aware. Here are the relevant changes (shown with line numbers):
<diff>

It bundles three assertions, all of which only hold if the user (or a linter) actually made the change:

  1. Cause — "either by the user or by a linter." Omits the common case of a concurrent process, including background work the session itself spawned.
  2. Intent — "This change was intentional."
  3. Awareness + silence — "Don't tell the user this, since they are already aware."

This is about the note's wording over-asserting, not the change-detection mechanism (cf. #25623): even when detection correctly reports that the file changed, the asserted cause and awareness are unfounded.

Why this matters

  • Confabulated provenance. The model relays the guess as known truth — "you edited this file", "a linter reformatted it" — when neither happened. This manufactures false certainty: the model ends up more wrong than with no note, because it now has a confident-sounding but baseless source. Observed in a session where a backgrounded Agent wrote to a file the main session had read — the note attributed the change to "the user or a linter," and the model then told the user it was their edit. Neither the user nor a linter had touched the file.
  • Suppressed surprise. "Don't tell the user this, since they are already aware" is correct only when the user made the change. If a concurrent task or external process changed the file unexpectedly, the user is not aware — and the note instructs the model to stay silent about exactly the kind of surprising change it should surface.

Suggested fix

The note should not assert a cause (or the user's awareness) it can't verify. Either:

  1. Make the wording cause-neutral — e.g. "<file> was modified by a process outside this tool call (an editor or formatter, a hook, the user, or a concurrent task)." State what is known — the file changed, here is the diff — and stop. Drop the "intentional" / "already aware" / "don't tell the user" clauses, which only hold for the user-initiated case.
  2. Condition the strong wording on actual knowledge — assert "by the user" / "already aware" only when the change was genuinely user-initiated (e.g. a tracked external editor), and fall back to neutral wording otherwise.

Option 1 is simplest and removes the false-certainty failure mode entirely.

Related issues

  • #63854 — redact secrets in the file-modification system-reminder content. Same note, different concern.
  • #62336 — a concurrent subsystem writing mid-turn invalidates Edit read snapshots. Same trigger condition (concurrent write), different surface.
  • #25623 — mtime-based change detection gives false positives (IDE autosave). The detection layer that fires this note.
  • #59994 / #9769 — granular control over <system-reminder> injections. A related knob.
  • #30735, #50331 — same class: injected system text states something that doesn't match reality, which the model then acts on.

Environment

  • Claude Code: 2.1.193
  • Model: claude-opus-4-8
  • Platform: Anthropic API (Claude Code CLI)
  • OS: macOS (Darwin 25.4.0)

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗