anthropics / anthropics/claude-code

Auto mode's Bash-first instruction is unusable with permissions.blockReadsOutsideWorkingDirectories

Open
#95,238 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
146k
Forks
23.8k
PR merge metrics
PR metrics pending

Description

# Auto mode's Bash-first instruction is unusable with `permissions.blockReadsOutsideWorkingDirectories`

## Environment

- Claude Code 2.1.258
- macOS 15.7.3 (darwin 24.6.0)
- Shell: zsh
- `~/.claude/settings.json` contains `"permissions": { "blockReadsOutsideWorkingDirectories": true }`

## Summary

Auto mode injects a system instruction telling the model to do file reads, searches
and edits through the Bash tool instead of the dedicated Read, Edit, Grep and Write
tools:

> 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.

`blockReadsOutsideWorkingDirectories` gates Bash commands with a static shell parser
that must prove every path a command touches is inside the working directory. Any
shell expansion defeats that proof, so the command escalates to a permission prompt:

> Contains expansion; under the read block
> (permissions.blockReadsOutsideWorkingDirectories) a command the shell parser cannot
> analyze asks the person

Command substitution, globs and variable references are ordinary in the exact command
shapes the auto mode instruction asks for. The result is a permission prompt on a
large share of tool calls, all day. In this workspace that is on the order of
thousands of prompts per day.

Two further points:

1. The auto mode instruction reverses a standing instruction in the same system
prompt ("Prefer the dedicated file/search tools over shell commands when one
fits"). The dedicated tools take literal paths, need no shell parsing, and pass
the read block without a prompt. Auto mode routes work away from the tools that
work and into the one that does not.
2. `Bash(cat:*)`, `Bash(grep *)` and similar entries in `permissions.allow` do not
suppress these prompts. The read block runs regardless of an allow-list match, so
an allow list cannot be used as a workaround.

## Reproduction

1. Set `"permissions": { "blockReadsOutsideWorkingDirectories": true }` in
`~/.claude/settings.json`.
2. Add `"Bash(cat:*)"` and `"Bash(grep *)"` to `permissions.allow` in the project's
`.claude/settings.json`.
3. Start a session in auto mode.
4. Ask for any task that reads several files, for example "summarise every settings
file under .claude".

Expected: the allow-listed read commands run without a prompt, or the model uses the
dedicated Read and Grep tools, which are not subject to the shell parser.

Actual: each command containing `$(...)`, a glob, or a variable produces a permission
prompt.

## Side effect on hooks

Auto mode also asks for file changes via `sed` and heredocs. A `PostToolUse` hook
matched on `Write|Edit` never fires for those changes. In this repo that hook runs
Prettier, so edits made under auto mode silently skip formatting that edits made with
the Edit tool receive.

## Related issues

These report the same parser behaviour from other angles. None of them names the auto
mode instruction as the cause of the non-literal paths, which is the point of this
report.

- #94560 — same symptom under strict sandbox mode, framed as a parser problem
- #91479 — allow-listed `gh` commands prompted because flag values are read as
runtime-computed paths
- #91629 — excessive prompts for allowed directories in auto mode
- #92582 — the read block ignores `additionalDirectories` from project and local
settings

## Suggested fixes

Any one of these would resolve it:

1. Suppress the auto mode Bash-first instruction when
`blockReadsOutsideWorkingDirectories` is enabled.
2. Let an explicit `permissions.allow` match satisfy the read block, so an allow list
is a usable workaround.
3. Give Read a batched form that accepts several literal paths in one call. The
stated benefit of the Bash-first instruction appears to be fewer round trips, and
a batched structured tool delivers that without defeating the parser. Independent
tool calls can already be issued in parallel in a single message, which weakens
the round-trip argument for routing work through the shell at all.

Contributor guide

No contributing guide indexed for this repository

Research direction

Reproduce with blockReadsOutsideWorkingDirectories enabled, the listed Bash allow rules, and an auto-mode task that reads several .claude files. Trace the auto-mode Bash-first instruction alongside the shell parser's handling of command substitution, globs, and variables, then check the PostToolUse Write|Edit hook behavior. Done means the reported prompt or hook mismatch is resolved without breaking the documented permission behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
shell, zsh
Domain
cli, developer-experience, security, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.