The junior opens the repo root. AGENTS.md is there. Codex already reads it. Copilot already reads it. They added Claude Code last week. The agent still ships a Laravel migration without the test command they wrote in that file. Standup calls it a model miss.
I stop the run there. A present AGENTS.md is not the project instructions while CLAUDE.md exists. Default load is the Claude files only when CLAUDE.md or CLAUDE.local.md sits in the working directory or above it. The shared file stays on disk. The session never treats it as the brief.
Official memory docs put that in one table. An AGENTS.md with no Claude file in the tree loads. An AGENTS.md next to a CLAUDE.md or CLAUDE.local.md does not. Change the mix under Project instructions in /config. [Source: https://code.claude.com/docs/en/memory]
I already refused to treat ubuntu-latest as a runner image I already tested in Ubuntu-latest Is Not a Runner Image You Already Tested. I already refused to treat a missing Wrangler previews block as production bindings in A Missing Previews Block Is Not a License to Reuse Production Bindings. This post is the same desk rule for an instruction file. Print the load line. Open /config. Name who owns the file Claude actually read.
The question is not whether AGENTS.md exists on disk. The question is whether the named owner can prove which file this session loaded.

The file that looks loaded
Juniors treat a repo-root markdown file the way they treat a README. If the name matches the tool, the tool must have read it. AGENTS.md is the shared name. The file is committed. The PR description says “agent instructions updated.” The session still ignores the test command.
That miss has two jobs, and they collide on a desk that already has a Claude file.
- Shared brief. Other coding agents read
AGENTS.md. The team wants one file. - Claude brief. Claude Code still counts
CLAUDE.md,.claude/CLAUDE.md, andCLAUDE.local.mdfirst. Those files win the default fallback.
Official docs say Claude can read AGENTS.md as project instructions so a repository already set up for other agents works without adding a CLAUDE.md, an import, or a setting. That sentence is the empty-tree case. It is not the case where a Claude file already exists. [Source: https://code.claude.com/docs/en/memory]
If you only ls the root and see AGENTS.md, you will file the model. You will not file the load order.
I do not invent a fake overnight outage. I use the public contract. The GitHub release that added the fallback says: in a project with no CLAUDE.md, Claude Code reads AGENTS.md instead; change it under “Project instructions” in /config. The same bullet says the fallback is not yet on Bedrock, Vertex, or Foundry. [Source: https://github.com/anthropics/claude-code/releases/tag/v2.1.277] [Source: https://code.claude.com/docs/en/changelog]
What Claude actually reads by default
I do not invent a merge. Official memory docs give three rows.
| Your repository has | Claude reads |
|---|---|
AGENTS.md, and no CLAUDE.md or CLAUDE.local.md in the working directory or above it | Your AGENTS.md |
AGENTS.md and a CLAUDE.md or CLAUDE.local.md in the working directory or above it | Your CLAUDE.md files only |
A CLAUDE.md that already imports AGENTS.md | Your CLAUDE.md, with AGENTS.md included through the import |
[Source: https://code.claude.com/docs/en/memory]
That middle row is the ticket on this desk. Most Laravel plus Vue repos already have a CLAUDE.md from last year’s /init. The junior then adds AGENTS.md so Codex and Copilot share one file. Default Claude Code still reads the Claude files only.
Files that count, so Claude reads them instead of AGENTS.md:
CLAUDE.md.claude/CLAUDE.mdCLAUDE.local.md
in the working directory or any directory above it.
Files that do not count, and keep loading alongside AGENTS.md when the fallback fires:
~/.claude/CLAUDE.md- the organization’s managed
CLAUDE.md .claude/rules/files
[Source: https://code.claude.com/docs/en/memory]
When none of the counting files exist, an interactive session prints a line such as no CLAUDE.md found; AGENTS.md loaded: /home/you/repo/AGENTS.md. That line is the artifact. A missing line is not “it must have loaded because the file is in git.”
Subdirectory AGENTS.md files load later, when Claude opens a file there with the Read tool and that subdirectory has none of the three Claude files of its own. AGENTS.local.md, AGENTS.override.md, and anything under .agents/ are not read. [Source: https://code.claude.com/docs/en/memory]
Pins are evidence, not the hook
AGENTS.md load needs Claude Code at or after the 18 September 2026 GitHub release that named the fallback. This morning’s npm registry, 20 September 2026: @anthropic-ai/claude-code latest and next are 2.1.278 (published 19 September 2026). stable is still 2.1.267 (published 9 September 2026). Do not treat stable as the field. Do not put those numbers in the title. Changelog notes for 2.1.278 are an auto-mode classifier change. That is a different ticket. [Source: https://github.com/anthropics/claude-code/releases/tag/v2.1.277] [Source: https://code.claude.com/docs/en/changelog] [Source: https://www.npmjs.com/package/@anthropic-ai/claude-code]The local file that steals the fallback
The trap I see on review is not the committed CLAUDE.md. It is CLAUDE.local.md.
Official docs say that file is for private per-project preferences. It loads alongside CLAUDE.md. Add it to .gitignore. Because it counts, adding one to keep your own uncommitted instructions in a project that relies on AGENTS.md stops Claude from reading AGENTS.md for you. [Source: https://code.claude.com/docs/en/memory]
The junior did the “right” thing. They gitignored a local file so personal sandbox URLs never hit the remote. The shared AGENTS.md still sits at the root. Codex still reads it. Claude Code on that laptop does not.
To keep CLAUDE.local.md and still have Claude read AGENTS.md, set Project instructions to claude-md-and-agents-md. Do not delete the local file in panic and call that a model fix. [Source: https://code.claude.com/docs/en/memory]
A user-level ~/.claude/CLAUDE.md does not steal the fallback. An org managed file does not steal the fallback. A .claude/rules/ file does not steal the fallback. Those three still load. They do not count as “a Claude file exists, skip AGENTS.md.” Mix those facts on a ticket and you will “fix” the wrong layer.

/config is the screenshot
I do not guess the mix from the repo tree. Official docs say: type /config in a Claude Code session, then set Project instructions.
| Value | What Claude reads |
|---|---|
claude-md-or-agents-md | Claude files, or AGENTS.md when no CLAUDE.md or CLAUDE.local.md is in the working directory or above it. This is the default. |
claude-md-and-agents-md | Both. Each directory’s Claude files first, then its AGENTS.md. An AGENTS.md already imported or symlinked is not read twice. |
claude-md | Claude files only. |
managed-only | Only the organization’s managed CLAUDE.md and auto memory at launch. Project, local, and user Claude files, .claude/rules/, and every AGENTS.md are left out of that launch set. |
[Source: https://code.claude.com/docs/en/memory]
You can also set the value in a settings file under the built-in agents-md plugin ID in pluginConfigs. Official docs put that in ~/.claude/settings.json, a --settings file, or managed settings. Claude Code ignores it in project and local settings files. The change applies from the next message you send and in every new session. [Source: https://code.claude.com/docs/en/memory]
1{
2 "pluginConfigs": {
3 "agents-md@builtin": {
4 "options": {
5 "instructionFiles": "claude-md-and-agents-md"
6 }
7 }
8 }
9}
That JSON is the user or managed settings shape from the public docs. It is not a project-root file you commit and expect every clone to honor. If the junior drops it in .claude/settings.json inside the app, the setting does not apply. File that as a settings-layer miss, not a plugin bug.
/memory lists CLAUDE.md and CLAUDE.local.md. An AGENTS.md loaded through the setting is not listed there. Confirm with the AGENTS.md loaded line under the default value, or ask Claude what its project instructions say. InstructionsLoaded hooks fire for Claude files. They do not fire for an AGENTS.md loaded through the setting. They do fire for an AGENTS.md that a CLAUDE.md imports or symlinks to. [Source: https://code.claude.com/docs/en/memory]

Sessions that never load AGENTS.md
Some sessions never show Project instructions in /config. Official docs list them. Claude reads Claude files only:
- The installed Claude Code is older than the release that added the fallback.
- The session does not fetch feature flags from Anthropic — Amazon Bedrock, another third-party provider, or telemetry disabled. The env-vars page has the full list.
- It is the first session after you install or upgrade to a version with
AGENTS.mdsupport. Claude readsAGENTS.mdfrom the next session on. - You or your organization set
disableAllHooksorallowManagedHooksOnly, or you disabled the built-inagents-mdplugin in/plugin.
[Source: https://code.claude.com/docs/en/memory]
The GitHub release bullet matches the provider row: not yet on Bedrock, Vertex, or Foundry. I do not turn that into a production claim on this desk. I treat it as a session class. If the host is on Bedrock, import @AGENTS.md from a CLAUDE.md. Do not wait for the fallback to appear in /config. [Source: https://github.com/anthropics/claude-code/releases/tag/v2.1.277]
A first session after upgrade is a time bomb for a junior who “just updated.” They open Claude Code, paste the ticket, and the fallback is still off until the next session. Print claude --version. Close. Open again. Then look for the load line.
When Claude is not reading AGENTS.md directly, keep one shared file with an import:
1@AGENTS.md
2
3## Claude Code
4
5Use plan mode for changes under `app/Billing`.
Official docs use that import shape. Claude reads the imported file first, then the rest. A symlink also works on Unix. Edit and Write refuse to write through a symlink and send Claude to the target instead. On Windows, use the import. Creating a symlink there needs Administrator privileges or Developer Mode, and Git checks a committed symlink out as a plain text file unless core.symlinks is enabled, which leaves that clone with a one-line CLAUDE.md. [Source: https://code.claude.com/docs/en/memory]
Leave an existing @AGENTS.md import in place if some sessions cannot load AGENTS.md directly. Keeping the import never makes Claude read AGENTS.md twice. A CLAUDE.md that only tells Claude in words to read AGENTS.md is not an import. Claude sees the file only if it decides to open it. Replace the sentence with @AGENTS.md or delete the Claude file so the fallback can fire. A SessionStart hook that prints AGENTS.md becomes a second copy once Claude reads the file directly. Remove the hook. [Source: https://code.claude.com/docs/en/memory]
I already refused to treat a client that still sends initialize as a broken Laravel MCP server in A Client That Still Sends Initialize Is Not a Broken Laravel MCP Server. Same habit here. An old session class is not a dead product.
A probe you run before you file the agent
I do not invent a dashboard. I read the files Git will ship and the files Git ignores.
1#!/usr/bin/env python3
2"""Print instruction files Claude Code counts from this working directory."""
3
4from __future__ import annotations
5
6import os
7from pathlib import Path
8
9CWD = Path.cwd().resolve()
10COUNTING = ("CLAUDE.md", ".claude/CLAUDE.md", "CLAUDE.local.md")
11AGENTS = ("AGENTS.md", ".claude/AGENTS.md")
12NOT_READ = ("AGENTS.local.md", "AGENTS.override.md")
13
14
15def walk_up(start: Path):
16 current = start
17 while True:
18 yield current
19 if current.parent == current:
20 break
21 current = current.parent
22
23
24def existing(root: Path, relative: str) -> Path | None:
25 path = root / relative
26 return path if path.is_file() else None
27
28
29def main() -> int:
30 owner = os.environ.get("INSTRUCTION_FILE_OWNER", "UNSET")
31 print(f"CWD={CWD}")
32 print(f"OWNER={owner}")
33 counting: list[str] = []
34 agents: list[str] = []
35 skipped: list[str] = []
36 for root in walk_up(CWD):
37 for name in COUNTING:
38 hit = existing(root, name)
39 if hit:
40 counting.append(str(hit))
41 for name in AGENTS:
42 hit = existing(root, name)
43 if hit:
44 agents.append(str(hit))
45 for name in NOT_READ:
46 hit = existing(root, name)
47 if hit:
48 skipped.append(str(hit))
49 agents_dir = root / ".agents"
50 if agents_dir.is_dir():
51 skipped.append(str(agents_dir) + "/ (not read)")
52 print("--- counting files (block AGENTS.md fallback) ---")
53 print("\n".join(counting) if counting else "(none)")
54 print("--- AGENTS.md files on disk ---")
55 print("\n".join(agents) if agents else "(none)")
56 print("--- not read as AGENTS.md ---")
57 print("\n".join(skipped) if skipped else "(none)")
58 if counting and agents:
59 print("VERDICT=CLAUDE_FILES_WIN_DEFAULT")
60 elif agents and not counting:
61 print("VERDICT=AGENTS_MD_FALLBACK_ELIGIBLE")
62 elif counting and not agents:
63 print("VERDICT=CLAUDE_ONLY")
64 else:
65 print("VERDICT=NO_PROJECT_INSTRUCTION_FILE")
66 if owner == "UNSET":
67 print("FAIL=name INSTRUCTION_FILE_OWNER before you file the agent")
68 return 1
69 return 0
70
71
72if __name__ == "__main__":
73 raise SystemExit(main())
Run it in the app root the coding agent uses, not in a docs folder on your laptop.
1export INSTRUCTION_FILE_OWNER="shinjae"
2python3 scripts/probe_instruction_files.py
3claude --version
The script does not talk to Anthropic. It reads the tree. VERDICT=CLAUDE_FILES_WIN_DEFAULT means the shared AGENTS.md is not the default brief. Then open /config. Copy Project instructions. Copy the load line from the session. Put those four lines on the ticket: owner, verdict, setting, load line.
find on those names is evidence of presence. It is not evidence of load.

What you must not do
Forbidden:
- File a “Claude ignored AGENTS.md” ticket without printing the counting files,
/configProject instructions, the load line, and one human name on the instruction file. - Put a Claude Code version in the title or the first line. The pin is evidence after the decision.
- Mix this field with an older bundled CLI that is not a logout, a Copilot picker name, or an
ubuntu-latestrunner label. Those are other tickets. - Treat
stableon npm as the field. This morningstableis still behind the fallback release. [Source: https://www.npmjs.com/package/@anthropic-ai/claude-code] - Drop
pluginConfigsinto project or local settings and expect Claude Code to honor it. Official docs say it ignores that key there. [Source: https://code.claude.com/docs/en/memory] - Add
CLAUDE.local.mdfor personal URLs and then claimAGENTS.mdis the brief. The local file counts. It steals the fallback. - Trust
/memoryas proof thatAGENTS.mdloaded. Official docs say that file is not listed there when it loaded through the setting. - Recommend buying a plan, a model, or a seat because a test command lived only in
AGENTS.md. - Treat the first session after an upgrade as a loaded fallback. Official docs say the next session is the one that reads
AGENTS.md.
Allowed:
- Print every counting Claude file from the working directory up.
- Print every
AGENTS.mdon disk, including.claude/AGENTS.md. - Open
/configand screenshot Project instructions. - Copy the
AGENTS.md loadedline when the fallback actually fired. - Keep
@AGENTS.mdinCLAUDE.mdwhen some hosts cannot load the fallback. - Name one human as
INSTRUCTION_FILE_OWNER.
GSC this week still has no striking-distance query on the ubuntu-latest post, the previews-block post, or the initialize post. I am not refreshing those URLs. This is a new field, not a synonym of Saturday’s runner label or Friday’s bindings warning.
If you need the broader habit, start at /ai-agent-operations/. Tooling notes live under /developer-tools/. Laravel plus Vue notes live under /laravel-vue-saas/ when the agent is touching that stack. A first-week map is at /start-here/.
A changelog bullet about AGENTS.md is not permission to skip /config.
What you should do Monday morning
- Open the repo that actually ships. Export
INSTRUCTION_FILE_OWNERto a human name. Runprobe_instruction_files.pyin the app root the coding agent uses. Write the verdict on the ticket next to that name. - Open Claude Code in that same directory. Type
/config. Copy Project instructions. If the panel has no such row, you are in a session class that never loadsAGENTS.mddirectly. Import@AGENTS.mdfromCLAUDE.mdon that host. - If both files exist and the setting is still the default, pick one owner decision: delete the unused Claude file so the fallback can fire, import
@AGENTS.md, or setclaude-md-and-agents-mdin user or managed settings. Do not leave two files and one hope. - If
CLAUDE.local.mdexists, treat it as a counting file. Either keep it and setclaude-md-and-agents-md, or move personal URLs out of a file that steals the brief. - Print
claude --version. If you upgraded this morning, close the first session and open a second before you claim the fallback loaded. - Confirm coding-agent instructions on this desk name the same owner and forbid “the agent ignored AGENTS.md” without the load line. A prompt that says “follow AGENTS.md” while
CLAUDE.mdstill wins is a different ticket.
The question is not whether AGENTS.md demos in an empty tree. The question is whether the load order survives maintenance, handoff, and a junior who already committed a Claude file.
Further reading
Source Claude Code Docs — How Claude remembers your project (AGENTS.md load table)
Source GitHub — Claude Code release that added AGENTS.md fallback
Source Claude Code Docs — Changelog (18–19 September 2026 notes)
