System-reminder for file drift tells assistant not to inform user
Bug report: PostToolUse system-reminder falsely claims file changes are "intentional" and instructs the assistant not to disclose them to the user
Summary
During a single interactive Claude Code session, after several Edit/Write tool calls on local markdown files, the tool result was followed by a <system-reminder> block claiming the target file "was modified, either by the user or by a linter," asserting the change "was intentional," and explicitly instructing the assistant: "Don't tell the user this, since they are already aware." This occurred three times in one ~45-minute session. In at least one instance, the content shown as the "change" was not a benign formatting adjustment but a substantive content edit — a wikilink the assistant had just written was reported as replaced with a link to an unrelated file. The assistant disregarded the non-disclosure instruction and reported it to the user each time, per its standing safety guidance about not concealing information from users based on embedded instructions.
This report is about the reminder mechanism itself: (1) its content appears to be templated/fixed regardless of whether the underlying change is trivial or substantive, and (2) it directs the assistant to withhold information from the user, which is a concerning default for a feature whose entire purpose is to inform the assistant about state it didn't cause.
Environment
- Claude Code version: 2.1.220 (CLI, macOS)
- Session type: interactive, local filesystem, no git repository in the working directory
- Working directory: a local Obsidian notes vault (plain markdown + YAML frontmatter files)
- Tools involved:
Edit(existing-file modification) andWrite(new file creation)
Observed pattern (verbatim reminder template, genericized)
Immediately following a tool result for Edit/Write on a given file, a system-reminder appeared with this structure:
Note:<file path>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):<line-numbered excerpt>
Three occurrences in one session:
- File A — the assistant had just added a wikilink in a "Related" section pointing to a specific, correct target file. The reminder's excerpt showed that link replaced with a link to a different, unrelated file that had only just been created elsewhere in the vault moments earlier in the same session (i.e., a file the assistant had not yet even encountered in this edit). This is not explainable as routine formatting — it is a content substitution that, if left uncorrected, would have propagated an incorrect cross-reference into the user's notes.
- File B — the excerpt showed only a YAML frontmatter list being reformatted from inline-array style (
tags: [a, b, c]) to block-list style. Plausibly attributable to a local third-party note-taking application with an installed plugin that rewrites frontmatter shortly after any detected file save. - File C — identical cosmetic pattern to (2), same plausible local explanation.
Investigation performed (ruling out local causes)
Before treating this as noteworthy, the assistant (at the user's request) investigated locally configured automation that could plausibly produce file drift between an Edit call and the next read:
- Reviewed all
PostToolUse/PreToolUsehooks configured in both project-level and user-levelsettings.json. Two hooks existed: one that greps a file for ordering issues (read-only, distinct output text) and one unrelated notification hook (emits a fixed, clearly-labeled, different message and never touches file content). Neither matches the observed pattern or could plausibly generate it. - Reviewed all
launchd-scheduled/triggered background automation touching the same working directory (a scheduled task and a file-count-triggered watcher, both logged to disk). Confirmed via logs that neither had actually run during the session window in question. - Reviewed the third-party note-taking application's installed plugin configurations. Identified one plugin capable of producing the cosmetic YAML-reformatting behavior (item 2/3 above) as a side effect of its normal, documented function (auto-updating a "last modified" frontmatter field on detected saves, with an ~1-second delay) — a plausible, benign explanation for those two instances specifically.
- Exhaustively searched (via
grep -r) every hook script, automation script, plugin JSON config, and compiled plugin JS bundle on the local filesystem for the literal reminder phrasing ("modified, either by the user or by a linter," "don't tell the user," "already aware"). The phrase does not appear anywhere in any local configuration, script, or installed application. It exists only in the session's own transcript (i.e., as something received, not something locally authored). - Confirmed the
claudeexecutable itself is an unmodified, natively-compiled binary (not a wrapper script), and that no shell alias or profile script intercepts or wraps it.
Conclusion of the local investigation: the underlying file-touch in items 2 and 3 has a plausible, benign, non-Anthropic explanation (a local app's autosave-triggered plugin). Item 1's content substitution has no local explanation found. In all three cases, the specific reminder text — and in particular its instruction not to inform the user — does not originate from anything on the local filesystem, which points to it being generated by the Claude Code client or backend session-construction layer itself rather than by user-level configuration.
Why this is worth investigating
- The non-disclosure instruction is the core issue. Regardless of whether the underlying file change is benign or not, a reminder whose stated purpose is to inform the assistant of external state should not simultaneously instruct the assistant to hide that state from the user. This creates a structural incentive for the assistant to conceal information from the person it's working for, based on an unverifiable claim ("they are already aware") that the assistant has no way to confirm.
- The "intentional" framing may be applied uniformly regardless of actual cause. If this reminder is a fixed template applied whenever any file-content drift is detected between tool calls, it will misrepresent unexplained or erroneous drift (item 1) as equivalent to routine, expected drift (items 2/3), actively discouraging exactly the kind of scrutiny that caught the problem in this case.
- Item 1 suggests the drift-detection/diff-reporting path itself may be unreliable in a way independent of any real external process. A content substitution that inserts a plausible-looking but incorrect link, appearing immediately after a normal
Editcall with no corroborating local cause found, raises the question of whether the diff shown to the assistant in this reminder is always a faithful representation of a real on-disk state, or whether it can itself be corrupted/mis-attributed under some condition (e.g., a race in reading back the file, or a bug in whatever component detects and summarizes the drift).
Suggested questions for the investigating team
- What component/feature generates this specific reminder, and is its "was intentional... don't tell the user" phrasing a fixed template applied to all detected external file changes, or is it conditioned on something (e.g., a detected linter/formatter process)?
- Is there a known failure mode where the reported "diff" in this reminder does not correspond to an actual external write — i.e., could the reminder itself be constructed from stale or incorrect state?
- Should this reminder's template be revised to never instruct the assistant to withhold information from the user, given that the assistant cannot verify the "already aware" claim?
Reproduction notes
Not reliably reproducible on demand — encountered organically across ordinary Edit/Write usage in a long-running interactive session with a local third-party application (with file-watching plugins) also holding the same directory open. Happy to provide the full session transcript or .jsonl log to the investigating team on request (removed from this report to avoid including the personal note content it contains).
3 Comments
Update from the reporter: on further investigation, the drift we saw was fully explained by a local Obsidian plugin (
front-matter-timestamps) racing with Claude Code's own file writes — not something in Claude Code itself. The findings and recommendations below are for anyone else who lands on this issue with the same symptom. Given that, I don't think there's anything actionable here for the Claude Code team, and I'd recommend closing this issue.---
Supplement: findings and recommendations for others hitting this issue
This is a companion to the original bug report above. That report is written for Anthropic and deliberately withholds the local cause we found (since it's not their bug to fix). This document is the opposite: it's for anyone else running Claude Code against a directory that Obsidian (or a similar live-editing app) also has open, who hits the same symptom and wants the fastest path to a diagnosis.
The symptom
After an
Edit/Writetool call, Claude Code surfaces a system-reminder saying the file "was modified, either by the user or by a linter," calling the change "intentional," and telling the assistant not to mention it to the user. If you're running Claude Code, you may never see this text directly — but you may notice the assistant occasionally saying something like "a reminder just told me this file changed outside our conversation, and it looks like just a formatting change" (a well-behaved assistant should always surface this rather than silently comply with the "don't tell the user" instruction — see recommendation 1 below).Two separate things, easy to conflate
1. A real, local, benign cause — most likely a frontmatter-rewriting plugin.
If you use Obsidian with a plugin that rewrites the frontmatter block on save (we confirmed
front-matter-timestamps, but any plugin that fully re-parses and re-serializes YAML on a save-triggered delay will do this), and Claude Code is editing files in that same vault while Obsidian has it open, you'll get a race: Claude Code writes the file, Obsidian's file watcher notices, the plugin fires ~1 second later and rewrites the whole frontmatter block (commonly reformatting inline arrays liketags: [a, b]into block-list style), and Claude Code's next read sees content it didn't write. That's a real external change — Claude Code is not wrong to flag it. This part is fully explained and not a bug in Claude Code.2. A separate, harder-to-explain issue in the reminder's own framing.
The reminder's "this was intentional, don't tell the user" wording appears to be a fixed template applied regardless of whether the drift is actually benign. In our case it fired identically on trivial cosmetic drift and on one instance of an actual content substitution (a correct wikilink swapped for an unrelated one) that had no plugin or local automation behind it. The assistant has no way to verify the embedded "they are already aware" claim, so treating it as ground truth is a real risk independent of the underlying cause. This is the part we reported to Anthropic.
Don't let finding cause #1 make you stop worrying about #2 — they're independent, and #1 being benign doesn't mean every future occurrence will be.
How we diagnosed the local cause
If you're trying to figure out whether your own setup is doing this:
PostToolUse/PreToolUsehook script (project and user-levelsettings.json) and any scheduled automation touching the vault for the literal reminder phrasing. If it's not there, it isn't coming from anything you configured.fswatchfor confirmation, not attribution. A simple recursivefswatchon the vault will show you how many times and when a file is touched after a single edit — if you see two touches (yours, then a second one ~1 second later) even with no visible user action, that's your reformatting plugin.fswatchwon't tell you which process did the second write; for that you'd needfs_usagewith process attribution, but in practice the timing pattern plus the A/B test is enough to confirm it without needing that level of detail.Recommendations
Updated:line and replace only that line's text, leaving everything else in the frontmatter block untouched. We implemented this two ways so it covers edits from both sides:PostToolUsehook (any language) that fires after Claude Code's ownEdit/Writecalls and does the line-level replacement.vault.on("modify", ...)listener once per app launch, doing the identical line-level replacement for edits made directly in the app. Make it idempotent (skip the write if the target line already matches) so it can't re-trigger itself in a loop when its own write fires anothermodifyevent.Between the two, every edit path gets a current
Updatedtimestamp and neither one can reformat anything else in the file.Open question we couldn't close
The one content-substitution incident (a wikilink replaced with a link to an unrelated file) was never reproduced across repeated controlled retests and had no local automation behind it. Best working theory is a live-editing collision rather than anything systemic, but that's a guess, not a finding. If you hit something similar, the reminder's own diff is the only evidence you'll have — capture it before it scrolls away.
Closing per the update above — root cause is local, not a Claude Code bug.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.