Worktree-isolated background sessions: command shape verifier refuses safe read-only commands at scale (0/100 protective in sampled refusals)

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 28, 2026

Environment

  • Claude Code 2.1.243, Linux (WSL2, kernel 6.6.x)
  • Background jobs running under worktree isolation (EnterWorktree / .claude/worktrees/), where Bash commands pass through the bundled command shape verifier before execution

Summary

The shape verifier that protects worktree-isolated sessions refuses a high volume of safe commands. On one machine over 30 days, the "too complex to verify" refusal fired 7,431 times. A uniform random sample of 100 occurrences (fixed seed, reproducible selection over the raw capture log) classified as:

  • 9 self-test fixtures (our own guard probes — excluded)
  • 91 operational commands, of which: 0 correctly-blocked dangerous operations, 53 false positives on visibly safe work, 1 legitimate block with a safer decomposition available, 37 truncated in capture and honestly unclassifiable

Among the 54 operational records whose full command text was recoverable, 53 (98.1%) were false positives. Frequency-weighted false-positive rate over all operational records: 58.2% (95% Wilson interval 48.0–67.8%), with the 37 truncated records held out rather than guessed.

The genuinely dangerous operations the isolation exists to stop (writes to the shared checkout, redirected git against the primary checkout) are refused by separate, correctly-firing rules — in our sampling those rules were overwhelmingly protective. The "too complex" branch specifically appears to add retry latency and noise without measurable protection.

Minimal reproductions (all refused)

  1. Pure read-only compound:

``bash
cmp -s fileA fileB; printf 'ok\n'; sed -n '1p' fileC
``
→ "too complex to verify"

  1. Env prefix with no git anywhere, /tmp-confined:

``bash
HOME=/tmp/scratch cargo build --manifest-path /tmp/project/Cargo.toml
``
→ refused for "sets HOME, injecting git configuration" — the command contains no git invocation and targets /tmp

  1. Read-only git on a registered sibling worktree:

``bash
git -C /path/to/repo/.claude/worktrees/other-task log -1
`
→ refused, while
git -C /tmp/<clone>` is allowed

Common refused-safe shapes from the sample

  • Read-only enumeration loops: for n in 101 102 103; do gh issue view "$n" --json title,body; done
  • Read-only queries using command substitution: git --no-pager grep -n "pattern" $(git rev-parse HEAD) -- subdir/
  • mktemp-confined scratch with env prefixes: T=$(mktemp -d /tmp/probe-XXXXXX); HOME="$T" timeout 20 sometool --version
  • Read-only diagnostics: ps -o pid,args -p "$(pgrep -f pattern | head -1)"

Suggested improvements

  1. Verify compounds recursively: permit known-pure/read-only commands composed with ;, &&, and pipes instead of the blanket "too complex" refusal.
  2. Gate the git-configuration environment check on the presence of an actual git invocation in the command.
  3. Add a read-only git -C carve-out (status, log, show, grep, rev-parse, merge-base, worktree list) for registered sibling worktrees, and permit git init in fresh /tmp directories.

Explicitly not requesting

Relaxation of the shared-checkout git protections (those fired correctly in our sample) or of package-manager operand blocks (npm run … can execute arbitrary project scripts; plausibly intended policy — our sample counted these as false positives operationally, but we understand the design argument).

Workaround in use

Writing multi-step work to a script file and running bash <script-file> passes verification, so agents route around the checker at the cost of an extra write + retry per refusal — which is also why the rule as-is yields little protection: anything it blocks inline can be expressed as a script.

View original on GitHub ↗