[BUG] Claude abuses bash tools for reads, writes, and edits when running in Auto Mode
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
After updating to the latest version, I started noticing that Claude no longer used the Read tool for reads and instead favored using sed and cat for reading files in Claude Code VSCode Plugin chat sessions. I asked it why it was doing that and it reported that it received this instruction straight from the harness:
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.
As far as I can tell, this is relatively new behavior and breaks the built-in caching that you get from the dedicated Read tool.
This also impacts the way it does edits. Rather than just using the Write and Edit tools like it used to, it tries to craft elaborate scripts to do trivial edits and wastes a lot of tokens in doing this. I've had to stop it multiple times and tell it to use the Edit tool instead of bash scripts.
What Should Happen?
- Claude should favor the
Readtool over bash commands to maximize cache hits for files already read in a given session. - Claude should use the
EditandWritetools for trivial edits instead of crafting overly elaborate bash scripts to do the same edits
Error Messages/Logs
Steps to Reproduce
- Start a new chat session
- Set the mode to Auto Mode
- Prompt Claude to take a look at a file and make some trivial edits
Expected:
- Claude uses the
Readtool when reading files for the duration of the session and only falls back tosedfor genuinely large files - Claude uses the
EditandWritetools when writing to files for trivial edits
Actual:
- Claude abuses
sed,cat, and other bash tools for reads - Claude tries to craft bash scripts for what seem like trivial edits
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
2.1.235
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Windows Terminal
Additional Information
_No response_
17 Comments
I've noticed this issue too recently, Claude even told me so too:
<img width="921" height="65" alt="Image" src="https://github.com/user-attachments/assets/12cfc512-5a53-443e-bbed-6205b4ba5239" />
This should not be the standard. It makes following along very difficult (or even after the fact, checking what it did by scrolling up).
Claude Code v2.1.236
On WSL2 / Ubuntu
Yeah, we've had to add this instruction to our enterprise managed settings and roll it out to all the engineers as a work around until this is fixed:
It introduced some real copy errors for me because of how much it botched using tools in bash to edit things.
This is apparently an intended change in Claude's system prompt, see the discussion here: https://www.reddit.com/r/ClaudeCode/comments/1vruj7h/psa_claude_will_now_use_bash_instead_of/ .
The real critical-level problem of this change (whether I'm right and it was intended, or not) is that, of course, Claude will sometimes mess up the (overly convoluted) scripts for simple file edits. And that can incur data loss. I already experienced it once - half of my document was deleted due to a bug in
sedshenanigans Claude invented for a simple couple-of-lines insertion (luckily for me, in this particular case, the document was recoverable).Auto mode classifier can only judge what's _safe_, not what's _correct_. Unfortunately this system prompt change turns auto mode into slop mode.
For someone who steers Claude a lot throughout a session, this essentially removes the steering wheel. You can no longer say, "We’re going the wrong way". Instead, you have to let Claude arrive at the wrong destination, then restart the navigation from there.
Sometimes (when the final change is small and readable) I actually prefer this behavior. But for larger changes it does the opposite of what auto mode is supposed to achieve - it wastes hours of my time and unnecessarily stretches out Claude sessions.
I think this breaks rules files, too. I only really noticed this issue when Claude started violating recommendations in our rules files; turns out they aren't being loaded when Claude skips the file tools.
https://github.com/anthropics/claude-code/issues/88041#issuecomment-5385012523 this solution solves the problem on the short term.
Looks like this does the trick!
Without that env var:
<img width="472" height="520" alt="Image" src="https://github.com/user-attachments/assets/bb313de3-7438-413c-9d01-792b19cbc412" />
With the env var:
<img width="488" height="594" alt="Image" src="https://github.com/user-attachments/assets/6452b284-1768-468e-ab89-af0462a0e87e" />
This misfeature makes Claude Code ignore nested CLAUDE.md files sometimes because it never gets them auto-loaded if it abuses bash to write a file in a directory that contains a CLAUDE.md. This bit me today when Claude missed a critical instruction in my
migrations/CLAUDE.mdand wrote a broken database migration file.Adding a data point from the Windows side, since the reports here are mostly Linux/WSL/macOS and the platform changes the failure mode.
Confirmed in the cohort on Windows 11 (Git Bash):
~/.claude.jsonhas"tengu_thrifty_sonic": true, and there is nocozy_teapotkey in my build at all — so this account gets the strict wording with no relaxed variant available.What makes this worse on Windows specifically:
cat/sed -n/grepis a fork, and fork is expensive here in a way it is not on Linux. The instruction trades oneReadcall for N shell round-trips on the platform where shell round-trips are slowest.Write/Editapply. #89307 already reports CRLF being introduced into files under an LF project convention. Ased -ion a CRLF file also silently leaves\rinside captured groups, which corrupts matches rather than failing loudly.On the substance, I want to add one thing to the argument in #89731 rather than repeat it. The strongest objection here is not that Bash is a worse tool — it is that the token accounting was done on the wrong ledger.
sed -nis cheaper thanReadper call, which is presumably the metric the experiment optimized. But that measurement excludes the cost of the failures it introduces: a scripted substitution that no-ops exits 0 and is reported as a successful edit, so the model proceeds on a false premise and the correction costs a multiple of whatever the originalReadwould have. #90704 in this repo is exactly that shape. Cheaper per call and more expensive per task are not in conflict; the experiment appears to have measured only the first.The reliability asymmetry is the part I would ask be weighed explicitly:
Editanchors on exact text and refuses on mismatch. A shell substitution fails silently, in the wrong place, or partially. Those are not equivalent tools with different token costs — one has a correctness gate and the other does not, and the gate is the reason the 2.1.31 changelog entry called the dedicated tools an improvement in the first place.Separately, as a matter of process: this reverses two changes (2.1.21 and 2.1.31) that were both announced in the CHANGELOG as improvements, and the reversal was announced nowhere. Arriving by silent cohort assignment means affected users cannot distinguish it from the model degrading, which is precisely what several of us initially concluded.
CLAUDE_CODE_THRIFTY_SONIC=0works — I have it pinned insettings.json— but an undocumented env var named after the experiment rather than the behavior is not a user-facing control, and as #89731 notes, its parse falls back to cohort assignment on any value outside the accepted set, so a typo silently re-enrolls you.The ask I would support: split auto-approval from tool routing into two settings. Nothing about wanting fewer permission prompts implies wanting edits to bypass diffs, checkpoints, and hooks. Bundling them means users cannot take the feature they asked for without the one they didn't.
Not happy about this one. Adding my voice to the request for a revert or a documented, stable setting.
This is a seriously backwards regression. Anthropic is injecting an instruction that steers agents around the very tool interfaces users depend on for visibility, contextual instructions, and edit-time hooks. What the hell is the point of configuring those hooks if the harness then explicitly tells the model to take a path that never invokes them?
We investigated this on Claude Code 2.1.263 after an implementation agent performed its edits through Bash/Python/sed instead of Edit/Write:
auto_modeattachment withbashFirst: true,bashFirstSteer: "strict",steerOnly: true, andbypass: false.PreToolUseintake gate andPostToolUsequality/advisory hook both matchEdit|Write|NotebookEdit. A Bash-based file mutation invokes neither. These are real configured hooks, not hypothetical safeguards.The hooks themselves have not malfunctioned: their tool matchers are doing exactly what they say. The regression is that the harness actively steers file mutations outside those matchers. Explicit verification commands still ran, but they do not retroactively provide the missing per-edit intake and advisory behavior.
Other users have separately reported skipped nested instructions and path-scoped rules; #92271 documents the same hook-routing problem. Blaming agents for following an injected instruction gets the attribution backwards.
Wanting fewer permission prompts is not consent to bypass the dedicated editing workflow. Bundling those two decisions is unacceptable. Please remove this steering by default, or provide a documented, stable, independent setting for it. An undocumented
CLAUDE_CODE_THRIFTY_SONIC=0experiment switch is not an adequate user-facing remedy.Please also document which behaviors depend on dedicated file tools and test that interaction before rolling out tool-routing changes. Whatever the intended optimization, this is a broken tradeoff for users whose workflow depends on those interfaces. We should not have to inspect bundled CLI code and session attachments to discover why the harness is undermining our configured workflow.
This thread has the most visibility of the several reports on this behaviour, so a pointer for anyone landing here: the detailed measurements live in #90450, and I've just added findings there that aren't in either thread yet. Two of them change what "am I affected?" means, so summarising rather than only linking:
The gate is per-session assignment (
forced/cohort/none), not per-model. Fable 5.1 isforced; Opus 5 sits in acohort, i.e. a remote A/B gate. Two users on the same version and model can therefore see different behaviour, and the same user can see it change between sessions — which is much of why this reads as intermittent.Subagents inherit the parent session's assignment (originally observed by @shunsock in #92271). A subagent on a model that is not assigned still receives the steer if its parent session is. So changing the subagent model is not a mitigation, and in a multi-agent setup every subagent loses nested
CLAUDE.mdand path-scoped rules at once — invisibly, since the parent only sees each subagent's summary.The mitigation found by users (not documented anywhere): setting
CLAUDE_CODE_THRIFTY_SONICtofalseinsettings.jsondisables the Bash-first steering while keeping Auto Mode. Credit to @kawasin73 in #90450; I've confirmed it independently on 2.1.263, and at user scope it covers subagents too, via the same inheritance.Also worth knowing: #92271 is the most complete write-up of the breakage (it covers path-scoped rules, nested
CLAUDE.md, andRead/Edit/Writehooks together, and identified the flag). It shows asClosed (completed), but it was closed by its own reporter shortly after they found the workaround — not fixed. Its findings are still current and easy to miss in open-issue searches.Still reproducing on 2.1.263: the steer text is byte-identical to 2.1.261, and the gating structure is unchanged.
Still reproducing on 2.1.268, VS Code extension, Windows 11 native (not WSL2, Bash tool backed by Git Bash), auto mode, two separate machines. Steer text is byte-identical to the 2.1.234 template in #88041.
One observation on Anthropic's own post and then a catalogue to try to collect these adjacent issues since I went through the headache of rederivation myself. Some of these have already been pointed to. Just figured a consolidated list would be nice.
The Bash-first steer runs against Anthropic's published design intent
How we built Claude Code auto mode:
In-project file editing is the designed fast path, intended to bypass classifier latency and justified by those edits being reviewable. The steer routes that same work through shell commands instead, shunting this Tier 2 work to Tier 3. However, by their own post, "Only actions with real downside potential reach the final tier."
Catalogue
Steer and gate
tengu_thrifty_sonicgate, ~1200-session bimodal measurementgit statusbeforereset/clean/rm -rf", is only in theelsebranch.bypassandsteerOnlyemit the Bash-first text aloneCounter to "shipped fixes", announced nowhere
Contradicts other shipped prompt text
grep/rgvia Bash"catguarantees the first Edit fails: 363 hits across 80 transcripts/rewindFail/rewindsilently no-ops on Bash-authored writes; a mixed session reports partial restore as successMemory, rules and skills never load
paths:frontmatter.claude/skillsand subdirectoryCLAUDE.mdBypassed Hooks
The shell appears to be the worse option
sed -iturned\nand\tin a Windows path into a real newline and tab; Everything exits 0.CLAUDE.md, the file the instruction stops loadingBashPreToolUsehook cannot substitute, sinceadditionalContextis unsupported forPreToolUsecmd | tail -5; echo $?reportstail's status< /dev/nullguard and every heredoc matches it, so a stdin-reading program blocks for 120sIt looks like with Opus 5.5’s release the opt out workaround no longer works
During some testing i also noticed Opus 5.5 loves to use Bash even with that THRIFTY_SONIC flag set to false/0.
One bit of good news though from version 2.1.288 rules and nested Claude.md are now also loaded with Edit and Write tools
Measured on Claude Code 2.1.296, macOS. Each action ran in a fresh
claude -psession. AnInstructionsLoadedhook was the ground truth, and every transcript was checked for exactly one tool call.What loads path rules and nested CLAUDE.md now:
cat/head/tail/nl/bat/sed -n, orgrep/rgwith a match. These also count inside a;or&&list.||, redirects (2>/dev/null), extra flags (cat -A),cd dir && cat file,grep -r, a grep with no match, and every Bash write (sed -i,>,>>, heredoc,python -c,cp).A fix that keeps Bash: a root CLAUDE.md brief that explains the gap and asks for one plain read per folder before working there. Tested on Opus in auto mode with
bashFirst:trueconfirmed in every session: 5 edit tasks × 3 runs per arm.| | No brief | Strict "Edit/Write only" brief | Read-first brief (below) |
|---|---|---|---|
| Rule loaded | 5/15 | 15/15 | 15/15 |
| Bash writes | 12/15 | 2/15 | 2/15 (after a Read) |
| Avg tool calls | 2.4 | 2.5 | 2.3 |
Small sample, and it's a workaround, not a fix, but it's been holding up for us.