anthropics / anthropics/claude-code
Auto mode's Bash-preference directive silently overrides CLAUDE.md file-editing rules, and propagates into subagents
- 主要语言
- Python
- 星标
- 145k
- 派生
- 23.1k
- PR 合并指标
- PR 指标待抓取
描述
**Claude Code 2.1.234 through 2.1.270**, Linux (Ubuntu 26.04), CLI entrypoint. 2.1.270
is what is installed here now, but it accounts for only 1 of the 216 observations below;
these span several weeks and several releases, concentrated in 2.1.260 (110 events) and
2.1.263 (79). This is not a 2.1.270-specific regression.
## Summary
When auto mode is active, Claude Code injects a `` instructing the
model to prefer Bash (`sed`, heredocs, `cat`) over the Read/Edit/Write tools. On this
machine that directive **directly contradicts a rule in the user's own CLAUDE.md**, and
the injected text gives no guidance about which wins.
The practical outcome has been fine — every agent that surfaced the conflict in its
result independently decided the user's CLAUDE.md outranked the reminder, and declined
it. But that consistency is a property of instruction-following, not of the design.
Nothing in the system states the precedence, so the resolution is re-litigated from
scratch on every agent, and each one spends output tokens reasoning about it and
reporting it.
## The conflict
The injected reminder:
```
While auto mode is active:
Do your work through the Bash tool wherever it can accomplish the job: read files with
cat, head, or sed -n, search with grep and find, and make file changes with sed,
heredocs, or short scripts, rather than using the dedicated Read, Edit, or Write tools.
Fall back to a dedicated tool only when Bash genuinely cannot do the job.
```
The user's rule, loaded via CLAUDE.md from `claude-rules/editing-conventions.md:9`:
> For all file modifications, use the dedicated file-editing tools (Edit or Write — the
> assistant's built-in file tools). Use the shell (Bash) only for running scripts, git
> commands, or file inspection — never for in-place file edits via sed, awk, or
> heredocs.
These are not in tension at the margins; they are exact opposites on the same question.
## Why this is worth fixing
**1. No stated precedence, and no visible seam.** The reminder does not say "unless the
user's instructions say otherwise." Claude Code's own guidance elsewhere establishes that
user instructions (CLAUDE.md) outrank default behavior, so the correct resolution is
inferable — but it is inferred, not stated, and it is inferred separately by every agent.
The delivery mechanism makes this worse, and it is the part we got wrong on the first
pass. The directive text is **not in any CLAUDE.md on disk.** The vault's CLAUDE.md is 67
lines and unmodified; grepping all 21 CLAUDE.md files on this machine for the string
returns nothing. The harness appends the directive to the *CLAUDE.md contents block* at
prompt-assembly time, with no separator marking where the user's file ends and the
harness text begins. From inside an agent it therefore reads as one continuous document
authored by the user — which is exactly why agents kept concluding "the vault's CLAUDE.md
carries an appended auto-mode block," and then, finding that block contradicting the
user's other rules a few lines above it, reached for "prompt injection" as the only
explanation for a file that appeared to contradict itself.
This is the strongest argument for stating precedence in the reminder text itself: a
directive with no visible boundary cannot be recognised as a *default* at all, so there
is nothing for the agent to rank the user's rule against.
**2. It arrives as a ``.** That wrapper is the same one used for
genuine harness instructions, so it reads as authoritative. An agent that resolves the
conflict the other way — toward the reminder — would be violating an explicit user rule
while believing it was following the system.
**3. It propagates into subagents.** Measured on this machine at 2026-09-14 19:50 PDT,
counting `attachment.type == "auto_mode"` records carrying `bashFirst: true` across all
809 transcripts under `~/.claude/projects`: **212 transcripts received the directive —
190 of them subagent transcripts, 22 top-level sessions — over 216 attachment events.**
```sh
grep -rlF '"type":"auto_mode","autoModeConsentFlow":false,"bashFirst":true' \
~/.claude/projects --include='*.jsonl' | wc -l # 212 transcripts
grep -rhoF '"type":"auto_mode","autoModeConsentFlow":false,"bashFirst":true' \
~/.claude/projects --include='*.jsonl' | wc -l # 216 attachment events
```
Count the attachment records, not the reminder wording. The attachment's `rendered` text
is only persisted from CLI 2.1.265 onward, so just 2 transcripts in this entire corpus
contain the directive verbatim. A text grep for the wording undercounts the reach by
roughly sevenfold (~30 files against 212 transcripts) and, worse, gets the composition
entirely wrong: it mostly matches agents *writing about* the directive rather than
receiving it.
Only **about one in five of those 190 subagents** had been given an explicit,
spelled-out tool constraint in their brief ("use Edit/Write, never sed/heredoc") — 32 to
38 of them, depending on how strictly you pattern-match the brief, which is as precise as
this particular measure gets. That is worth stating plainly, because the opposite is easy
to assume: the other four in five received a directive that
contradicted the user's CLAUDE.md with nothing in their own prompt to flag it. The
conflict is not rarer there, only quieter — no agent notices, so no agent reports it.
In the great majority of cases — 194 of 212, and in **every subagent transcript
examined (190 of 190)** — the reminder was injected *after* the agent's first tool call,
contradicting the brief it was dispatched with. (17 transcripts saw it before the first
tool call; one session made no tool call at all.) One wrinkle for anyone reproducing
this: the only two transcripts that persist the reminder *text* are both non-`after`
cases (one saw it before its first tool call, the other made no tool call at all), so the
verbatim quote above cannot itself establish the ordering. That result comes from the
attachment's position in the transcript, not from its text.
Subagents are the worst place for an ambiguous override, because their operator cannot
see the conflict happening.
**4. Scope appears wider than configuration.** The `autoMode` block in
`~/.claude/settings.json` was configured with an environment description scoped entirely
to one repository (a single private application repo under the user's home directory —
its trusted-repo, sensitive-data, and soft-deny entries all name that project). The
behavioral directive nonetheless fired across **10 distinct working directories, and
only 80 of the 216 attachment events occurred in that configured repo.** The single
largest share landed in an unrelated project, and 20 of the affected transcripts made
tool calls against files in a personal Obsidian vault under `~/Documents`. (A further 28
merely had that vault in context rather than under edit — the distinction matters, and
the smaller number is the one we are standing behind.) Whether auto mode is
intended to be repo-scoped is not clear from the settings shape, but a configured scope
of one repo against an observed reach of ten working directories is more than surprising.
**5. The cost is real if small.** Every agent that *noticed* spent output tokens
deciding, and then reported the conflict in its result — several under headings like
"SECURITY / INSTRUCTION-CONFLICT REPORT" — because from inside a subagent, an unexplained
directive that contradicts your brief is indistinguishable from a prompt-injection
attempt. That is a reasonable inference for the agent to draw and a bad experience to
design for.
## Suggested fixes, smallest first
**First, a question that may be cheaper than any of them.** The runtime payload is
`{"type":"auto_mode","autoModeConsentFlow":false,"bashFirst":true,"bashFirstSteer":"strict","steerOnly":true,"bypass":false}`.
A `bashFirstSteer` of `"strict"` implies a non-strict steer mode already exists. If that
softer mode already defers to CLAUDE.md, then nothing below needs building — the answer
is configuration and documentation, and 196 of the 216 events here were `"strict"`
simply because that is what this machine was set to. Worth answering before any code.
1. **State precedence in the reminder text.** One clause — "unless the project's
CLAUDE.md specifies otherwise" — removes the ambiguity entirely and costs nothing.
Point 1 above is the argument for why this has to live in the reminder text rather
than in documentation: the agent cannot see where the harness text begins.
2. **Inject it before the first tool call rather than after.** Cheap, and well supported
by the measurement: 194 of 212 transcripts and every one of the 190 subagents got it
after they had already started working, so they planned against one instruction set
and were re-instructed mid-task. Ordering alone would fix that, independently of any
detection logic.
3. **Clarify whether auto mode is repo-scoped.** The configured environment block names
one repository; the directive fired across 10 working directories, with only 80 of
216 events inside that repo. If the block is meant to bind the mode to a project, the
behavioral directive should respect the same scope.
4. **Only then consider suppression or constraint detection** — suppressing the directive
when CLAUDE.md contains a contradicting file-editing rule, or when a subagent's prompt
sets explicit tool constraints. This is last for two reasons: detection is fuzzy, and
the subagent-prompt variant would miss roughly 80% of the exposure measured here,
since only about one in five of the 190 affected subagents had such a constraint to
detect. It would
silence the agents that complain while leaving the quiet majority unchanged.
## What this report is not
Auto mode's goal — fewer permission prompts by routing work through one already-approved
tool — is sensible, and the directive is reasonable as a *default*. The ask here is
precedence and scope, not removal.
Nor is this a security finding. An earlier internal pass on this machine characterised
the reminder as prompt injection; that was wrong, and is corrected here. `autoMode` is a
first-party Claude Code feature enabled in the user's own settings file. The reason
multiple independent agents on this machine reached for the security framing — several
filing it under headings like "SECURITY / INSTRUCTION-CONFLICT REPORT" — is itself the
most useful signal in this report: a legitimate feature was reliably mistaken for an
attack, because it behaved like one from the inside — unexplained, authoritative in form,
arriving glued to the user's own instruction file, and contrary to the instructions the
agent was given.
We are deliberately not putting a number on that one. How many transcripts "reached for
the security framing" turns out to depend almost entirely on how the phrase is
pattern-matched — counts we tried ranged from single digits to the entire affected
population, because harness boilerplate mentioning prompt injection appears in all 212.
The phenomenon is solid and reproducible; a headcount for it is not, so we are not
claiming one.
## Reproduction
1. Put a rule in CLAUDE.md forbidding `sed`/heredoc in-place edits.
2. Enable auto mode.
3. Dispatch a subagent with a brief that restates the rule, and have it edit a file.
4. Observe the `` arrive — in every subagent transcript measured here,
after the agent's first tool call — instructing the opposite, with no precedence
guidance, and appended to the CLAUDE.md contents block with no separator.
Measure reach by counting attachment records, not reminder text:
```sh
grep -rlF '"type":"auto_mode","autoModeConsentFlow":false,"bashFirst":true' \
~/.claude/projects --include='*.jsonl' | wc -l
```
212 transcripts here, 190 of them under `subagents/`, over 216 attachment events, at
2026-09-14 19:50 PDT. The corpus grows, so expect drift.
A text grep for the reminder wording is **not** a usable proxy: `grep -rl 'While auto
mode is active' ~/.claude/projects` returns ~30 files on this machine, nearly all of them
agents writing *about* the directive in their output, and zero subagent transcripts
containing the delivered text. That figure is also visibly unstable — it moved from 25 to
31 to 33 over three passes on the same machine within a couple of hours, because what it
actually tracks is how often agents have recently discussed the directive. The
attachment count over the same interval moved by one (215 → 216). The reminder's
`rendered` content is
only persisted from CLI 2.1.265 onward — 2 transcripts out of 212 here, both top-level.
贡献指南
这个仓库没有索引到贡献指南
评估
这个 Issue 还没有评估数据。