Agent isolation:"worktree" — concurrent dispatches sometimes execute early commands in the parent worktree, not the isolated one
Summary
Agent tool calls with isolation: "worktree" appear to sometimes execute the
agent's first shell command(s) against the wrong working directory (the
parent/principal session's worktree) rather than the newly-created isolated
worktree, when several isolation: "worktree" agents are dispatched
concurrently. The agent's later commands in the same session then correctly
resolve to its own isolated worktree, and its own final self-report/footer
(worktreePath:/worktreeBranch:) can look entirely correct — but a stray
prefix of git-mutating commands has already landed in the shared parent
worktree.
What we observed
During an autonomous multi-agent release orchestration (Grimoire-framework
Noir paradigm, 14 Agent(isolation:"worktree") dispatches across 3 batches in
one release), the parent/orchestrator session's own principal worktree showed
a chain of 5 sequential git branch -m <name> events in its reflog — one per
dispatched agent in that batch, each renaming the shared checked-out branch,
each overwriting the previous rename. Each dispatch prompt instructed the
agent: "first, rename your current branch to <branch-name>" as its very
first action after landing in its own worktree.
Cross-checking each agent's own dedicated worktree afterward:
- 3 of 7 agents in that batch ended up with a correctly-renamed branch and
their real work correctly committed, entirely inside their own isolated
worktree (no visible effect from the above).
- 1 agent's own worktree never had its branch renamed at all (still sitting
on the default worktree-agent-<id> placeholder name) — but its actual
work was committed correctly inside its own worktree, under that
unrenamed branch. Its rename command appears to be the one that hit the
parent worktree's branch instead.
- 1 agent (the most severe case) had its entire final commit — not just the
rename — land on the parent/principal worktree's checked-out branch. Its own
dedicated worktree was left completely untouched at the original base
commit, with no commits of its own. Its self-reported
worktreePath:/worktreeBranch: footer did not accurately reflect what had
happened.
Separately (and possibly related, possibly a distinct issue), several later
agents in subsequent, less-concurrent batches reported catching their own
worktree rooted at a stale/wrong base commit (an old ancestor far behind the
intended integration branch's live tip at dispatch time) before making any
commits, and self-corrected by re-rooting in place.
Why this looks like a race, not a one-off
- The affected agents' substantive work (file edits,
git commit) mostly
still landed correctly in their own isolated worktrees, even when an early
command (the rename) did not — suggesting the misdirection is transient,
present only in the first tool call(s) issued right after worktree
creation, and resolves itself shortly after.
- The one full-cross-contamination case is consistent with the same
transient window simply lasting long enough to also catch that agent's
final commit, rather than a structurally different failure mode.
- This only appeared with several
isolation:"worktree"agents dispatched
in the same batch (i.e., concurrently) — not with single, sequential
dispatches earlier/later in the same session.
Impact
- Silent branch/commit corruption in the parent session's checked-out
branch — recoverable via git reflog + manual branch renaming (which is
how we recovered here, with no data loss), but only detectable by manually
auditing the parent worktree's reflog and every dispatched worktree's
actual branch/HEAD state — the agent's own "done" report and the
worktreePath:/worktreeBranch: footer are not sufficient signals to
detect it.
- Any workflow that trusts an isolated agent's self-report of having stayed
in its own worktree could silently merge or lose work incorrectly.
Ask
- Is
isolation: "worktree"provisioning (creating the worktree, attaching
the spawned agent's shell cwd to it) synchronous with the agent's first
tool call, or is there a window where a fresh agent's Bash cwd could
still resolve to the parent session's directory? A race here would
explain everything above.
- If a race exists, could the
Agenttool result reliably surface (or the
harness detect) when a spawned agent's commands executed outside its
assigned worktree, rather than relying on the agent's own self-report?
Happy to provide more detail (this was reconstructed from git reflog and
per-worktree branch/HEAD inspection after the fact, not captured live with
tracing) if useful.
3 Comments
Your forensic breakdown is convincing, and it lines up with a race where the agent's first command(s) run before its cwd has actually switched into the new worktree — so
git branch -m/ the first commit land on whatever the parent session had checked out. The parent reflog showing N sequentialgit branch -m(one per concurrent agent, each overwriting the last) is the signature. Two things help while this is unfixed: a guard the agent runs before any git mutation, and how to detect and recover damage that already landed on the parent.Guard: make the first action prove it's in its own worktree
A worktree's identity is cheap to check and distinct from the parent's — I verified locally that a child worktree reports its own
git rev-parse --show-toplevel(its own path, not the parent's) and its own branch (child-branch, not the parent'smaster). So gate the first git-mutating command on that:If the dispatch prompt doesn't know the exact worktree path, the discriminator that always holds is that the isolated worktree starts on the placeholder branch
worktree-agent-<id>: assert the current branch is NOT the parent's principal branch before renaming — ifgit branch --show-currentcomes back as the parent's branch, the race hit and you must not mutate.Don't trust the self-report footer — trust the worktree's own log
The most dangerous part of what you saw is that the agent whose entire commit landed on the parent still emitted a correct-looking
worktreePath:/worktreeBranch:footer. That's the classic "isolation wearing the face of success." Verify against ground truth after each batch, not the footer:Recovering damage already on the parent
Nothing is lost — it's just on the wrong branch. The stray rename/commit is in the parent's reflog; move it where it belongs and restore the parent:
Real fix is on the harness side: don't run the agent's first command until its cwd is confirmed switched into the new worktree (close the race window), and derive the self-report footer from the actual worktree state rather than from intent.
(Honesty note: I verified the guard's basis — a child worktree's toplevel and branch are distinct from the parent and reliable to check — but I did not reproduce the concurrent race itself; it's timing-dependent and needs the Agent dispatch harness. The guard holds regardless, because it checks ground truth before mutating.)
</content>
Fixed in 2.1.203 — changelog: "Fixed worktree-isolated subagents sometimes running shell commands in the parent checkout instead of their own worktree" (https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md). Closing — reply to reopen if it still happens on the latest version.
🤖 Generated with Claude Code
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.