Worktree-isolated subagents load the project CLAUDE.md (and its @imports) twice; the only workaround exclude pattern that doesn't drop subfolder CLAUDE.md files is non-obvious

Status Fixed / completed
Reported on v2.1.284
Maintainer reply None cached
Activity 1 comment · opened Sep 29, 2026 · closed Sep 29, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (reproduced on 2.1.284, and on 2.1.282; the 2.1.283 and 2.1.284 changelogs contain no related fix)

What's Wrong?

A subagent dispatched with isolation: "worktree" loads the project's CLAUDE.md twice:

  1. At startup it loads <project>/CLAUDE.md (plus its @imports) from the parent project root.
  2. On its first file read inside its worktree, it loads the worktree's copy again as nested_memory attachments: <project>/.claude/worktrees/agent-<id>/CLAUDE.md, plus the worktree copy of every file that CLAUDE.md @imports.

The worktree is created inside the project (.claude/worktrees/), so the worktree's root CLAUDE.md looks like a subdirectory CLAUDE.md of the parent project.

  • Cost: it scales with CLAUDE.md size and dispatch volume. With a CLAUDE.md plus imports of about 100 KB, it adds roughly 25-30k tokens to every worktree subagent, and in our transcripts most worktree subagents carried the duplicate.
  • The two copies can differ. The startup copy comes from the parent checkout's working directory, while the worktree is created from the last-fetched origin/<default branch>. If the parent checkout is behind or has local edits, the subagent receives two different versions of its instructions, with no indication of which one applies.

What Should Happen?

A worktree subagent should load its project memory once. Either:

  • recognise the worktree's root CLAUDE.md (and its imports) as the project memory it already loaded, while still loading genuine subfolder CLAUDE.md files, or
  • root the subagent's memory in its worktree, so its CLAUDE.md matches the code it works on.

Error Messages/Logs

None; the duplicate shows up only in the subagent transcript.

Steps to Reproduce

  1. Create a fresh repo, with no .claude/ settings and no hooks:

``
git init -b main repro && cd repro
printf '# Tiny project\nMARKER-123: be concise.\n\n@docs/imp.md\n' > CLAUDE.md
mkdir -p docs sub src
echo 'IMPORT-MARKER: imported rules.' > docs/imp.md
printf '# Sub guide\nSUB-MARKER: sub rules.\n' > sub/CLAUDE.md
echo hello > src/a.txt && echo world > sub/b.txt
git add -A && git commit -m init
``

  1. Dispatch one worktree-isolated subagent. From the repo root, run this single shell command. It starts a headless Claude Code session and gives it the quoted prompt; that session then spawns the subagent, which runs in its own worktree under .claude/worktrees/ and does the file reads:

``
echo "Do not read files yourself. Spawn exactly ONE subagent with the Agent tool, subagent_type general-purpose, isolation worktree, and this prompt: 'Run pwd, then Read src/a.txt and then sub/b.txt using absolute paths inside your working directory. Reply with the path.'" | claude -p --output-format json --allowedTools Agent Bash Read
`
Interactive alternative: start
claude` in the repo root and paste the quoted prompt.

  1. Find the subagent's transcript. The JSON output contains session_id. The transcript is ~/.claude/projects/<project-dir>/<session_id>/subagents/agent-*.jsonl, where <project-dir> is the repo path with separators replaced by -.
  2. Check what was loaded. In that file:
  • <repo>/CLAUDE.md is loaded at startup (search for MARKER-123)
  • after the first Read, entries with "type": "nested_memory" appear for <repo>/.claude/worktrees/agent-<id>/CLAUDE.md and .../docs/imp.md, the duplicates
  • IMPORT-MARKER appears 4 times instead of 2.
  1. Repeat with each exclude. Create .claude/settings.local.json with each claudeMdExcludes value from the table below, e.g. {"claudeMdExcludes": ["**/.claude/worktrees/*/CLAUDE.md"]}, and re-run step 2. .claude/settings.local.json is local and uncommitted. Check whether a nested_memory entry for .../sub/CLAUDE.md appears (search for SUB-MARKER).

Results on 2.1.284:

| claudeMdExcludes | Duplicate root CLAUDE.md + imports | sub/CLAUDE.md loaded | IMPORT-MARKER count |
|---|---|---|---|
| none | yes: root CLAUDE.md and docs/imp.md loaded again from the worktree | yes | 4 |
| **/.claude/worktrees/** | no | no (lost) | 2 |
| **/.claude/worktrees/*/CLAUDE.md | no | yes | 2 |

Claude Model

Sonnet (the behaviour does not appear to be model-dependent)

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.284 (Claude Code); also reproduced on 2.1.282

Platform

Anthropic API

Operating System

Windows 11

Terminal/Shell

Git Bash / PowerShell, headless claude -p

Additional Information

  • Workaround, and its trap:
  • claudeMdExcludes: ["**/.claude/worktrees/*/CLAUDE.md"] in the parent project's local, uncommitted settings removes the duplicate root CLAUDE.md, and its @imports go with it. Subfolder CLAUDE.md files inside the worktree still load.
  • The more obvious **/.claude/worktrees/** also removes the duplicate, but it silently drops every subfolder CLAUDE.md inside the worktree. That is a real loss of scoped instructions, and nothing warns about it.
  • Either pattern must stay out of version control. Committed, it reaches every worktree, and a top-level session started inside a worktree then loads no root CLAUDE.md at all.
  • Path rules are unaffected by the exclude, because worktree subagents read .claude/rules/*.md from the parent project. However, paths: globs are matched relative to the parent root, so an anchored glob like src/**/*.ts doesn't match .claude/worktrees/agent-<id>/src/x.ts, while **/src/**/*.ts does. This is likely the same root cause: the subagent's memory and rules are rooted in the parent project, not its worktree.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗