EnterWorktree / isolation: "worktree" creates nested worktrees when CWD drifts after context compaction
Description
When an orchestrator agent dispatches subagents with isolation: "worktree", context compaction can leave the orchestrator's CWD pointing inside a previous worktree path. Subsequent worktree dispatches then nest inside the previous worktree instead of being created at the repository root. This can go 3+ levels deep and, critically, can cause agents to bypass worktree isolation entirely and commit directly to the main branch.
Reproduction Steps
Path A: Context compaction mid-session
- Start a session in a git repository (e.g.,
/home/user/projects/myrepo/) - Dispatch a subagent with
isolation: "worktree"— creates.claude/worktrees/agent-XXXXXXXX/correctly - Continue working until context compaction triggers (autocompact or manual)
- After compaction, the
<env>block is reconstructed from current process state — CWD is now.claude/worktrees/agent-XXXXXXXX/ - Dispatch another subagent with
isolation: "worktree"— new worktree is created at.claude/worktrees/agent-XXXXXXXX/.claude/worktrees/agent-YYYYYYYY/(nested) - Repeat — nesting goes deeper with each compaction cycle
Path B: Session continuation after context limit
- Start a session, dispatch subagents with
isolation: "worktree" - Session hits context limit and continues into a new conversation
- The continued session's
<env>block shows the CWD as the worktree path from the previous session (e.g.,Primary working directory: /home/user/projects/myrepo/.claude/worktrees/agent-XXXXXXXX) - All subsequent worktree dispatches nest from that stale CWD
- Each retry or new dispatch nests deeper
Observed Behavior
git worktree list output from a real session:
/home/user/projects/myrepo develop
/home/user/projects/myrepo/.claude/worktrees/agent-aba5b87b/.claude/worktrees/agent-a1684db4 (nested level 2)
/home/user/projects/myrepo/.claude/worktrees/agent-aba5b87b/.claude/worktrees/agent-a1684db4/.claude/worktrees/agent-a643979b (nested level 3)
/home/user/projects/myrepo/.claude/worktrees/agent-aba5b87b/.claude/worktrees/agent-ae22c7e3 (nested level 2)
/home/user/projects/myrepo/.claude/worktrees/agent-ad348c0b (correct level 1)
The nesting tree:
agent-aba5b87b/ <- original worktree (cleaned up but dir remains)
.claude/worktrees/
agent-a1684db4/ <- first retry (nested level 2)
.claude/worktrees/
agent-a643979b/ <- second retry (nested level 3)
agent-ae22c7e3/ <- different agent, also nested
The session's <env> block at start showed Primary working directory: .../agent-aba5b87b, confirming the stale CWD was carried from a previous session continuation.
Safety Impact
This is not just a cosmetic issue. When nesting goes deep enough, worktree creation can fail silently, causing the agent to fall back to the current CWD — which may be checked out on develop or main.
Observed data loss scenario: A junior agent was dispatched with isolation: "worktree" from a double-nested CWD. The worktree creation failed silently. The agent fell back to the parent directory, which was checked out on develop, and committed directly to develop — bypassing the branch isolation and merge-review process entirely.
This defeats the entire purpose of worktree isolation — agents that should be on isolated branches end up with direct write access to protected branches. In a worst case, this could introduce broken code, conflicts, or security issues directly into a mainline branch with no review gate.
Root Cause
Two factors combine:
- CWD drifts into worktree paths and persists across compaction/continuation. Context compaction reconstructs the
<env>block from current process state, and session continuation carries the CWD from the previous session. In both cases, if the CWD was inside a worktree, it stays there — the orchestrator has no mechanism to detect or correct this.
EnterWorktreecreates worktrees relative to CWD. It does not verify that CWD is the actual repository root. If CWD is already inside a worktree, the new worktree nests inside it.
- Silent fallback on failure. When deeply nested worktree creation fails (e.g., path too long, git limitations), the agent silently falls back to the current directory instead of erroring out. This means the isolation guarantee is silently dropped.
Expected Behavior
EnterWorktree should resolve to the git repository root (via git rev-parse --show-toplevel, following worktree .git files back to the main repo) before creating a new worktree. Worktrees should always be created at <repo-root>/.claude/worktrees/<name>, regardless of the current CWD.
Additionally, EnterWorktree should detect if it is being invoked from inside an existing worktree and either:
- Automatically resolve to the main repository root, or
- Refuse with a clear error message
Suggested Fix
Before git worktree add, resolve the true repository root:
# Follow .git file symlinks back to the main repo
REPO_ROOT=$(git -C "$(git rev-parse --git-common-dir)" rev-parse --show-toplevel 2>/dev/null || git rev-parse --show-toplevel)
Then create the worktree at $REPO_ROOT/.claude/worktrees/<name> instead of $(pwd)/.claude/worktrees/<name>.
Related Issues
- #12748 — Feature request: add
cwdparameter to Task tool (would allow explicit root specification) - #27343 —
CLAUDE_PROJECT_DIRwrong in worktrees - #12885 — Working directory mismatch with worktrees
- #10105 — Claude confuses git worktree directories with main repository
- #9796 — Context compaction erases project-context instructions
- #19471 — CLAUDE.md instructions ignored after compaction
Environment
- Claude Code CLI
- Linux (WSL2)
- Git 2.43+
- Orchestrator pattern: parent agent dispatching multiple subagents with
isolation: "worktree"across a multi-hour session with multiple compaction cycles
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗