[Bug] Plan agent uses main branch path instead of git worktree directory

Open 💬 16 comments Opened Nov 8, 2025 by davemurphysf

Bug Description
I understand the issue - when you're working in a git worktree like
/Users/dave/code/shingleai/.conductor/monaco-v1, the Plan agent is
incorrectly trying to access files from the main branch location at
~/code/shingleai instead of your current working directory.

This is a bug in how the Plan agent handles working directory context when
invoked. The Plan agent should inherit and respect the working directory
from the parent session, but it appears to be either:

  1. Not receiving the correct working directory context
  2. Making incorrect assumptions about the repository root
  3. Resolving paths relative to the main git directory instead of the

worktree

Recommended Actions

Report this issue:
You can report this at https://github.com/anthropics/claude-code/issues
with details like:

  • You're using git worktrees
  • Current working directory:

/Users/dave/code/shingleai/.conductor/monaco-v1

  • Plan agent incorrectly tries to access: ~/code/shingleai
  • Expected: Plan agent should use the current working directory

Temporary Workaround

In the meantime, when the Plan agent gives you a plan, you may need to:

  • Review the plan carefully for any incorrect path assumptions
  • Manually correct paths when executing the plan
  • Or avoid using plan mode for tasks that require precise file location

awareness

Environment Info

  • Platform: darwin
  • Terminal: iTerm.app
  • Version: 2.0.36
  • Feedback ID:

Errors

[{"error":"AxiosError: Request failed with status code 403\n    at WT (file:///Users/dave/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js:51:1136)\n    at Unzip.<anonymous> (file:///Users/dave/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js:56:9845)\n    at Unzip.emit (node:events:520:35)\n    at Unzip.emit (node:domain:489:12)\n    at endReadableNT (node:internal/streams/readable:1701:12)\n    at process.processTicksAndRejections (node:internal/process/task_queues:90:21)\n    at sGA.request (file:///Users/dave/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js:58:2129)\n    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n    at async ft2 (file:///Users/dave/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js:3771:7832)","timestamp":"2025-11-08T02:08:15.925Z"},{"error":"AxiosError: Request failed with status code 403\n    at WT (file:///Users/dave/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js:51:1136)\n    at Unzip.<anonymous> (file:///Users/dave/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js:56:9845)\n    at Unzip.emit (node:events:520:35)\n    at Unzip.emit (node:domain:489:12)\n    at endReadableNT (node:internal/streams/readable:1701:12)\n    at process.processTicksAndRejections (node:internal/process/task_queues:90:21)\n    at sGA.request (file:///Users/dave/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js:58:2129)\n    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)\n    at async _f8 (file:///Users/dave/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js:868:467)\n    at async Promise.all (index 0)\n    at async file:///Users/dave/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js:854:41014","timestamp":"2025-11-08T02:17:12.093Z"}]

View original on GitHub ↗

16 Comments

github-actions[bot] · 7 months ago

This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

joebates25 · 6 months ago

This still occurs in 2.1 and also with the Explore agent. I'm not really sure how I can leverage worktrees to have multiple Claude instances work in parallel if they won't actually stay within their own worktree...

trobanga · 5 months ago

I'm experiencing it, too.

Anfed-2030 · 5 months ago

Same issue here on macOS. I can confirm the root cause:

Claude Code follows git rev-parse --git-common-dir (which returns the main repo's .git) instead of git rev-parse --show-toplevel (which correctly returns the worktree path).

From inside the worktree:

| Command | Output |
|---------|--------|
| git rev-parse --show-toplevel | /path/to/my-worktree ✅ |
| git rev-parse --git-common-dir | /path/to/main-repo/.git ❌ |

The worktree's .git file contains gitdir: /path/to/main-repo/.git/worktrees/..., and Claude Code follows that pointer back to the main repo to resolve the project root.

Result: Even when launching claude from inside the worktree directory, the session environment shows Working directory: /path/to/main-repo. Every Bash call resets to the main repo. Every file edit targets the main repo. cd into the worktree doesn't persist.

This completely breaks worktree-based isolation. In my case it led to accidental edits on the production branch and reverted work.

The fix: Use --show-toplevel instead of --git-common-dir when resolving the project root. --show-toplevel correctly respects worktrees.

  • macOS Darwin 25.2.0
  • Claude Code latest (Feb 2026)
  • Anthropic API (Opus 4.5)
mtnptrsn · 4 months ago

Also having this issue.

TeddyHarnat · 4 months ago

Also having this issue

marijnbakker2 · 4 months ago

Still having this issue too, making worktrees in claude unreliable to use...

arjunven · 4 months ago

also having this

arjunven · 4 months ago

@Anfed-2030 is this something you used to fix this locally for you or are you suggesting this to the Claude Code team?

Update:
I think the answer is this is a Claude Code side change that needs to happen.

As a work around i'm trying the following in my claude.md

## Plan mode and branch/worktree context

Due to a [Claude Code bug](https://github.com/anthropics/claude-code/issues/11239), the working directory resets to the main repo root after plan mode exits (worktree `.git` files redirect project root resolution). To work around this:

- **When creating a plan on a non-`main` branch, embed the branch context into the plan** — add a `## Prerequisites` section at the **top** of the plan:
  - For **worktree branches** (e.g. `worktree-*`): include the absolute worktree path and a `cd` instruction. The worktree path follows `.claude/worktrees/<slug>/` where the slug is derived from the branch name (strip `worktree-` prefix).
    ```
    ## Prerequisites
    This plan targets worktree branch `worktree-<slug>`.
    **Before executing any steps**, `cd` to the worktree:
    `cd /absolute/path/to/.claude/worktrees/<slug>/`
    ```
  - For **regular feature branches** (e.g. `claude/*`): include the branch name and a checkout instruction.
    ```
    ## Prerequisites
    This plan targets branch `claude/<name>`.
    **Before executing any steps**, verify you are on this branch:
    `git checkout claude/<name>`
    ```
- **When executing a plan that has a Prerequisites section, follow it first** — before any code changes, `cd` to the worktree or `git checkout` the branch. If the current branch is `main` but the plan targets a different branch, do NOT proceed until on the correct branch.

Update 2:
Seems to work! My next plan after this had this at the top

Here is Claude's plan:
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
 MER-397: Address PR #534 review feedback

 Prerequisites

 This plan targets worktree branch worktree-mer-397-xxx-xxx-xxx.
 Before executing any steps, cd to the worktree:
 cd /Users/arjun/source/xxx/.claude/worktrees/mer-397-xxx-xxx-xxx/

As expected when clearing and executing the plan it landed back on main but did cd immediately to the worktree

``` shell
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

⏺ I'll start by reading the files in the worktree to understand the current state.

⏺ Bash(cd /Users/arjun/source/xxx/.claude/worktrees/mer-397-xxx-xxx-xxx/)
⎿  Done


Definitely very cursed and likely not 100% reliable buut lets you limp along until this bug is fixed.
ryotapoi · 4 months ago

Also seeing this on 2.1.74.

Additional note: The built-in /simplify skill seems to rely on git diff to locate the plan file alongside implementation changes. However, since the plan file is written to the main repo path (outside the worktree), git diff in the worktree never picks it up. As a result, /simplify can't cross-reference the plan with the implementation—it only sees the code changes.

(I haven't directly verified /simplify's internals, but the behavior matches this hypothesis.)

arjunven · 4 months ago

@bcherny this is a pretty big one mate. Surprised this is still open. Seeing a lot of dedupe bot running around tagging this but seems like it's not bubbling up at all?

At this point i'm hesitant to even submit bugs since it seems like they go into a void and never get addressed. CC has been accruing bugs lately. Do y'all have a plan for ranking severity / priority? The dedupe bot doesn't appear to be working and seems to just link many related issues together and then closing new bug reports without emphasizing the single representative ticket people should go upvote etc. This seems like a process failure.

sashatc · 2 months ago

suffering from this also with code-review:code-review skill subagents. Directed main agent to always include worktree path as mandatory into subagent's flow - works for some time or several PRs and then reverts back to this misbehavior. I even threatened to terminate the main if it allows this to reoccur, did not hold for long.

I notices that it most often happens when subagents are Haiku or Sonnet - less prompt-following models.

archodev · 1 month ago

This is preventing me from using /ultraplan

camhpj · 1 month ago

I have recently moved to using Claude in devcontainers. Has several advantages (mostly security related) but it inadvertently solved this issue (I give Claude full access to /workspace where I mount my git repo).

feliperoberto · 1 month ago

The custom sub agents also does the same, so spawning parallel sub agents will got the bad results, too.

lkiii · 1 month ago

I am experiencing the same issue. I have a framework where I use multiple subagents and I end up with bunch of random changes in the main dir, not the worktree

Workaround: PreToolUse hook that blocks (and auto-corrects) main-tree edits from worktree sessions

Until this is fixed, you can fully stop the silent main-tree edits with a PreToolUse hook. It only activates when the session cwd is under .claude/worktrees/, denies any Edit/Write/NotebookEdit targeting a file outside the worktree, and - when the bad path points into the main repo - echoes the equivalent worktree path back to the model so the agent self-corrects on the next attempt. Hooks also run inside subagents, which is exactly where this bug bites (subagents inherit a project root from git rev-parse --git-common-dir, i.e. the main repo).

.claude/hooks/guard-worktree.sh (chmod +x it):

#!/usr/bin/env bash
set -euo pipefail

input=$(cat)
cwd=$(jq -r '.cwd' <<<"$input")

# Only enforce inside worktree sessions (claude -w / --worktree)
case "$cwd" in
  */.claude/worktrees/*) ;;
  *) exit 0 ;;
esac

file=$(jq -r '.tool_input.file_path // .tool_input.notebook_path // empty' <<<"$input")
[ -z "$file" ] && exit 0

# Resolve relative paths against the session cwd, not the hook's cwd
case "$file" in
  /*) ;;
  *) file="$cwd/$file" ;;
esac
resolved=$(realpath -m "$file")
case "$resolved" in
  "$cwd"/*) exit 0 ;;
esac

# Main repo root = everything before /.claude/worktrees/<name>
main_root="${cwd%%/.claude/worktrees/*}"

suggestion=""
case "$resolved" in
  "$main_root"/*)
    rel="${resolved#"$main_root"/}"
    suggestion=" Use the worktree path instead: $cwd/$rel"
    ;;
esac

echo "Blocked: $resolved is outside the active worktree ($cwd). This session must only modify files inside the worktree.$suggestion" >&2
exit 2   # deny the tool call; stderr is fed back to the model

.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write|NotebookEdit",
        "hooks": [
          { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/guard-worktree.sh" }
        ]
      }
    ]
  }
}

Verified behavior:

| Scenario | Result |
|---|---|
| Main-repo absolute path from a worktree session | ❌ blocked, message suggests the corrected worktree path |
| ../../../ escape out of the worktree | ❌ blocked |
| Path inside the worktree (absolute or relative) | ✅ allowed |
| Edits in a normal (non-worktree) session | ✅ allowed, hook is a no-op |

In practice the suggestion line matters: the agent retries with the corrected path immediately instead of getting stuck.

Known gap: Bash-based file writes (sed -i, tee, git -C ..) aren't covered since arbitrary shell can't be reliably parsed - but agents do file changes via Edit/Write, so this catches the failure mode described in this issue. If your worktrees live somewhere other than .claude/worktrees/, adjust the two case patterns accordingly.