Background Agent subagent's worktree/Bash sandbox gets redirected by parent session's later EnterWorktree call

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

Summary

A background Agent-tool subagent's Bash sandbox isolation appears to track the parent session's live EnterWorktree pin, not a value fixed when the subagent was dispatched. If the parent session calls EnterWorktree (to a different path, for unrelated work) while a background subagent is still mid-task in its own worktree, the subagent's subsequent Bash commands are refused/redirected toward the parent's new pin instead of the worktree it was actually assigned.

This is dangerous because a subagent that isn't watching for it can end up executing file writes (including git checkout --, commits, etc.) against the wrong working tree — in our case, briefly clobbering the subagent's own uncommitted work when the parent (unaware anything had gone wrong) ran an ordinary cleanup command against what it reasonably believed was an unrelated, empty directory.

Repro (confirmed, reproduced deliberately)

  1. Parent session calls EnterWorktree({ name: "some-path" }), dispatches a background Agent subagent to do file-writing work. The subagent is not given isolation: "worktree" — it's instructed via its prompt to create and navigate to its own worktree/branch itself.
  2. Subagent creates its own worktree (e.g. via git worktree add) and begins editing files there — confirmed via its own pwd/git branch --show-current output at the time.
  3. While the subagent is still running, the parent session calls EnterWorktree({ path: "<a different, unrelated worktree>" }) for its own separate task.
  4. The subagent's next Bash tool call is refused, with a sandbox message naming the parent's new worktree as "the shared checkout" and telling the subagent to re-run its command from there — even though the subagent never called EnterWorktree itself and has no reason to think its assigned location changed.
  5. We tested the mechanism directly: with the parent's pin sitting at path A, the subagent's Bash calls targeting its own (different) worktree B were refused, naming A. When the parent then called EnterWorktree({ path: B }) (matching the subagent's actual assigned worktree) and the subagent additionally called EnterWorktree({ path: B }) on its own side too, its Bash calls then succeeded there. Moving the parent's pin is what gated whether the subagent's commands worked at all — the subagent's own EnterWorktree calls alone did not fix it while the parent's pin was elsewhere.

Impact observed

  • A background subagent's ~150 lines of uncommitted work (a schema/validator addition) were briefly destroyed when the parent, believing a directory had accumulated unrelated stray files, ran git checkout -- <file> against what turned out to be the subagent's real in-progress work — because the subagent's writes had landed in the parent's currently-pinned worktree rather than its own. Recovered without permanent loss only because the subagent still had the content in its own context and could restate it verbatim.
  • A second, differently-shaped incident the same day (possibly the same root cause, possibly a distinct issue — see below): a different background subagent, told to create its own worktree, encountered a benign/transient git message (failed to store: 100001 / could not lock config file — a credential-helper artifact that in our experience never corresponds to a real git failure) while attempting git worktree add, and — rather than retrying — concluded it should work in "its already-assigned worktree," which turned out to be the parent session's own home worktree. This may be the same underlying mechanism surfacing differently, or an unrelated model-behavior issue (treating a benign warning as a hard failure). We were not able to cleanly separate the two explanations.

Model tiers observed

  • The confirmed, deliberately-reproduced instance (the numbered repro above) was on Opus.
  • The second, differently-shaped incident was on Sonnet — but as noted above, we can't be certain it's the identical bug rather than a related-but-distinct failure mode.
  • A third incident was reported by a peer Claude Code session on the same machine, same day, writing to the same repo — it found its own uncommitted content (an appendix to a planning doc) sitting in a worktree belonging to an already-merged branch, written via an absolute-path Edit tool call rather than a relative Bash path. That session flagged it as a possibly more serious variant, since an absolute-path edit landing in the wrong place would rule out ordinary relative-path/cwd confusion, but explicitly hedged that it couldn't rule out its own user/harness error either. We were unable to confirm that session's model tier before it completed its own task and its worktree was cleaned up.

What we'd expect instead

Either:

  • A background subagent's sandbox/worktree assignment is fixed at dispatch time and never affected by anything the parent session does afterward, or
  • If a shared/global "current worktree" concept is intentional, a subagent should be told explicitly (not just refused with a generic message) that its assignment changed out from under it, so it can stop and report rather than silently working somewhere unintended.

Workaround we've adopted

Passing isolation: "worktree" on the Agent tool call itself (letting the harness provision the subagent's worktree, rather than instructing the subagent to self-navigate via prompt) and avoiding any EnterWorktree/ExitWorktree call in the parent session while a background subagent is still running. Untested whether isolation: "worktree" fully closes this — we adopted it going forward but haven't yet deliberately re-reproduced the bug against it.

View original on GitHub ↗