---
title: "When Claude Code Actually Reads AGENTS.md: Why I Still Can't Delete CLAUDE.md"
description: "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."
canonical_url: "https://carlwang.com/posts/claude-code-agents-md-fallback"
---

> Index of every page on this site: [llms.txt](https://carlwang.com/llms.txt)

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.

<table>
<thead>
  <tr>
    <th>
      Case
    </th>
    
    <th>
      Layout
    </th>
    
    <th>
      Question
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      A
    </td>
    
    <td>
      <code>
        AGENTS.md
      </code>
      
       only
    </td>
    
    <td>
      Does the fallback fire?
    </td>
  </tr>
  
  <tr>
    <td>
      B
    </td>
    
    <td>
      Parent has <code>
        CLAUDE.md
      </code>
      
      ; child has only <code>
        AGENTS.md
      </code>
      
      ; start in child
    </td>
    
    <td>
      What happens if I delete a subproject's <code>
        CLAUDE.md
      </code>
      
      ?
    </td>
  </tr>
  
  <tr>
    <td>
      C
    </td>
    
    <td>
      <code>
        AGENTS.md
      </code>
      
       only, with one <code>
        @
      </code>
      
       import inside cwd and one outside
    </td>
    
    <td>
      How are imports handled on the fallback path?
    </td>
  </tr>
  
  <tr>
    <td>
      D
    </td>
    
    <td>
      Parent has <code>
        CLAUDE.md
      </code>
      
      ; child has one-line <code>
        CLAUDE.md
      </code>
      
       plus <code>
        AGENTS.md
      </code>
      
       with an outside import
    </td>
    
    <td>
      Control: the current setup
    </td>
  </tr>
</tbody>
</table>

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

<table>
<thead>
  <tr>
    <th>
      Case
    </th>
    
    <th>
      Markers loaded
    </th>
    
    <th>
      Conclusion
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      A
    </td>
    
    <td>
      <code>
        MARKER_A_AGENTS
      </code>
    </td>
    
    <td>
      Fallback works; the log shows <code>
        AGENTS.md loaded
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      B
    </td>
    
    <td>
      only the parent's <code>
        MARKER_B_PARENT_CLAUDE
      </code>
    </td>
    
    <td>
      The child's <code>
        AGENTS.md
      </code>
      
       is <strong>
        skipped entirely
      </strong>
      
      ; the log has no ancestor scan at all
    </td>
  </tr>
  
  <tr>
    <td>
      C
    </td>
    
    <td>
      <code>
        MARKER_C_AGENTS
      </code>
      
      , <code>
        MARKER_C_IMPORT_INSIDE
      </code>
    </td>
    
    <td>
      The inside import expands; the outside import is dropped silently
    </td>
  </tr>
  
  <tr>
    <td>
      D
    </td>
    
    <td>
      <code>
        MARKER_D_PARENT_CLAUDE
      </code>
      
      , <code>
        MARKER_D_CHILD_AGENTS
      </code>
    </td>
    
    <td>
      The paired entry works; the outside import is likewise not loaded
    </td>
  </tr>
</tbody>
</table>

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

```bash
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.

## Sitemap

See the full [sitemap](https://carlwang.com/sitemap.md) for all pages.
