| name | main-bash-cwd-persists-nested-worktree |
| description | Prevent and diagnose nested git worktrees created at the wrong filesystem path when
orchestrating parallel work from the main Claude Code agent. Use when (1) you ran
`git worktree add .claude/worktrees/<name> ...` from the main agent's Bash tool,
(2) `git worktree list` shows the new worktree at an unexpected nested path like
`.claude/worktrees/<previous-worktree>/.claude/worktrees/<name>` instead of the
intended top-level location, (3) a subagent dispatched to the intended path reports
"worktree path mismatch" or operates from a longer nested path. Root cause: the
main agent's Bash tool **persists cwd between calls** (per its docstring: "The
working directory persists between commands"). An earlier `cd /abs/path && cmd`
changes the main shell's cwd; a later `git worktree add <relative-path> ...`
resolves against that persisted cwd rather than the project root, silently creating
nested layouts. This is the **inverse** of the subagent variant
(subagent-bash-cd-wrong-worktree) — subagent shells reset per call, main shell
doesn't. **Also covers the sibling case (v1.1): from the project ROOT, a
`git worktree add ../<name> ...` escapes UP to the repo's PARENT dir (e.g.
`/Users/x/Documents/<name>`), OUTSIDE the `.claude/worktrees/` convention — and a
later Read/Edit/Write using the assumed `.claude/worktrees/<name>` absolute path
fails with a MISLEADING "file does not exist" (the file exists, the worktree is
just elsewhere).** **Also covers (v1.2): a drifted cwd makes `git diff A B -- <repo-relative-path>`
return EMPTY while `git diff A B --stat` (no pathspec) shows the same file as
changed — because pathspecs resolve relative to cwd but `--stat` reports against
the repo root. Tell: a pathspec-filtered git command comes back empty yet `--stat`
/ `git show <rev>:<path>` disagree → suspect cwd drift, not the commit/branch/range.**
|
| author | Claude Code |
| version | 1.2.0 |
| date | "2026-07-02T00:00:00.000Z" |
| disable-model-invocation | true |
Main-agent Bash cwd persistence → nested worktrees at wrong path
Problem
You're orchestrating multiple parallel-dispatch subagents, each in its own git worktree. From the main agent's Bash tool you do:
git worktree add .claude/worktrees/track-A origin/main -b feat/track-A
cd /path/to/repo/.claude/worktrees/track-A && grep -rn "foo" src/
git worktree add .claude/worktrees/track-B origin/main -b feat/track-B
You expect track-B at <repo>/.claude/worktrees/track-B. Instead git worktree list reports it at <repo>/.claude/worktrees/track-A/.claude/worktrees/track-B — nested inside the Track A worktree.
Branches, commits, and pushes still work (git resolves them via .git/worktrees/<name> metadata regardless of disk location), but:
- Dispatched subagents pointed at the intended path will report "worktree path mismatch."
- Cleanup (
git worktree remove .claude/worktrees/track-B) from the project root won't find it.
- Per-worktree caches, venvs, and uploads end up under the wrong parent directory.
Context / Trigger conditions
- Main agent runs more than one
git worktree add in the same session.
- Between worktree-add calls, the main agent ran a Bash command that included a
cd to a path other than the project root.
- The later
git worktree add uses a relative path (e.g., .claude/worktrees/<name>).
- Symptom:
git worktree list shows nested paths, OR a subagent given the intended path can't find its worktree, OR pwd inside a subagent reports a longer-than-expected path.
The Bash tool's own description says it: "The working directory persists between commands, but shell state does not." This is the opposite of subagent Bash, which resets cwd per call (see subagent-bash-cd-wrong-worktree).
Solution
Three reliable mitigations, in order of preference:
-
Always pass an absolute path to git worktree add from the main agent.
git worktree add /Users/<user>/Documents/the-handover-repo/.claude/worktrees/track-B origin/main -b feat/track-B
This is the cleanest fix and is robust against any cwd drift.
-
Reset cwd to project root in the same chained call before any git worktree add with a relative path:
cd /Users/<user>/Documents/the-handover-repo && git worktree add .claude/worktrees/track-B origin/main -b feat/track-B
-
Create ALL worktrees up-front in a single batch at the start of the session, before any other Bash commands that might cd.
When dispatching parallel subagent prompts, also bake an absolute-path verification step into each prompt:
First action: verify worktree path matches expectation.
cd /Users/<user>/Documents/the-handover-repo/.claude/worktrees/<name>
pwd # MUST end in <name>; STOP and report if it doesn't
git rev-parse --abbrev-ref HEAD # MUST be feat/<name>
Verification
After creating a worktree, immediately:
git worktree list | grep <name>
The reported path must NOT be nested under another worktree. If it is, before any subagent dispatch:
git worktree remove <wrong-nested-path>
git worktree add /abs/path/to/.claude/worktrees/<name> origin/main -b feat/<name>
Example
What went wrong (Session 15, the-handover-repo):
git worktree add .claude/worktrees/s15-lows-bundle origin/main -b feat/s15-lows-bundle
cd /Users/<user>/Documents/the-handover-repo/.claude/worktrees/s15-lows-bundle && grep "_JINJA_ENV" src/
git worktree add .claude/worktrees/s15-csv-upload origin/main -b feat/s15-csv-upload
Fix applied in that session: none mid-session (PRs all pushed correctly via branch refs). The lesson is to use absolute paths next time.
Variant (v1.1): ../<name> escapes UP to the repo parent, then a file-tool call "file does not exist"
A second, even-easier-to-hit shape — cwd was correct (the project root), the relative path itself was wrong:
cd /Users/x/Documents/myrepo
git worktree add -b docs/foo ../foo origin/main
tail ../foo/docs/file.md
The ../<name> reads like "a worktree beside the others" but .claude/worktrees/ is two levels down, so ../ goes the wrong direction entirely. The trap is the downstream symptom: the worktree was created fine and even tail in the same bash worked (cwd-relative), but the next file-tool call uses a hard-coded absolute path under .claude/worktrees/ and reports the file missing — pointing you at the file, not at the worktree's real location.
Guards (in addition to the absolute-path rule above):
- To match the convention, pass the full intended path, not
../: git worktree add .claude/worktrees/<name> <ref> (from the project root) or the absolute equivalent.
- Resolve the worktree's REAL path before constructing absolute paths for Read/Edit/Write:
git worktree list | grep <name>
Use that exact path — never an assumed .claude/worktrees/<name> — when the next tool call needs an absolute path.
- If you see a file-tool "file does not exist" right after a
git worktree add, suspect the worktree location before suspecting your file path.
Variant (v1.2): drifted cwd makes git diff -- <repo-relative-path> return EMPTY while --stat shows the change
Same root cause (main-shell cwd persisted into a subdir after an earlier cd), different — and very disorienting — symptom: git pathspecs are resolved relative to cwd, but --stat/--name-only without a pathspec report against the repo root. So the two disagree, and the file looks both changed and unchanged at once:
cd /repo/<analytics_pkg>/cloudrun/<dashboard_app> && python -m pytest ...
git show --stat HEAD | grep bq_queries
git diff HEAD~1 HEAD -- <analytics_pkg>/cloudrun/<dashboard_app>/bq_queries.py
git show HEAD:<analytics_pkg>/.../bq_queries.py | grep <symbol>
The tell is the contradiction: git show --stat / git diff A B --stat (no pathspec) lists the file as changed, but git diff A B -- <repo-relative-path> returns nothing, and git show HEAD:<path> (a <rev>:<path> object name, which is always repo-root-relative) shows the content fine. When a pathspec-filtered git command comes back empty but the unfiltered --stat disagrees, suspect cwd drift before suspecting the commit, the branch, a .gitattributes -diff driver, or a bad range.
Guards:
pwd when a pathspec-filtered git result surprises you — the harness's own "Shell cwd was reset to …" tool-result lines are reporting the drift, not just noise.
- Prefer a leading
cd /abs/repo/root && git diff … -- <path> for any pathspec-filtered inspection, OR use the cwd-independent git show <rev>:<path> / --stat (no pathspec) forms.
- A
cd inside a compound Bash command (cd X && cmd) still mutates the persistent cwd for every later call — it is not scoped to that one command.
Notes
- Branch and push behavior are NOT affected because git tracks worktrees by
.git/worktrees/<name> metadata, not by filesystem path. So this bug is silent — you only notice when a subagent reports a path mismatch or when you try to git worktree remove from the project root.
- Variant v1.2's pathspec trap is not worktree-specific — it bites in any repo the moment cwd drifts into a subdir — but the fix is identical (absolute paths / repo-root
cd / cwd-independent git forms), so it lives here with the other cwd-drift symptoms.
- This is a property of the Claude Code Bash tool specifically. Other tools (e.g., Edit, Write, Read) don't have a persistent cwd — they take absolute paths or resolve against the project root.
- The subagent variant (
subagent-bash-cd-wrong-worktree) describes the opposite failure mode: subagent shells reset cwd per call, so a cd followed by git commit in a separate Bash call commits to the parent repo's HEAD. Both are real, and the fix is the same: use absolute paths and verify with pwd before any state-changing command.
References
- Claude Code Bash tool docstring: "The working directory persists between commands, but shell state does not."
- Related skill: subagent-bash-cd-wrong-worktree — the inverse failure mode in subagent shells.
- Related skill: using-git-worktrees — general worktree workflow.