When Claude Code Actually Reads AGENTS.md: Why I Still Can't Delete CLAUDE.md
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.
| Case | Layout | Question |
|---|---|---|
| A | AGENTS.md only | Does the fallback fire? |
| B | Parent has CLAUDE.md; child has only AGENTS.md; start in child | What happens if I delete a subproject's CLAUDE.md? |
| C | AGENTS.md only, with one @ import inside cwd and one outside | How are imports handled on the fallback path? |
| D | Parent has CLAUDE.md; child has one-line CLAUDE.md plus AGENTS.md with an outside import | Control: the current setup |
I did not rely on the model's answer. Two harder sources of evidence:
- the
--debuglog from the built-incc-plugin-agents-mdplugin, which writesno 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
| Case | Markers loaded | Conclusion |
|---|---|---|
| A | MARKER_A_AGENTS | Fallback works; the log shows AGENTS.md loaded |
| B | only the parent's MARKER_B_PARENT_CLAUDE | The child's AGENTS.md is skipped entirely; the log has no ancestor scan at all |
| C | MARKER_C_AGENTS, MARKER_C_IMPORT_INSIDE | The inside import expands; the outside import is dropped silently |
| D | MARKER_D_PARENT_CLAUDE, MARKER_D_CHILD_AGENTS | The 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.