Skip to content

AI CODING ASSISTANTS

Claude Code AGENTS.md: What Actually Reaches Context

We denied every file-reading tool and measured it. Claude Code agents.md support is not automatic discovery — an unimported AGENTS.md never reaches the model at all.

Claude Code agents.md support is not file discovery. On 2.1.273 we put a unique codeword inside AGENTS.md, denied every tool that can open a file, and asked a session to repeat it — it answered UNKNOWN, three runs in a row. The identical test with CLAUDE.md returned the codeword immediately. AGENTS.md reaches Claude Code through exactly one route, an @AGENTS.md import line, and without it the file is invisible no matter where you put it. The complete Claude Code guide covers how instruction files load; this is the measurement of which ones do.

Key takeaways

  • A project containing only AGENTS.md answered UNKNOWN when its own codeword was requested, with reading tools denied.
  • CLAUDE.md loaded on its own in the same harness, same prompt, same restrictions.
  • With both files present, the CLAUDE.md codeword won and the AGENTS.md codeword never appeared at all.
  • A one-line @AGENTS.md inside CLAUDE.md carried the AGENTS.md codeword through intact.
  • With tools enabled the same session answers correctly by grepping for the file — which is why this question is so widely answered wrong.

The claude code agents.md answer in one table

Four projects, one codeword each, one prompt, one build. The only difference between arms is which instruction files sit in the working directory.

Files in the projectAnswer returnedReached context
AGENTS.md onlyUNKNOWNNo
CLAUDE.md onlym8qd-3zplYes
Both, different codewordsw7ju-1cke (the CLAUDE.md one)CLAUDE.md only
AGENTS.md + CLAUDE.md holding @AGENTS.mdx5ta-8dmr (the AGENTS.md one)Yes, via the import

Row three is the one that matters in practice. Dropping an AGENTS.md into a repository that already has a CLAUDE.md feels like adding a second instruction source. It adds nothing. The file sits there, committed, reviewed in pull requests, and never once reaches the model.

How we measured it

The hard part of this question is not running a session — it is stopping the session from cheating. A Claude Code agent with Read, Grep, Glob and Bash available will find an instruction file whether or not the harness loaded it, and then it looks like discovery.

So every file-reading tool was denied. The prompt has one legal route to the codeword: auto-loaded instructions.

Terminal
claude -p "Reply with the project codeword and nothing else. If no codeword is in your instructions, reply UNKNOWN." \
  --output-format json \
  --disallowedTools Bash Read Grep Glob Task Agent Edit Write WebSearch WebFetch NotebookEdit Skill

Each arm is a fresh empty directory holding one or two files. The codewords are unguessable strings — k4rn-9twx, m8qd-3zpl, v2hs-6fbn, w7ju-1cke, x5ta-8dmr — so no arm can borrow another's answer and a plausible guess cannot pass.

Terminal
npm run check:agents-md

The committed check re-validates all thirteen guards against the recorded arms: that the reading tools were denied, that the five codewords are distinct, that the negative arm reproduced, and that the import arm returned the AGENTS.md value rather than the CLAUDE.md one.

Arm by arm, what reached the model

AGENTS.md alone returned UNKNOWN. One turn, no tool calls, no hedging. The file was at the repository root with a plain Project codeword: k4rn-9twx line in it — the canonical placement the AGENTS.md standard describes — and the model had never seen it.

CLAUDE.md alone returned m8qd-3zpl. Same directory shape, same prompt, same denied tools, one turn. This is the control that proves the method works: when a file is auto-loaded, a tool-less session can quote it.

Both files together returned w7ju-1cke. That is the CLAUDE.md codeword. The AGENTS.md codeword in that arm was v2hs-6fbn and it never appeared. There is no merge, no precedence contest, no second-place file. Anthropic's memory documentation describes CLAUDE.md as the file the CLI looks for, and the absence of any AGENTS.md fallback is visible here rather than inferred.

The import arm returned x5ta-8dmr. A CLAUDE.md whose entire contents were the string @AGENTS.md pulled the AGENTS.md codeword straight through.

Why a casual test says the opposite

Before the controlled arms, we ran the obvious version: AGENTS.md with a codeword, a plain claude -p asking for it, tools left on. It answered tp84-vmq2 and cited AGENTS.md:1. That looks exactly like proof of automatic discovery, and it is the test most people run.

The streamed transcript shows what actually happened.

stream-json, tool calls only
TEXT       "I'll look for the codeword in the working directory."
TOOL_USE   Bash    ls -la <project>
TOOL_USE   Grep    pattern: codeword, path: <project>
TOOL_RESULT        AGENTS.md:1:When asked for the project codeword, reply with exactly: tp84-vmq2
TEXT       "tp84-vmq2"

Three turns and two tool calls. The session did not know the codeword; it went and found it. That distinction decides whether your instructions are in force on every request or only when the agent happens to look — and the second one is not a configuration, it is a coincidence.

The one line that fixes it

Keep the rules in AGENTS.md where every other agent finds them, and spend one line of CLAUDE.md on the bridge.

CLAUDE.md
@AGENTS.md

That is the whole fix, and it is the arrangement our AGENTS.md versus CLAUDE.md comparison recommends. Both of those articles asserted the transclusion route from documentation; this is the run that confirms it and the negative control they were missing. Anything Claude-specific — subagents, skills, permission notes — goes underneath the import line in CLAUDE.md, and the shared contract stays vendor-neutral.

The alternative route, symlinking CLAUDE.md to AGENTS.md, still carries the Windows caveat documented in the open agent standard explainer: without Developer Mode, git checks the link out as a text file containing a path, and Claude Code loads the path string. We did not re-measure that here, and it is named as untested rather than repeated as fact.

Claude Code is also not alone in stepping over the file. Running the same probe shape against an installed Antigravity CLI on 2026-09-18 found it loaded no instruction file from four candidate paths, AGENTS.md at the workspace root included — so the file both vendors point at is one neither loads unprompted.

What /import is actually for

import is a real command — it is one of 86 slash commands the session init event lists, and it also exists as a shell subcommand.

Terminal
claude import --help
# → Import config from another AI coding agent into Claude Code
# → source      Which agent to import from (codex, gemini, cursor)

It migrates another agent's configuration into yours. It is not an instruction-file loader. Against a Cursor project fixture, adding an AGENTS.md changed the importer's reported item count by exactly zero. Treat /import as a one-time migration step when you arrive from Codex, Gemini CLI or Cursor, and treat @AGENTS.md as the thing that keeps working every session afterwards.

Common mistakes

  • Committing AGENTS.md next to an existing CLAUDE.md and assuming both apply. It is tempting because both files are obviously instruction files. The symptom is silent: rules get ignored with no warning anywhere. The fix is the import line.
  • Testing discovery with tools enabled. The agent finds the file and you conclude it was loaded. Deny the reading tools, or ask something the file alone can answer and watch for a tool call.
  • Duplicating the rules into both files. Two copies drift within a sprint, and the one the model reads is the one you forgot to update. Import instead.
  • Expecting /import to wire up AGENTS.md. It migrates config from another agent; the source list is codex, gemini, cursor, and AGENTS.md is not in it.
  • Assuming a large AGENTS.md is free once imported. The import inlines the file, so it lands in context on every request exactly as CLAUDE.md content does. Our memory files census covers what that costs per turn.

What did not work

Our own first reading of the data was wrong. The tools-enabled probe answered the codeword and cited AGENTS.md:1, and the draft note said Claude Code auto-discovers AGENTS.md. The transcript overturned it within one command. That result is published above rather than quietly deleted, because it is the failure mode of every version of this test on the internet.

The memory_paths field looked like the structural answer and is not. The session init event carries a memory_paths object, which reads like a list of loaded instruction files. It reports only the auto-memory directory — nothing about CLAUDE.md or AGENTS.md — so the behavioural arms had to carry the whole argument.

The first arm's token accounting nearly became a finding. AGENTS.md-only reported 15,857 cache-creation tokens against roughly 3,600 for the other arms, which reads like a large file being loaded. It was prompt-cache warming on the first run of the batch. Two reruns in the same directory returned UNKNOWN at 825 and then 0 cache-creation tokens, so the spike is recorded as an ordering artifact rather than evidence.

One measurement was thrown away entirely. Running claude -p "/import cursor --dry-run" from Git Bash does not run the command: the shell rewrites the leading slash into C:/Program Files/Git/import, the session sees a file path, improvises by reading files by hand, and then reports that /import does not exist. It does exist. That trace was discarded and the shell subcommand used instead.

Best practices

  • Write the rules once, in AGENTS.md. Every other major agent discovers it, and one line brings Claude Code along.
  • Add @AGENTS.md as the first line of CLAUDE.md. Put Claude-specific instructions under it, not instead of it.
  • Verify with tools denied. A codeword and --disallowedTools turns a belief into a result in one command.
  • Do not mirror content between the two files. The import costs nothing and cannot drift.
  • Re-check after a CLI upgrade. This behaviour is version-pinned to 2.1.273; npm run check:agents-md is the thirty-second version of this article's evidence.

Conclusion

If you run Claude Code alongside any other agent, keep AGENTS.md as the shared contract and add @AGENTS.md to the top of CLAUDE.md today — measured on 2.1.273, that single line is the difference between instructions that apply on every request and a committed file the model has never seen. Do not trust a test that leaves the reading tools on. Next, read the AGENTS.md versus CLAUDE.md comparison for how to split the two files once the bridge is in place.

Frequently asked questions

Does Claude Code read AGENTS.md automatically?
No. On Claude Code 2.1.273, a project containing only AGENTS.md answered UNKNOWN when asked for a codeword written in that file, with every file-reading tool denied. The same test with CLAUDE.md returned the codeword. AGENTS.md is not auto-discovered; it has to be imported.
How do I make Claude Code use AGENTS.md?
Put a single line reading @AGENTS.md in your CLAUDE.md at the repository root. In our test that carried the AGENTS.md codeword into context unchanged, so the file becomes a live instruction source without duplicating a word of it.
If both CLAUDE.md and AGENTS.md exist, which one wins?
CLAUDE.md, and AGENTS.md does not merely lose — it is absent. Our arm with both files and a different codeword in each returned the CLAUDE.md codeword and never produced the AGENTS.md one. Adding AGENTS.md beside CLAUDE.md changes nothing without an import line.
Why did Claude Code quote my AGENTS.md if it does not read it?
Because it searched for it. With tools enabled, our session ran ls and grep, found the file and answered correctly, citing AGENTS.md:1. Reading a file on demand is not the same as loading it at session start, and only the second one is reliable.
Does the /import command import AGENTS.md?
No, and whether it even sees the file depends on the source. Adding AGENTS.md to a Cursor project changed the importer's item count by zero; naming codex instead counted a lone AGENTS.md as one project-level item, measured 2026-09-17. Project items are held back from non-interactive import either way, so /import remains a migration command rather than an instruction-file loader.

Muhammad Kashif

Founder and editor of Devventa, covering AI coding assistants, Next.js and the modern AI development stack.