Worktree isolation silently disabled when lead CWD is stranded under .claude/worktrees/ (falls back to in-place edits)

Open 💬 2 comments Opened Jun 23, 2026 by gavin-reve

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 add siblings sharing one object store
  • main clone: /repos/proj (the .git lives here)
  • working session runs in a linked worktree: /repos/proj.worktrees/wt1 (branch feature-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:

  1. An isolated spawn leaves the lead's CWD inside the worktree it just ran in.
  2. That worktree is later removed / orphaned (normal cleanup, or a discarded task), but the lead's CWD path is still lexically under .claude/worktrees/.
  3. The next isolation: worktree spawn 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).
  4. 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

  1. In a repo with at least one git worktree add linked worktree, start a Claude Code session inside the linked worktree.
  2. Spawn an isolation: worktree subagent; let it run and return (lead CWD is now inside …/.claude/worktrees/agent-XXX).
  3. Remove/orphan that agent worktree (e.g. discard the task / git worktree remove) without the lead cd-ing back to the repo root.
  4. Spawn another isolation: worktree subagent.
  • Observed: second subagent edits in place; no worktreePath trailer.
  • 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

  • cd back 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.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗