One AGENTS.md for every coding agent: import, symlink, or duplicate?
AGENTS.md is a plain Markdown file of standing instructions: build commands, conventions, the trap in the build that a new teammate would have to be told. It is the closest thing coding agents have to a shared instruction filename. It is not a shared loader.
A root AGENTS.md reaches Codex, OpenCode, Qwen Code, Copilot CLI, and Cursor by default. Claude Code reads it only when no project CLAUDE.md is in the working directory or above it, and Gemini CLI reads it only when you tell it to, through context.fileName or a GEMINI.md import. One file can serve every agent covered here, but not by dropping it in the repository and assuming. The version that survives is one canonical AGENTS.md plus a one-line adapter where a tool needs it. An import is the adapter that travels with the repository. A symlink looks simpler and fails in narrower places. A duplicate is the one that drifts.
Checked against each tool's documentation on 27 October 2026.
Which agents read a root AGENTS.md?#
A root file is the easy case. Nested files, monorepos, and conflicting rules are a different question; the concept page covers that.
| Agent | Root AGENTS.md by default? | What to add for one shared file | More |
|---|---|---|---|
| Claude Code | Only when no project CLAUDE.md, .claude/CLAUDE.md, or CLAUDE.local.md is in the working directory or above it, on v2.1.277 or later (memory) | A CLAUDE.md with @AGENTS.md, or set Project instructions to claude-md-and-agents-md. A CLAUDE.local.md also switches it off. | Claude Code guide |
| Codex | Yes, from the project root to the working directory; AGENTS.override.md wins in a directory (AGENTS.md) | Nothing. No include syntax is documented; an open request asks for one (#6038). A differently named file can go in project_doc_fallback_filenames. | Codex guide |
| OpenCode | Yes. V2 reads AGENTS.md only; V1 falls back to CLAUDE.md when no AGENTS.md is on the path (V2, V1) | Nothing for AGENTS.md. For another name, use the instructions array. | OpenCode guide |
| Copilot CLI | Yes, in its standard locations (custom instructions) | Nothing. It also reads the adapter files you add for other tools. | Copilot CLI guide |
| Gemini CLI | No. GEMINI.md is the default; AGENTS.md loads only when added to context.fileName (GEMINI.md) | Add AGENTS.md to context.fileName, or put @./AGENTS.md in GEMINI.md. Pick one. | Gemini CLI guide |
| Qwen Code | Yes. QWEN.md and AGENTS.md are both defaults (memory, source) | Nothing. Do not add an @AGENTS.md shim; Qwen already reads both names, and the same text loads twice when an imported file is also on the list (#15679, open, reported with a CLAUDE.md shim). | Qwen Code guide |
| Cursor | Yes, at the repository root, always applied (rules) | Nothing for the root file. A nested AGENTS.md attaches when the agent reads a file there (CLI since v2026.10.22: also edits or creates one), once per conversation, and can drop after a summary. | Cursor AGENTS.md |
Claude's direct support arrived in v2.1.277; before v2.1.281, sessions on Bedrock or with telemetry off could still load only CLAUDE.md, so the import is the fallback there. Gemini CLI's docs now carry a banner: unpaid-tier and Google One users were moved to Antigravity CLI on 18 June 2026. The Gemini CLI guides cover the transition.
Import, symlink, or duplicate?#
| Arrangement | Works where | Breaks when |
|---|---|---|
| Native read | Codex, OpenCode, Qwen, Copilot, and Cursor; Claude with no project CLAUDE.md; Gemini after a setting | A project CLAUDE.md exists; Gemini is unconfigured; a tool needs another name; a nested file must apply from the first turn |
| Import | Claude, Gemini, Copilot in three filenames, and Qwen | Codex and OpenCode do not expand @; Cursor documents no import in AGENTS.md; depth limits differ; the same file is also discovered |
| Symlink | A tool that reads the linked name; Cursor deduplicates a symlinked CLAUDE.md from 3.26 | Claude's edit tools, Windows checkouts, network paths, user-scope duplicate; older Cursor builds load the pair twice |
| Duplicate | A tool you cannot configure | Drift; both names load; no single source; Cursor reads both AGENTS.md and CLAUDE.md with no documented precedence |
Import#
An import is a line in a file the tool already reads. The text is expanded at load time; the model sees the text, not a reference.
In Claude Code, a CLAUDE.md whose first line is @AGENTS.md is the documented adapter. The docs say it never makes Claude read AGENTS.md twice, whichever Project instructions value is set (memory). Imports nest four hops, and an import from a project file that resolves outside the working directory needs one approval per project.
Gemini's import processor allows five levels and rejects paths outside its allowed directories; an absolute import outside the base path is the common failure (memport, #4098). Copilot CLI expands @ in .github/copilot-instructions.md, AGENTS.md, and CLAUDE.md, but not in GEMINI.md or *.instructions.md, and only for repository-relative paths (custom instructions). Qwen expands @path five levels deep inside the project root, but does not need a shim because it reads AGENTS.md (Qwen guide).
Cursor's docs do not document an import in AGENTS.md. They say rule content reaches the agent as written, and a file mention tells the agent where to look rather than inlining the file (rules); treat @path there as a pointer the agent may read, not an expansion at load time.
Keep imports one hop deep. Do not put an import in the canonical AGENTS.md: Claude, Copilot, and Qwen expand it; Codex and OpenCode pass the line through as text, and Cursor leaves a file mention for the agent to read with its tools. A file that says @docs/rules.md means different things in different tools.
Symlink#
A symlink is a filesystem alias. The agent opens CLAUDE.md; the operating system returns AGENTS.md. Claude's docs present it as an option, and in a project directory they say the content is read once (memory). Claude's Edit and Write tools refuse to write through a symlink and tell the model to edit the target instead (#66559, open). On Windows, creating a symlink needs Administrator privileges or Developer Mode, and Git checks a committed symlink out as a plain text file unless core.symlinks is enabled. A symlink to a network path is not followed at all.
At user scope, the dedupe does not hold: ~/.claude/CLAUDE.md pointing at ~/AGENTS.md loads both copies, because different loaders find them (#102369, open 15 October 2026). The docs describe the project case.
Qwen fixed the same bug for a symlinked QWEN.md by deduplicating on the real path (#9597, closed 26 August 2026). Symlink dedupe is a per-tool detail, not a property of symlinks.
Cursor does not need a symlink, because it reads AGENTS.md directly. From 3.26, a CLAUDE.md that is a symlink, hard link, or identical copy of AGENTS.md is sent once; older builds could load both (release notes, forum).
Duplicate#
A duplicate is two real files. It works in a tool you cannot configure, and creates two sources of truth. You fix the test command in AGENTS.md; the copy in GEMINI.md still says npm test. The next agent reads the stale one.
Copilot CLI's docs say it removes duplicate copies of identical instructions (custom instructions). Claude, Gemini, and Qwen do not promise that for two separate files; if both names load, both texts are in the prompt. The benchmark found context files add inference cost without a general gain in task success (arXiv:2602.11988v3, revised 29 September 2026), so paying twice for the same words is a real cost.
A copy is defensible when you cannot add an adapter file or change a setting, and the tool cannot read AGENTS.md. Then copy the smallest useful delta, not the whole file, and date it.
Cursor reads AGENTS.md directly, so a copy under another name is not needed. If both names exist, the docs describe both as applied, with no precedence between them, so the duplicate is a second source of truth (Help).
A setup that works in all seven#
- Make
AGENTS.mdthe source. Put in it what an agent cannot derive: exact build and test commands, non-standard tooling, repo-specific traps, constraints. The benchmark found repository overviews did not help; Claude's docs say to move procedures out; Qwen's docs say longer files are followed less reliably. - Leave Codex, OpenCode, Qwen, Copilot, and Cursor alone. They read
AGENTS.md. Cursor always applies the root file; a nested file attaches on a read in its folder, once per conversation, and can drop after a summary, so keep load-bearing rules in the root. If a tool needs another filename, useproject_doc_fallback_filenamesin Codex orinstructionsin OpenCode; do not add a copy. - For Claude, choose direct or imported. With no project
CLAUDE.md,.claude/CLAUDE.md, orCLAUDE.local.md, Claude readsAGENTS.mddirectly. With one, put@AGENTS.mdat the top ofCLAUDE.mdand Claude-only notes below. The import travels with the repository; the Project instructions setting is per-user, so it does not. ACLAUDE.local.mdanywhere above the working directory switches Claude offAGENTS.md; set Project instructions toclaude-md-and-agents-mdor keep the personal notes elsewhere. - For Gemini, pick one adapter. Add
AGENTS.mdtocontext.fileName, or makeGEMINI.mda one-line@./AGENTS.md. Not both: at v0.65.0 the configured name is added to the default, so a shim plusAGENTS.mdin the list sends the same text twice. With the shim,/memory listshowsGEMINI.md; the imported text sits inside its block. - Do not symlink. The import avoids the Windows checkout, the edit refusal, the network-path rule, and the user-scope duplicate. If you have a project symlink, replace it with an import; the docs say the content is read once either way.
Check for one copy, not zero and not two#
Each agent has an inventory. Use it; a model sees the prompt, not the loader.
| Agent | Check | What one copy looks like |
|---|---|---|
| Claude Code | /context under Memory files; the InstructionsLoaded hook, which logs each load | One CLAUDE.md entry and one include. The hook does not fire for that path when Claude reads AGENTS.md directly. |
| Codex | codex debug prompt-input | One block per file on the chain; the text appears once. |
| OpenCode | V2 instruction record or a prompt logger; V1 a prompt logger | One Instructions from: <path> block per path. |
| Copilot CLI | /instructions; /context | The file list plus a token count that is not two full copies. It reads both AGENTS.md and any CLAUDE.md you added. |
| Gemini CLI | /memory list; /memory show | GEMINI.md once, with the imported text inside it. A separate AGENTS.md block means both adapters are on. |
| Qwen Code | /context detail; /memory | Each top-level file once. Two entries for one path are the duplicate case. |
| Cursor | Customize → Rules; @AGENTS.md or a canary in a new chat | One AGENTS.md entry with the always-applied rules, if the build lists it; the canary shows whether the text reached the model. |
Full commands: Claude Code, Codex, OpenCode, Copilot CLI, Gemini CLI, Qwen Code, and Cursor.
If the same physical file appears twice, delete one path before adding anything else. The duplicate is usually an adapter you added for one tool that another tool also reads.
Where to go next#
- AGENTS.md and skills: what each agent reads — nested files and memory.
- Why Claude Code loaded your CLAUDE.md but ignored it — loads but loses.
- Why Codex ignores part of your AGENTS.md — the chain and 32 KiB.
- Why OpenCode ignores your AGENTS.md — V1, V2, checks.
- Why Copilot CLI ignores your AGENTS.md — combined files, process cache.
- Does Gemini CLI read AGENTS.md? — the default and
context.fileName. - QWEN.md and AGENTS.md in Qwen Code — default list, duplicate import.
- Does Cursor read AGENTS.md? — root and nested files, and the read trigger.
- Persistent memory for Claude Code and Codex — if the question is memory.