Worktree isolation silently disabled when lead CWD is stranded under .claude/worktrees/ (falls back to in-place edits)
Summary
When a lead session spawns isolation: worktree subagents, isolation intermittently does not engage: the subagent edits the live working copy (and can land commits on the wrong branch / wrong clone) instead of getting its own worktree. A full session restart reliably restores correct isolation. Root cause is a CWD-based short-circuit in the EnterWorktree path, not the base-ref logic.
Environment
- Claude Code v2.1.187 (macOS arm64)
- Repo uses git linked worktrees: a main clone plus one or more
git worktree addsiblings sharing one object store - main clone:
/repos/proj(the.gitlives here) - working session runs in a linked worktree:
/repos/proj.worktrees/wt1(branchfeature-branch) - Subagents spawned with
isolation: worktree(both via agent frontmatter and Agent-tool calls), orchestrated by a lead session that fans out multiple subagents
Expected behavior
A spawn requesting isolation: worktree either gets a fresh isolated worktree, or hard-errors. It should never silently fall back to editing the lead's working copy.
Actual behavior
Intermittently, the subagent result carries no worktreePath/worktreeBranch trailer and its edits/commits land in place — on the lead's working copy, which may be the main clone parked on an unrelated branch with its own uncommitted WIP. Successful spawns in the same session do produce the worktree trailer, so it's intermittent, not total. Restarting the session fixes it.
Root cause (diagnosed from the v2.1.187 binary + a live probe)
1. Worktree directory location is fine and by design. The worktree dir is built as join(<root>, ".claude", "worktrees"), where <root> derives from the parent of git rev-parse --git-common-dir. For any linked worktree, --git-common-dir returns the shared main .git, so all agent worktrees live under the main clone's .claude/worktrees/. A controlled isolation: worktree probe spawned from the linked worktree confirmed this is harmless: the worktree landed under the main clone but was correctly branched off the linked worktree's HEAD (baseRef: "head") and was genuinely isolated. So this is not the bug.
2. The real bug is a CWD short-circuit in EnterWorktree. The guard (paraphrasing the in-binary string) is: "…unless your cwd is already under .claude/worktrees/, in which case the working copy is edited directly."
Failure chain:
- An isolated spawn leaves the lead's CWD inside the worktree it just ran in.
- That worktree is later removed / orphaned (normal cleanup, or a discarded task), but the lead's CWD path is still lexically under
.claude/worktrees/. - The next
isolation: worktreespawn hits the guard → "cwd already under.claude/worktrees/" → isolation is skipped, and edits go to whatever the stranded CWD resolves to (main clone / wrong branch). - Session restart resets CWD to the repo root → guard no longer fires → isolation works again.
Accumulated stale agent-* worktrees enlarge the surface for steps 2–3, and cleanupStaleAgentWorktrees won't clear worktrees held by another clone/session sharing the object store.
Reproduction
- In a repo with at least one
git worktree addlinked worktree, start a Claude Code session inside the linked worktree. - Spawn an
isolation: worktreesubagent; let it run and return (lead CWD is now inside…/.claude/worktrees/agent-XXX). - Remove/orphan that agent worktree (e.g. discard the task /
git worktree remove) without the leadcd-ing back to the repo root. - Spawn another
isolation: worktreesubagent.
- Observed: second subagent edits in place; no
worktreePathtrailer. - Expected: a fresh isolated worktree, or a hard error.
Suggested fix
In the EnterWorktree path, when isolation is requested:
- Detect when the current CWD is under
.claude/worktrees/but that worktree no longer exists / is orphaned, and re-resolve to the repo root and create a fresh worktree rather than treating "cwd under.claude/worktrees/" as "already isolated." - If isolation genuinely cannot be established, hard-error instead of falling back to in-place edits — silent fallback is the most damaging part (commits land on unrelated branches / another clone's WIP).
Impact
- Subagent edits/commits land on the wrong branch or a sibling clone's working copy, including clobbering pre-existing uncommitted WIP in the main clone.
- Silent: callers checking only "did I get a worktree?" still see plausible results until they inspect git state across clones.
- Affects multi-worktree / multi-clone setups and any lead orchestrating multiple isolated subagents.
Workaround
cdback to the repo root after every isolated spawn; never let the lead's CWD sit under.claude/worktrees/.- Restart the session to reset CWD.
- Prune stale
agent-*worktrees regularly.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗