One AGENTS.md, every tool
Verified against Claude Code 2.1.311, Codex CLI 0.164.0, Cursor 3.27.14 · Updated
Most developers I’ve talked to maintain multiple config files for their AI coding tools. A CLAUDE.md for Claude Code, a .cursor/rules/ directory for Cursor, maybe a codex.md or AGENTS.md for Codex. Same project conventions written in three places.
The thing is, you probably don’t need to do that. AGENTS.md works natively in Codex, Cursor, and Claude Code. Claude Code is the odd one only when a CLAUDE.md is already on the path: then it needs a one-line bridge. That’s it. One file, three tools.
The problem with multiple config files
If you’ve ever switched between AI coding tools mid-project, you’ve felt this. Cursor knows you use vitest. Claude Code thinks you’re still on jest because nobody updated CLAUDE.md when you migrated. Codex has no config at all because you forgot it reads from AGENTS.md, not the other two.
It gets worse on teams. One developer sets up Cursor rules, another writes CLAUDE.md, a third adds AGENTS.md for Codex. Within a week, they’ve diverged. The Cursor rules say “use Prisma for database access.” The CLAUDE.md says “use Drizzle” because someone refactored last Tuesday. Nobody updated the other files.
There’s a simpler answer.
What each tool actually reads
In Claude Code
Claude Code reads AGENTS.md on its own when nothing else is in the way. The blocker is a CLAUDE.md, .claude/CLAUDE.md, or CLAUDE.local.md in the working directory or any directory above it. Your ~/.claude/CLAUDE.md and an org-managed CLAUDE.md do not count. Direct reads need v2.1.277 or later. If one of those project files is already there, Claude reads it and skips AGENTS.md, and the bridge below is how you share one file anyway. A symlink (ln -s AGENTS.md CLAUDE.md) also works if you have nothing Claude-specific to add. 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 instead of your instructions.
In Codex
Codex reads AGENTS.md natively. In ~/.codex (or CODEX_HOME if you set it) it reads the first non-empty file, AGENTS.override.md before AGENTS.md. It then walks from the project root, usually the Git root, down to the current directory and takes one non-empty file per directory in that same order. It stops adding files once the combined text reaches project_doc_max_bytes (32 KiB by default). If it cannot find a project root, it only checks the current directory.
In Cursor
Cursor reads AGENTS.md natively, in the project root and in nested directories, alongside .cursor/rules/*.mdc files. AGENTS.md is plain markdown with no frontmatter. The .mdc files add conditional rules (description, globs, alwaysApply). For most project-wide conventions, AGENTS.md is enough.
The Claude Code bridge
Create a CLAUDE.md when Claude is not reading AGENTS.md directly. That is any repo that already has a CLAUDE.md, .claude/CLAUDE.md, or CLAUDE.local.md on the path, a session with Project instructions set to claude-md, or a session that cannot load AGENTS.md: before v2.1.277, with the built-in AGENTS.md plugin disabled, or the first session after an upgrade from v2.1.276 or earlier.
Put the file in the project root. One line:
@AGENTS.md
That’s the entire file. Claude Code’s @ import pulls in AGENTS.md at launch, then reads any lines under the import. No symlinks, no build scripts. Edit AGENTS.md and the next session loads the new text.
@ paths resolve relative to the file that contains the import, not your working directory. From a root CLAUDE.md, @AGENTS.md is the project file. A CLAUDE.md inside .claude/ would look for .claude/AGENTS.md instead. The same line in ~/.claude/CLAUDE.md loads ~/.claude/AGENTS.md, not the repo’s. Keep the project import in the project file. The global file is for preferences that apply everywhere, and an import there needs a real path:
# Global preferences
- Always use TypeScript strict mode
- Prefer functional patterns
- @~/.claude/my-project-instructions.md
The @ import merges with any other content in the file. Claude reads the imported file first, then the rest. Your AGENTS.md handles the project-level config, and anything tool-specific goes below the import.
Writing your AGENTS.md
Here’s a real AGENTS.md for a Next.js + TypeScript project. Every section has a reason.
# AGENTS.md
## Setup
- Install deps: `pnpm install`
- Dev server: `pnpm dev` (port 3000)
- Run all tests: `pnpm test`
- Run single test: `pnpm vitest run -t "test name"`
- Type check: `pnpm tsc --noEmit`
- Lint: `pnpm lint`
## Stack
- Next.js 15 (App Router)
- TypeScript 5.7 (strict mode)
- Tailwind CSS 4
- Drizzle ORM + Postgres
- Vitest + Testing Library
## Code style
- Single quotes, no semicolons
- Named exports over default exports
- Server components by default, 'use client' only when needed
- Collocate tests next to source files (Button.test.tsx beside Button.tsx)
- Use cn() helper from lib/utils for conditional class names
## Database
- Migrations in drizzle/migrations/
- Generate migration: `pnpm drizzle-kit generate`
- Apply migrations: `pnpm drizzle-kit migrate`
- Schema files in src/db/schema/
- Always use prepared statements, never raw SQL strings
## Architecture
- Feature folders in src/features/ (each has components/, hooks/, actions/)
- Shared UI in src/components/ui/
- Server actions in actions.ts files, validated with Zod
- Environment variables: src/env.ts (validated at build time)
## PR conventions
- Branch format: feature/short-description or fix/short-description
- Commit messages: imperative mood ("add login page" not "added login page")
- Run pnpm test and pnpm lint before committing
- One concern per PR
A few things to notice. The setup section has exact commands, not descriptions. “Run pnpm vitest run -t "test name"” is more useful to an AI agent than “use vitest for testing.” Same for the database section: the actual migration commands, not “we use Drizzle.”
The architecture section tells the agent where things live. Without this, every AI tool will ask you where to put a new component, or worse, guess wrong and create files in random locations.
If you’re working in Python, Rust, or Go, the structure is the same. Swap the commands and stack, keep the sections.
What can’t go in AGENTS.md
AGENTS.md covers 90% of what you need. But each tool has features that AGENTS.md doesn’t support. Here’s what’s left out and whether it matters.
Cursor’s .mdc metadata
Cursor’s .cursor/rules/*.mdc files support frontmatter that AGENTS.md can’t replicate:
---
globs: "*.test.tsx, *.spec.ts"
alwaysApply: false
---
When writing tests, always use describe/it blocks (not test).
Mock external services with MSW, never with jest.mock.
The globs field attaches this rule when a matching file is in context. alwaysApply: false is what lets that glob decide. Set alwaysApply to true and Cursor includes the rule in every chat and ignores globs. AGENTS.md has no frontmatter, so a root AGENTS.md is loaded for the project. A nested AGENTS.md applies when you work in that directory or its children.
Does this matter? For most projects, no. Putting your testing conventions in AGENTS.md works fine. The agent sees them on every request, but that’s a few extra tokens, not a real cost. Conditional loading matters more in large monorepos where you have hundreds of context-specific rules.
If you do need it: keep your AGENTS.md as the primary config, and add a thin .cursor/rules/ directory for the few rules that genuinely need file-pattern triggering.
Codex’s override files
Codex supports AGENTS.override.md, which replaces AGENTS.md in the same directory. It loads only one of them, and it skips an empty file. Personal preferences go in ~/.codex/AGENTS.override.md, which replaces ~/.codex/AGENTS.md until you remove it. Inside a repo, the docs use AGENTS.override.md in a subdirectory for rules that replace that directory’s AGENTS.md. That example is a project file you can commit. The AGENTS.md format has no override filename. This one is Codex.
Claude Code’s @-imports
Claude Code’s CLAUDE.md supports importing multiple files with @ syntax:
@AGENTS.md
@docs/api-reference.md
@docs/deployment-guide.md
This lets you pull in additional context beyond your AGENTS.md. Useful when you have detailed docs that the agent should reference but don’t belong in your project conventions file. AGENTS.md is plain markdown and the format does not define imports, so this syntax stays Claude Code’s. When Claude Code loads an AGENTS.md directly, it expands @path imports inside that file too.
The pattern
Think of it as layers:
- AGENTS.md (committed, cross-tool): your project conventions, setup commands, architecture decisions, coding style. Codex, Cursor, and Claude Code all read this. Claude Code skips it when a
CLAUDE.md,.claude/CLAUDE.md, orCLAUDE.local.mdis already on the path. - CLAUDE.md (committed, Claude Code only):
@AGENTS.mdin the project root, plus any Claude-specific lines under it. You need this when a CLAUDE.md is already on the path, or when a session cannot load AGENTS.md directly. - .cursor/rules/ (committed, Cursor only): conditional rules that need file-pattern triggering. Only if you actually need them.
- AGENTS.override.md (Codex only): replaces AGENTS.md in the same directory. A personal one lives in
~/.codex/. A project one can be committed when a subdirectory needs different rules.
Most projects need layer 1. Layer 2 is one line, and only when Claude Code is not already reading AGENTS.md. Layers 3 and 4 are optional and situational.
AGENTS.md is the standard
AGENTS.md isn’t just a convention that caught on. The Agentic AI Foundation hosts it as an open project, next to MCP and A2A.
Claude Code reads AGENTS.md on its own as of v2.1.277, when no CLAUDE.md, .claude/CLAUDE.md, or CLAUDE.local.md sits in the working directory or above it. Your ~/.claude/CLAUDE.md does not block that. When a project CLAUDE.md is already there, the one-line @AGENTS.md import is the documented way to share one file. I keep that import in repos that already have a CLAUDE.md.
Write your conventions once. Put them in AGENTS.md. Let every tool read the same source of truth.
Sources
- https://code.claude.com/docs/en/memory
- https://docs.anthropic.com/en/docs/claude-code/memory
- https://raw.githubusercontent.com/anthropics/claude-code/main/CHANGELOG.md
- https://registry.npmjs.org/@anthropic-ai/claude-code/latest
- https://developers.openai.com/codex/guides/agents-md
- https://github.com/openai/codex/releases/tag/rust-v0.164.0
- https://registry.npmjs.org/@openai/codex/latest
- https://cursor.com/docs/context/rules
- https://cursor.com/help/customization/rules
- https://cursor.com/changelog
- https://cursor.com/docs/release-notes/ide
- https://cursor.com/download
- https://cursor.com/api/download?platform=darwin-arm64&releaseTrack=stable
- https://aaif.io/projects
- https://agents.md/