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 "work...
Scanned 9/6/2026
Install to Claude Code
npx -y skills add wan-huiyan/agent-traffic-control --skill main-bash-cwd-persists-nested-worktree --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Main Bash Cwd Persists Nested Worktree?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/wan-huiyan-main-bash-cwd-persists-nested-worktree)More formats (shields.io, HTML) on the badges page.
---
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-02
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:
```bash
git worktree add .claude/worktrees/track-A origin/main -b feat/track-A
# ... dispatch Track A subagent ...
# ... investigate codebase ...
cd /path/to/repo/.claude/worktrees/track-A && grep -rn "foo" src/ # persists cwd!
# ... time passes, you dispatch Track B ...
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:
1. **Always pass an absolute path to `git worktree add`** from the main agent.
```bash
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.
2. **Reset cwd to project root** in the same chained call before any `git worktree add` with a relative path:
```bash
cd /Users/<user>/Documents/the-handover-repo && git worktree add .claude/worktrees/track-B origin/main -b feat/track-B
```
3. **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:
```bash
git worktree list | grep <name>
```
The reported path must NOT be nested under another worktree. If it is, before any subagent dispatch:
```bash
# Move it to the correct location (requires admin; or just remove + re-add)
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):**
```bash
# Main agent at /Users/<user>/Documents/the-handover-repo (project root)
git worktree add .claude/worktrees/s15-lows-bundle origin/main -b feat/s15-lows-bundle
# → created at .../the-handover-repo/.claude/worktrees/s15-lows-bundle ✅
# Later, investigation:
cd /Users/<user>/Documents/the-handover-repo/.claude/worktrees/s15-lows-bundle && grep "_JINJA_ENV" src/
# → main shell cwd is now inside s15-lows-bundle worktree
# Even later, second worktree:
git worktree add .claude/worktrees/s15-csv-upload origin/main -b feat/s15-csv-upload
# → created at .../s15-lows-bundle/.claude/worktrees/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:
```bash
cd /Users/x/Documents/myrepo # at project root — cwd is fine
git worktree add -b docs/foo ../foo origin/main # ../ escapes to /Users/x/Documents/foo ❌
# intended .claude/worktrees/foo, but ../foo = the repo's PARENT dir
tail ../foo/docs/file.md # works HERE — same bash, cwd still repo root
# ... later, an Edit/Write/Read with the ASSUMED path:
# Edit /Users/x/Documents/myrepo/.claude/worktrees/foo/docs/file.md
# → "File does not exist" ← MISLEADING: the file exists at /Users/x/Documents/foo/...
```
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):**
1. 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.
2. **Resolve the worktree's REAL path before constructing absolute paths for Read/Edit/Write:**
```bash
git worktree list | grep <name> # the path column is the source of truth
```
Use that exact path — never an assumed `.claude/worktrees/<name>` — when the next tool call needs an absolute path.
3. 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:
```bash
# earlier in the session, cwd drifted into a subdir:
cd /repo/<analytics_pkg>/cloudrun/<dashboard_app> && python -m pytest ... # persists cwd
# later, trying to inspect a commit that DID touch bq_queries.py:
git show --stat HEAD | grep bq_queries # → "bq_queries.py | 62 ++++--" (file IS in the commit)
git diff HEAD~1 HEAD -- <analytics_pkg>/cloudrun/<dashboard_app>/bq_queries.py
# → EMPTY ❌ (pathspec resolved from cwd = .../<dashboard_app>/<analytics_pkg>/... which doesn't exist)
git show HEAD:<analytics_pkg>/.../bq_queries.py | grep <symbol> # → matches (object-name form is cwd-INDEPENDENT)
```
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:**
1. `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.
2. 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.
3. 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](../subagent-bash-cd-wrong-worktree/SKILL.md) — the inverse failure mode in subagent shells.
- Related skill: [using-git-worktrees](../using-git-worktrees/) — general worktree workflow.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!