CLAUDE.md in the directory above a git worktree is not loaded when that directory holds the worktree's repository

Status Open
Reported on v2.1.266
Maintainer reply None cached
Activity 0 comments · opened Sep 9, 2026

Summary

A session started inside a git worktree does not load the CLAUDE.md in the directory directly above it, when that directory is the one holding the worktree's own repository. Every CLAUDE.md above that point loads normally, and the same parent hands its CLAUDE.md down without trouble to a child that is not a worktree of it. The docs say every ancestor directory is read, so this looks unintended.

Reproduced on 2.1.266 and 2.1.251, macOS 15 (Darwin 25.6.0), in both -p (print) mode and a normal interactive session.

What the docs say

From Manage Claude's memory:

Claude Code reads memories recursively: starting in the current working directory, it recurses up to (but not including) the root directory / and reads any CLAUDE.md or CLAUDE.local.md files it finds.

Repro

#!/bin/bash
set -e
R=/tmp/cc-worktree-claudemd
rm -rf "$R"; mkdir -p "$R"

# CASE D — parent holds a bare repository; child is a WORKTREE of that repository
mkdir -p "$R/fleet"
git init --bare -q "$R/fleet/.git"
printf 'The parent word is zorb-parent-WORKTREE.\n' > "$R/fleet/CLAUDE.md"
git --git-dir="$R/fleet/.git" worktree add -q "$R/fleet/child" 2>/dev/null || \
  git --git-dir="$R/fleet/.git" worktree add --orphan -b child "$R/fleet/child"
printf 'The child word is zorb-child-D.\n' > "$R/fleet/child/CLAUDE.md"

# CASE C — parent holds a bare repository; child is a PLAIN directory (the control)
mkdir -p "$R/plain/child"
git init --bare -q "$R/plain/.git"
printf 'The parent word is zorb-parent-PLAIN.\n' > "$R/plain/CLAUDE.md"
printf 'The child word is zorb-child-C.\n' > "$R/plain/child/CLAUDE.md"

Q='List the full path of every CLAUDE.md loaded into your context, then say whether the exact string "zorb-parent" appears anywhere in your context. Two short lines.'
echo "--- case D: worktree child"; ( cd "$R/fleet/child" && claude -p --model haiku "$Q" < /dev/null )
echo "--- case C: plain child (control)"; ( cd "$R/plain/child" && claude -p --model haiku "$Q" < /dev/null )

Actual output

Case D — the parent CLAUDE.md is absent:

CLAUDE.md files loaded:
- /Users/david/.claude/CLAUDE.md
- /private/tmp/cc-worktree-claudemd/fleet/child/CLAUDE.md

The exact string "zorb-parent" does not appear anywhere in my context.

Case C, same run, identical parent shape, child is a plain directory instead of a worktree — the parent CLAUDE.md loads:

CLAUDE.md files:
- /Users/david/.claude/CLAUDE.md
- /private/tmp/cc-worktree-claudemd/plain/CLAUDE.md
- /private/tmp/cc-worktree-claudemd/plain/child/CLAUDE.md

The string "zorb-parent" appears in my context: Yes (in .../plain/CLAUDE.md, as "zorb-parent-PLAIN")

Expected

Case D loads fleet/CLAUDE.md as well as fleet/child/CLAUDE.md, the same way case C loads plain/CLAUDE.md.

Isolating the variable

Six fixtures, one variable changed at a time. Only row D fails, and the two rows that separate the candidate explanations are C and F:

| Parent directory | Child directory | Parent's CLAUDE.md loaded? |
|---|---|---|
| plain, no git | plain directory | yes |
| plain, no git | its own ordinary repository | yes |
| holds a bare repository | plain directory | yes |
| holds a bare repository | worktree of that repository | no |
| plain, no git | worktree of a repository elsewhere | yes |
| holds a bare repository | worktree of a different repository | yes |

So it is neither "a bare repository in the parent" nor "the child is a worktree" on its own. The condition is the specific pairing: the child is a worktree of the repository the parent directory holds. (Our first pass concluded it was the bare repository and was wrong, because that fixture set had no row 3 and no row 6.)

Neither documented location arrives

Both <parent>/CLAUDE.md and <parent>/.claude/CLAUDE.md were tested in the failing shape. Neither reaches the worktree. And no fixture used a symbolic link anywhere, so this is not about link resolution.

Notes on method

Each result came from a freshly started session, since a session reads its memory files once at startup. Each child CLAUDE.md carries its own unique word so the child's "yes" proves the probe works in the same breath as the parent's "no". /context cannot settle it — it reports "Memory files" as a single total, and at this file size the difference rounds away.

Not a recent regression, and not an editor integration

  • Same result on 2.1.251, the oldest build still on this machine, and the same 2.1.251 binary loads the parent file correctly in case C. So whatever causes it predates 2.1.251.
  • Every probe was a plain claude from a shell — no VS Code extension in the path.

Possibly related, not the same

  • #23565 — memory files loaded twice in a worktree (parent repo path and worktree path). Opposite symptom, possibly the same path-resolution code.
  • #39920 — auto-memory directory of a manually created worktree resolves to the main worktree's path.
  • #27994 — closed as duplicate; reports that in this shape the project root resolves to the directory holding the bare repository rather than to the worktree.

Why it matters

This is the standard layout for parallel worktrees: one directory holds the repository, every checkout is a sibling inside it. Shared instructions naturally belong in that one directory, and it is the exact directory that gets skipped — so the file sits one level above every session that needs it and reaches none of them. The workaround is an @-import in each worktree's own CLAUDE.md. It works, but it has to be repeated per worktree, and because the imported file is tracked, each worktree reads its own branch's copy — so a change to shared instructions arrives only when each branch next catches up. Across one repository here with 16 worktrees, a corrected shared instruction sat on the shared branch while 15 worktrees still read the old text, some of them 16 commits behind. The one directory whose copy is always current is the directory that gets skipped.

View original on GitHub ↗