Project Setup
Use when wiring a repo so Claude Code, Codex, and Cursor all work in it, or when the user asks to make a project agent-friendly.
Setup is not the audit. The audit judges an existing file; setup decides which files exist and which tool reads each one. Run setup first on a bare repo, then audit the AGENTS.md it produces.
Contents
- One Shared Instruction File
- What Each Tool Actually Loads
- Per-Tool Wiring
- Where Deep Docs Go
- Project-Scoped Skills
- Enforcement That Survives Tool Choice
- Verify By Asking, Not By Reading
One Shared Instruction File
AGENTS.md at the repo root is the shared source of truth. Claude Code supports it through the built-in agents-md mod; Codex and Cursor also read it. Keep nested instructions in nested AGENTS.md files. Do not create Claude wrappers, duplicate copies, or compatibility symlinks for an AGENTS.md-only setup. Gemini CLI needs its context.fileName setting configured separately.
Source: Anthropic agents-md mod. The announcement identifies Claude Code 2.1.277 as the first supporting version; check the installed version and built-in mod before relying on it.
Two copies of a rule is the failure this prevents. They drift silently, because nothing in the codebase contradicts either one.
Set the scope deliberately. Repo-specific commands, conventions, and gotchas go in the repo. Personal defaults ("commit to the current branch", a preferred code style) belong in the user-level file each tool reads (~/.claude/CLAUDE.md, ~/.codex/AGENTS.md, Cursor's User Rules), not in a file the team shares.
What Each Tool Actually Loads
The instruction files look identical on disk and behave differently per tool. Decide placement from this table, not from the file tree.
| Behaviour | Claude Code | Codex | Cursor |
|---|---|---|---|
| Root file | AGENTS.md and .claude/AGENTS.md through the enabled mod, subject to Project instructions mode |
AGENTS.override.md, else AGENTS.md, else names in project_doc_fallback_filenames |
AGENTS.md, plus .cursor/rules/*.mdc |
| User-level file | ~/.claude/CLAUDE.md, ~/.claude/rules/ |
~/.codex/AGENTS.md (or AGENTS.override.md) |
User Rules in the app |
| Nested files | Ancestors of the launch directory at start; subdirectories on demand when Claude reads files there | Only the root-to-launch-directory path, concatenated root first, until project_doc_max_bytes (32 KiB default) is hit |
Nested AGENTS.md in subdirectories |
@path import |
Expanded at launch, four hops deep, skipped inside code spans and fences | Plain text, no warning | Plain text |
| Path-scoped rules | .claude/rules/*.md with paths: frontmatter |
None | .cursor/rules/*.mdc with globs: |
| Enforcement, not advice | Hooks in .claude/settings.json |
None in the instruction layer | .cursor/hooks.json |
Two rules follow from the table:
- Anything every tool must obey goes inline in the root
AGENTS.md. Imports,.claude/rules/, and.mdcfiles each reach one tool. - An import never reduces context; it is expanded at launch. When a root file must shrink and still reach every tool, cut content or move it to a nested file, a path-scoped rule, or a skill. Hiding it behind an import keeps the cost and loses two of the three tools.
Per-Tool Wiring
Add only what the repo actually needs.
Claude Code: use the enabled built-in
agents-mdmod and/config→ Project instructions.claude-md-or-agents-mdis the default. A projectCLAUDE.md,.claude/CLAUDE.md, orCLAUDE.local.mdanywhere from root to working directory suppresses that fallback for the project; managed files,~/.claude/CLAUDE.md, and.claude/rulesdo not.claude-md-and-agents-mdloads both formats, deduplicating imports and linked copies.claude-mdandmanaged-onlydo not load project AGENTS.md. Disabling the mod also disables AGENTS.md support.The option is
pluginConfigs["agents-md@builtin"].options.instructionFilesin user settings (~/.claude/settings.json),--settings, or managed settings. Project.claude/settings.jsondoes not configure plugin options. Preserve unrelated settings. A legacyprojectInstructionsoption can affect the default; inspect it when loading differs from the selected mode.Migrate each directory: rename a standalone
CLAUDE.mdtoAGENTS.md; when both exist, merge unique instructions into AGENTS.md and remove the old file. Unlink duplicate symlinks without deleting their targets. Resolve reverse links (AGENTS.md -> CLAUDE.md) before removal. Update references to moved files and any scaffold that recreates wrappers. Keep user edits and nested scope intact. Inspect.claude/CLAUDE.mdand privateCLAUDE.local.mdtoo; do not publish private content into a shared file. If private overrides must remain, use the both-files mode and report that exception.Nested AGENTS.md attaches on text
Read, with a nested CLAUDE.md taking priority in fallback mode. The mod does not cover--add-dirAGENTS.md, prompt mentions, IDE selections, or non-text Read attachments in the same way as engine CLAUDE.md./memorydoes not list AGENTS.md; verify the instruction announcement and a loaded-only rule probe. External imports require approval the AGENTS.md mod cannot itself request.Codex: nothing beyond
AGENTS.md.AGENTS.override.mdin the same directory wins overAGENTS.md, which is useful for a local experiment and a trap when one is committed by accident, so checkgit ls-files | grep overrideduring setup. A repo that must keepCLAUDE.mdas its only file can be read by Codex withproject_doc_fallback_filenames = ["CLAUDE.md"]in~/.codex/config.toml, but that is per machine, so renaming toAGENTS.mdis the fix that travels.Cursor:
AGENTS.mdcovers the prose. Add.cursor/rules/*.mdconly for rules that need glob scoping, whichAGENTS.mdcannot express:
---
description: Test conventions
globs: **/*.test.ts
alwaysApply: false
--- The .mdc extension and the frontmatter are both required; a plain .md dropped in that folder is ignored with no message. alwaysApply: true with empty globs duplicates what AGENTS.md already does. Cursor's own ceiling is 500 lines per rule. Hooks live in .cursor/hooks.json.
Where Deep Docs Go
Detail that does not fit the root file goes in a neutral, committed path: docs/ or .agents/, referenced from AGENTS.md by plain relative path so every tool can follow it when the task needs it.
Do not put shared knowledge under .claude/. That path reads as Claude-only, and it is commonly gitignored, which quietly scopes hard-won knowledge to one machine. Check .gitignore during setup: if agent config is ignored, decide per file whether it is personal (leave ignored) or repo knowledge (commit it).
Project-Scoped Skills
Install skills into the repo rather than the user's home when they encode this project's workflows:
npx skills add <owner>/<repo> # project scope is the default; -g would install to the home directoryClaude Code reads .claude/skills/; Codex and Cursor read .agents/skills/. The CLI writes each.
Skills that drive a specific harness do not travel. One that calls a Claude Code tool, spawns claude -p, or depends on an MCP server present in only one tool should stay out of the shared set, because in the other tools it advertises a capability that is not there.
Watch the description budget; both tools have one. Claude Code caps the skill listing at 1% of the context window and shortens descriptions to fit (/doctor estimates the cost); Codex caps it at 2% of the context window or 8,000 characters, shortens descriptions first, then omits skills with a warning. Either way a large install degrades triggering across every skill, not just the new one. Install what the repo needs, not everything available.
Enforcement That Survives Tool Choice
An instruction file is context, not configuration; Claude Code's own docs say so, and the same holds in Codex and Cursor. A rule stated in prose is obeyed unevenly across tools. A rule with an exit code is obeyed by all of them.
Prefer, in order: a linter or formatter rule, a git hook (lefthook, husky) that fires whichever agent made the edit, then a CI check. Tool-native hooks (.claude/settings.json, .cursor/hooks.json) are the last rung, because they cover one tool only. Move a prose rule down to an exit code whenever the check is mechanical, and delete the prose once the gate exists.
Verify By Asking, Not By Reading
A correct-looking instruction file proves nothing: a broken setup and a working one are identical on disk. Ask each tool to quote a rule back.
claude -p "From loaded instructions only, no tools: quote the repo's test command."
codex exec --skip-git-repo-check "From loaded instructions only, no tools: quote the repo's test command."
agent -p "From loaded rules only, no tools: quote the repo's test command."Pick a small fast model for the probe; the point is loaded context, not model strength.
Pick a rule that appears nowhere else in the repo, so a correct answer cannot come from reading the code. If a tool cannot answer, its wiring is broken regardless of what the file says. Inside an interactive Claude Code session, /context lists the memory files that loaded, alongside the mod's instruction announcement and the loaded-only probe; a missing wrapper is not a failure.