Agent tool isolation:"worktree" spawns a seat whose every Bash call is refused on arrival (analyzer fails closed on plain commands too)
Summary
Spawning a subagent with the Agent tool's isolation: "worktree" parameter produces a seat that cannot execute any Bash command — the harness's own worktree-isolation analyzer refuses 100% of the seat's commands from the first call, including plain non-git ones, and keeps refusing after the seat follows the refusal's own instructions. The seat is dead on arrival: it judges nothing and burns its whole budget on refusals.
Measured: 10 of 10 worktree-isolated spawns dead on bundle 2.1.289 (2026-10-06), reproduced again today 4/4 commands on 2.1.296. Spawns without the flag on the same days and the same machine run normally.
Environment
- Claude Code 2.1.296 (npm global
@anthropic-ai/claude-code), Linux (WSL2, kernel 6.6.87). - Subagent: a custom read-only surveyor agent (tools Bash/Read/Grep/Glob), spawned with the Agent tool passing
isolation: "worktree". - Same behavior observed with a general-purpose seat on 2.1.289.
Repro
- Spawn a subagent with the Agent tool, passing
isolation: "worktree". - In the subagent, run one command at a time, plainly:
pwd, thengit status --short --branch, thengit worktree list, thennode --version. - Every call is refused before execution. Round 2: repeat all four as plain, separate commands, with no
cdand no compound syntax, from the isolated worktree the refusal text itself names — refused identically (8 refusals across the two rounds).
Refusal for plain pwd (verbatim):
This agent is isolated in the worktree/workspace/.claude/worktrees/agent-<id>, but this command runs trap inside a construct too complex to verify; what it reads or is handed as shell text cannot be shown not to run git. Refusing to run it — a worktree-isolated agent's git operations must target its own worktree. Split it into plain, separate commands and run them from/workspace/.claude/worktrees/agent-<id>.
Refusal for git status --short --branch and git worktree list (first line):
This agent is isolated in the worktree /workspace/.claude/worktrees/agent-<id>, but this command names git in a form too complex to verify that it stays inside the worktree.
node --version receives the same "runs trap inside a construct too complex to verify" template as pwd.
Expected
A worktree-isolated subagent should be able to run plain commands inside its own worktree — at minimum pwd, node --version and git status. Two specifics:
- The templates do not match the commands. Plain
pwdandnode --versioncontain neithertrapnor any git reference, yet get the "runs trap inside a construct too complex to verify ... cannot be shown not to run git" template.git status/git worktree listcontain git but are plain single commands, yet get the "names git in a form too complex to verify" template. - The refusal's own remedy does not work. "Split it into plain, separate commands and run them from
<worktree>" is exactly what round 2 did — identical refusals. The seat has no legal move.
Also noted: the auto-created worktree lands under the project mount (/workspace/.claude/worktrees/agent-<id> in this setup), not under the user's home, which puts an auto-generated checkout on a shared/bind-mounted path.
Measured history
- Bundle 2.1.289 (2026-10-06): 10 of 10 worktree-isolated spawns refused on EVERY Bash call, including a surveyor clerk handed the literal list
pwd; date; echo hi; git rev-parse HEAD(all four refused); a 7-seat batch of isolated referee agents returned no verdicts at all. Isolated spawns on the pre-update bundle the day before (2026-10-05) ran with zero refusals. - Bundle 2.1.296 (2026-10-13): reproduced, 4/4 commands, 2 rounds, plain forms included.
Related
- #96209 — subagent spawned before
EnterWorktreerefused afterward (trigger is the parent's laterEnterWorktree, not the Agent tool's isolation parameter). - #98307 — background session: after parent
EnterWorktree, subagent Bash refused even for other repos (same trigger class). - Analyzer false-positive family, all open: #100385 (overrides explicit PreToolUse allow), #100806 (substring match on "git"), #90377 (string-executor check matches every argument position), #97760 (curl + settings.json env var), #93592 (every
jjsubcommand), #77660 (remote-tracking ref clobbered).
Our shape — the isolation parameter itself yielding a seat that is refused on arrival — is not covered by any of these.
Workaround we ship in the meantime
Do not pass isolation: "worktree". Build seats create their own locked git worktree (git worktree add --lock under ~/worktrees/); read-only seats are handed a checkout path in their prompt. An in-repo dispatch-time guard refuses the flag so the failure costs one immediate refusal instead of one burned seat cycle discovered minutes later in the child's transcript.