BuildingOctober 21, 2026

When Claude Code Actually Reads AGENTS.md: Why I Still Can't Delete CLAUDE.md

Tested with claude -p --debug on Claude Code 2.1.304: when any ancestor directory has a CLAUDE.md, a subproject's AGENTS.md is skipped entirely, and @ imports outside cwd are not loaded in non-interactive mode.

Since 2.1.277, Claude Code reads AGENTS.md directly when there is no CLAUDE.md. My projects serve both Codex and Claude Code, so every directory keeps a pair of entry files: AGENTS.md is the single source of truth, and CLAUDE.md holds one line, @AGENTS.md. The obvious question: can that one line go?

No. Here is the test.

Setup

In a temporary directory with no CLAUDE.md anywhere above it, I built four layouts. Each file carries a unique marker token such as MARKER_A_AGENTS. I then started a non-interactive session in each directory with claude -p --debug and checked which markers made it into context.

CaseLayoutQuestion
AAGENTS.md onlyDoes the fallback fire?
BParent has CLAUDE.md; child has only AGENTS.md; start in childWhat happens if I delete a subproject's CLAUDE.md?
CAGENTS.md only, with one @ import inside cwd and one outsideHow are imports handled on the fallback path?
DParent has CLAUDE.md; child has one-line CLAUDE.md plus AGENTS.md with an outside importControl: the current setup

I did not rely on the model's answer. Two harder sources of evidence:

  • the --debug log from the built-in cc-plugin-agents-md plugin, which writes no CLAUDE.md found; AGENTS.md loaded: <path> when it loads one;
  • the session transcript (projects/<cwd>/<session>.jsonl), which contains the instruction files actually injected. Count the markers.

The CLI's OAuth token happened to be expired, so the model never answered. That turned out to be useful: the instruction files were assembled and written to the transcript before the first API call. Loading does not depend on the model.

Results

CaseMarkers loadedConclusion
AMARKER_A_AGENTSFallback works; the log shows AGENTS.md loaded
Bonly the parent's MARKER_B_PARENT_CLAUDEThe child's AGENTS.md is skipped entirely; the log has no ancestor scan at all
CMARKER_C_AGENTS, MARKER_C_IMPORT_INSIDEThe inside import expands; the outside import is dropped silently
DMARKER_D_PARENT_CLAUDE, MARKER_D_CHILD_AGENTSThe paired entry works; the outside import is likewise not loaded

Case B is exactly what deleting a subproject's CLAUDE.md produces. If any ancestor still has a CLAUDE.md, Claude Code treats the whole tree as a Claude project and never looks for AGENTS.md. The subproject's identity, status line and stack imports vanish together, with no warning.

Mechanism

The binary shows the order of checks. The plugin first scans the ancestor chain for CLAUDE.md, .claude/CLAUDE.md or CLAUDE.local.md. If any exists it sets isClaudeProject and skips the AGENTS.md lookup. Only with a clean ancestor chain does it look for AGENTS.md and expand its @ imports.

That is why case B's log has no AGENTS.md ancestor scan: the first check short-circuits.

One thing the test did not separate

The outside imports in C and D both failed to load. I also tried writing hasClaudeMdExternalIncludesApproved: true into projects[<cwd>] in ~/.claude.json and re-running. Same result. So under non-interactive claude -p, both paths treat imports outside cwd the same way: not loaded. The documented approval prompt for imports reached via CLAUDE.md is interactive behavior, and this test did not cover it.

What it means for me

My workspace is a container repository with a CLAUDE.md at its root and dozens of subprojects, each its own Git repository. Every one of them matches case B. Delete any subproject's one-line CLAUDE.md and its AGENTS.md becomes invisible to Claude Code.

The 11-byte @AGENTS.md line stays. The fallback saves nothing and silently drops rules in two situations: the whole file when an ancestor has CLAUDE.md, and outside imports when none does.

Reproduce

mkdir -p /tmp/fb/B/child
printf 'MARKER_B_PARENT_CLAUDE present.\n' > /tmp/fb/B/CLAUDE.md
printf 'MARKER_B_CHILD_AGENTS present.\n' > /tmp/fb/B/child/AGENTS.md
cd /tmp/fb/B/child && claude -p --debug 'reply NONE' >/dev/null 2>&1
grep -c MARKER_B_CHILD_AGENTS "$(ls -t ~/.claude/projects/*fb-B-child/*.jsonl | head -1)"

0 is case B. Replace ~/.claude with your CLAUDE_CONFIG_DIR if you set one. Baseline: Claude Code 2.1.304, tested 2026-10-21.