Worktree-isolated subagents leak Edit/Write into parent checkout (Windows)

Resolved 💬 4 comments Opened May 10, 2026 by JBudgeME Closed Jun 11, 2026

Summary

When Agent({ isolation: "worktree", ... }) dispatches a subagent on Windows, the subagent's Edit / Write operations sometimes write to the parent checkout's files instead of the isolated worktree's files. The same pattern affects subagent-issued git operations — commits land on the parent's branch ref instead of the worktree's branch.

The PR on remote ends up correct because the subagent runs git push -u origin <branch>, which pushes the branch regardless of where it lives locally. But the parent's local state is silently corrupted: branch ref jumps forward, working tree gains modified/untracked files. Recovery for the user requires git reset --hard origin/<branch>.

Environment

  • Platform: Windows 11 Home 10.0.26200
  • Shell: PowerShell (also Bash via the Bash tool)
  • Claude Code: Opus 4.7 (1M context), claude-opus-4-7[1m]
  • Repo layout: monorepo with multiple isolated worktrees under .claude/worktrees/agent-*
  • Project env: CLAUDE_PROJECT_DIR set to repo root

Repro pattern (one session, today)

3 of 7 worktree-isolated subagent dispatches in one session leaked. All briefs used repo-relative paths (e.g., .claude/settings.json, .claude/hooks/foo.js). All used isolation: "worktree". All received explicit "do not push to master directly. PR only." instructions in the brief.

| Subagent | Symptom | Self-detected? |
|---|---|---|
| A | First Write hit parent's .claude/settings.json instead of worktree's. Caught via grep showing the worktree file unchanged. | Yes — recovered with git checkout -- then re-wrote to worktree path. |
| B | 8 commits landed on parent's master branch directly. Subagent also pushed the branch as origin/feat/<name> (PR is correct). Local master ref silently advanced. | No — caught later by controller diffing parent state. |
| C | Modified files + untracked files in parent's working tree (.claude/workflow/scripts/...) that the subagent created. | No — caught later. |

The other 4 dispatches (using the same controller pattern, same brief style) didn't leak. No obvious differentiator in brief content or task type.

Suspected root cause

Edit / Write tools may resolve relative or CLAUDE_PROJECT_DIR-rooted paths against the parent's project dir env var rather than the subagent's worktree cwd. A subagent's brief that says "edit .claude/settings.json" gets resolved to <parent CLAUDE_PROJECT_DIR>/.claude/settings.json instead of <worktree>/.claude/settings.json.

Subagent A's report (verbatim, after self-detection):

Initial Write inadvertently hit the parent repo's .claude/settings.json (not the worktree's). Caught via grep showing 10 gsd-* entries still present in the worktree file. Restored the parent's working copy via git checkout -- and re-wrote to the correct worktree path.

git -C <worktree-path> invocations from the subagent's Bash tool work correctly when the path is explicit. The leak appears to be specific to Edit / Write (and to git invocations without -C that inherit a cwd that's actually the parent).

Impact

  • Silent local corruption: parent branch advances without controller intent. Next push to master would push subagent work straight to master without going through the PR.
  • Destructive recovery: git reset --hard is the only practical recovery. If operator had uncommitted work in parent at the time, it's at risk.
  • Cascading confusion: a second subagent wave dispatched off a contaminated parent inherits the leak.

What might help

If the root cause is path resolution against the wrong CLAUDE_PROJECT_DIR:

  1. Edit / Write should resolve paths against the subagent's own cwd / worktree dir, not the parent's CLAUDE_PROJECT_DIR.
  2. When a subagent runs in isolation: "worktree", the tool runtime should override CLAUDE_PROJECT_DIR for that subagent to the worktree path before any tool invocations.
  3. Subagent's first invocation should fail-loud if cwd doesn't match the worktree the controller created.

If you'd like a more targeted repro, I can produce a single-session script with mock briefs and surface which dispatches leak. Happy to share full controller + brief content from today's session if helpful.

Workaround in the field

I shipped a controller-side guard at JBudgeME/BOOKREADER-REPO:

  • check-subagent-isolation.mjs snapshot / verify — snapshots parent git state before dispatch and detects drift after, exiting non-zero on leak
  • subagent-brief-preamble.md — verbatim block pasted into every Agent brief, has the subagent run cwd + git-dir + status checks before any write

Reduces blast radius. Doesn't fix the underlying path resolution.

Side note (separate, lower-priority)

While filing this issue, my repo's PreToolUse commit-format-conventional hook false-positived on gh issue create because the body content contained the literal string "git commit" inside a heredoc. The hook's \bgit\s+commit\b regex matches anywhere in the command, including inside string arguments. Not a Claude Code bug — my hook needs tightening — but worth flagging in case you've seen similar false-positive interactions with PreToolUse hooks parsing Bash commands. I worked around with --body-file.

View original on GitHub ↗

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