Bash tool refuses read-only and worktree-local commands as 'too complex to verify' in git worktree isolation
Environment
- Claude Code 2.1.283, headless (
claude -p) - macOS (Darwin 25.6)
- Reproduced with hooks, plugins and MCP servers disabled
Summary
Inside a subagent dispatched with isolation: "worktree", the Bash tool refuses many read-only and worktree-local commands. These commands never leave the agent's own worktree, yet they are rejected with two classes of messages:
- "too complex to verify that it stays inside the worktree"
- "isolated in the worktree ... cannot be shown not to be git"
The refusals block valid workflows. The commands below have been confirmed as safe by an installed tm hook --pm-guard (trusty-tools 1.7.8), which accepts all 16 shapes; the refusals originate in Claude Code 2.1.283.
Refused command shapes
uv run pytest tests/unit/test_github_sync_pull_recovery.py— path contains "github" substring, not a git commandsedcall on a shell variable path ($For loop variable$f)grep -n 'pattern_containing_git' <file>— pattern text contains "git" substring, not a git commandgrepwith pattern text containing "eval" substringgrep -n <pattern> <path-a> <path-b>— multiple path arguments to read-only grepls a b— multiple path arguments to lscat a b c— multiple path arguments to catgrep -n "rustdoc" .github/workflows/ci.yml— path contains .github/ subdirectoryterraform fmt infra/terraform/digitalocean/...— path contains "digitalocean" substringgit range-diff <a>..<b>— read-only git querycd <worktree> && git ...— directory change (cd) before git, worktree-localgit fetch origin; git checkout -b <branch>— chained git commands with semicolonfor f in <paths>; do sed -i '' ... "$f"; done— loop variable used as sed argument- Heredoc containing literal
{(e.g. Rust snippet piped to rustfmt) git checkout -b <branch>— create new branch, no -C redirect, worktree-localawk -f /dev/stdin <<'AWK' ...— awk program in quoted heredoc
Observed vs expected
Observed: Refusals are triggered by:
- Substring matches on "git", "eval", "github", "digitalocean" anywhere in arguments (not just command position)
- Path segments like
.github/or filenames containing pattern keywords - Multiple positional arguments to read-only commands (ls, cat, grep)
- Shell constructs like loops, cd, semicolon chaining, heredocs
- Environment variables like
$PWDor$Fin command arguments
One refusal can cascade, causing the isolation guard to refuse nearly every later command in the same session with "too complex to verify", including unrelated commands like cargo and ls.
Expected: Commands that run entirely within the agent's own worktree and never invoke git should be accepted. Substring matching in argument text should not trigger git-operation refusals when the command position is not a git operation. Refusals should be documented with actionable substitutes, or validated before implementation.
Workarounds
- Redirect grep/find to a file instead of piping
- Use absolute worktree paths instead of variables or relative paths
- Run single-argument invocations rather than multi-argument ones
- Write scripts to the scratchpad with the Write tool instead of inline heredocs
- Use Read tool instead of cat/grep for file inspection
- Avoid variable names or filenames containing "git", "eval", "github", "digitalocean"
Related
- bobmatnyc/trusty-tools#6982 — tracking issue collecting refused shapes
- anthropics/claude-code#97224 — isolation: "worktree" cannot target existing trees
- anthropics/claude-code#97225 — earlier issue on the same Bash-tool refusals
🤖🤖🤖 Generated with trusty-mpm — https://github.com/bobmatnyc/trusty-tools
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗