How to Write AGENTS.md and CLAUDE.md Files Agents Follow (2026)
This guide is for engineers who maintain a repository that coding agents now work in, and who want one set of instructions that Claude Code, OpenAI Codex, Cursor and GitHub Copilot all pick up and actually follow. By the end you will have a short AGENTS.md as the single source of truth, a CLAUDE.md that imports it, path-scoped rules for the parts of the codebase that need them, a hook for the rules that must never be broken, and a script that tests the whole setup. Paths and behaviour were checked against the Claude Code, Codex, Cursor and GitHub docs in October 2026; native AGENTS.md reading in Claude Code needs v2.1.277 or later. You need a git repository and at least one of those agents installed.
Step 1: Pick AGENTS.md as the canonical file
AGENTS.md started at OpenAI and is now stewarded by the Agentic AI Foundation, announced by the Linux Foundation on 9 December 2025 with MCP, goose and AGENTS.md as founding projects. The agents.md site lists over 20 tools that read it and cites more than 60,000 open-source projects using it. It is plain Markdown with no required fields.
Here is what each tool reads today. Verify against your installed version, because this changed several times in 2026.
| Tool | Reads | Nested files | Source |
|---|---|---|---|
| Claude Code | CLAUDE.md, .claude/CLAUDE.md, CLAUDE.local.md; AGENTS.md only when no CLAUDE.md exists (default) |
Subdirectory files load on demand | Claude Code memory docs |
| OpenAI Codex | AGENTS.override.md if present, else AGENTS.md (one file per directory), from git root to cwd |
Concatenated, closer files last; 32 KiB default cap | Codex AGENTS.md docs |
| Cursor | .cursor/rules/*.mdc, AGENTS.md |
Nested AGENTS.md combine with parents |
Cursor rules docs |
| GitHub Copilot | .github/copilot-instructions.md, .github/instructions/*.instructions.md, AGENTS.md (or a root CLAUDE.md or GEMINI.md) |
Nearest AGENTS.md wins |
GitHub docs |
The one trap in that table is Claude Code. By default it reads AGENTS.md only when there is no CLAUDE.md, .claude/CLAUDE.md or CLAUDE.local.md in the working directory or above it. Adding a personal CLAUDE.local.md silently switches AGENTS.md off for you. Step 3 handles that.
Step 2: Write a short AGENTS.md with commands, conventions and don'ts
Before you write anything, read the one rigorous study on these files. Evaluating AGENTS.md (Gloaguen et al., first posted February 2026, revised in September) found that context files generally did not improve task success across several agents and models, and raised inference cost by over 20 percent. Agents followed the instructions; the repository overviews just did not help them navigate. The authors conclude that context files are useful for specifying non-standard coding practices, and that anything more should be evaluated before you rely on it.
So the file should hold what an agent cannot work out by reading the code: exact commands, the conventions that differ from the language default, and the hard don'ts. Skip the architecture essay. Claude Code's docs suggest under 200 lines per file; I aim for under 80.
# AGENTS.md
## Commands (run from repo root)
- Install: `pnpm install --frozen-lockfile`
- Unit tests: `pnpm test -- --run` (Vitest; do not start watch mode)
- One test file: `pnpm test -- --run src/billing/invoice.test.ts`
- Lint and types: `pnpm lint && pnpm typecheck`
- Local stack: `docker compose up -d postgres redis` (tests need both)
## Conventions that differ from the defaults
- Database access only through `src/db/repo/*`; never import `pg` elsewhere.
- Money is integer cents (`number`), never floats. See `src/billing/money.ts`.
- New HTTP handlers go in `src/api/handlers/` and must have a Zod schema.
## Before you finish
- Run lint, typecheck and the tests for files you touched. Fix failures.
- Commit messages: `type(scope): summary`, for example `fix(billing): round tax`.
## Do not
- Do not edit `migrations/` that are already merged; add a new migration.
- Do not add dependencies without saying why in the PR description.
- Do not run `terraform apply` or anything under `infra/` against real accounts.
Every line is checkable. Claude Code's docs make the same point: "Run npm test before committing" beats "Test your changes", and "API handlers live in src/api/handlers/" beats "Keep files organized". Vague instructions are the ones agents drop first.
If you already have a long CONTRIBUTING.md, do not paste it in. Link to it in one line, and the agent can read it when a task calls for it. That is just-in-time retrieval, the same idea I describe in Context Engineering Explained.
Step 3: Wire Claude Code with CLAUDE.md and an @AGENTS.md import
Claude Code supports imports with @path. A CLAUDE.md next to AGENTS.md that imports it works on every Claude Code version, works when a teammate has a CLAUDE.local.md, and gives you a place for Claude-specific lines:
<!-- CLAUDE.md (repo root). HTML comments like this are stripped before loading. -->
@AGENTS.md
## Claude Code only
- Use plan mode for any change under `src/billing/`.
- For log or kubectl output longer than a page, delegate to the log-triage subagent.
Prefer the import to ln -s AGENTS.md CLAUDE.md if anyone clones on Windows: the docs warn that Git checks a committed symlink out as a plain text file unless core.symlinks is enabled. Do not write "please read AGENTS.md" in prose either; the docs note Claude then sees the file only if it decides to open it.
The full load order, broadest first, is: managed policy (/Library/Application Support/ClaudeCode/CLAUDE.md on macOS, /etc/claude-code/CLAUDE.md on Linux), your user file ~/.claude/CLAUDE.md, then project files from the filesystem root down to your working directory, with CLAUDE.local.md appended after CLAUDE.md at each level. Files are concatenated, not overridden, so contradictions between levels are resolved arbitrarily. Imports can nest up to four hops.
For personal, uncommitted preferences:
# Personal notes for this repo only
printf '%s\n' '- My sandbox API is http://localhost:8787' > CLAUDE.local.md
echo 'CLAUDE.local.md' >> .gitignore
If you want Claude Code to read CLAUDE.md and AGENTS.md without the import, set Project instructions to claude-md-and-agents-md in /config. That setting lives in user or managed settings, not in the repo, so the import is the more portable choice for a team.
Step 4: Scope rules to paths instead of growing one file
Rules that only matter for part of the codebase should not load on every task. Each tool has a mechanism.
Claude Code reads .claude/rules/*.md. A rule with paths frontmatter loads only when Claude reads or edits a matching file:
---
paths:
- "infra/**/*.tf"
- "infra/**/*.tfvars"
---
# Terraform rules
- Pin providers with `~>` in `versions.tf`; never use `>=` alone.
- Run `terraform fmt -recursive infra/` and `terraform validate` after edits.
- Plans only. Never run `apply`, `import` or `state rm`.
Cursor uses .mdc files in .cursor/rules/ with description, globs and alwaysApply frontmatter. A plain .md file there is ignored:
---
description: Terraform conventions for the infra directory
globs: infra/**/*.tf
alwaysApply: false
---
- Pin providers with `~>`. Run `terraform fmt` and `terraform validate` after edits.
- Never run `terraform apply`.
Copilot uses .github/instructions/NAME.instructions.md with applyTo, and you can hide a file from code review or the cloud agent with excludeAgent:
---
applyTo: "infra/**/*.tf,infra/**/*.tfvars"
---
Pin providers with `~>`. Never suggest `terraform apply` in automation.
Duplication across three formats is annoying. For a monorepo the simpler option is a nested infra/AGENTS.md: Codex concatenates it after the root file, Cursor combines it with parents, Copilot uses the nearest one, and Claude Code reads a subdirectory AGENTS.md when it opens a file there, but by default only when no CLAUDE.md exists on the path. With the root CLAUDE.md from Step 3, add an infra/CLAUDE.md containing just @AGENTS.md, or set Project instructions to claude-md-and-agents-md. Keep path-scoped formats for rules a single tool needs.
Step 5: Enforce the rules that must hold with hooks
Instruction files are context, not configuration. The Claude Code docs say this plainly: CLAUDE.md content is delivered as a user message after the system prompt, and there is no guarantee of strict compliance. If breaking a rule causes an incident, do not leave it to a Markdown bullet. Use a PreToolUse hook, which runs before a tool call and can block it with exit code 2, sending your stderr back to Claude as feedback.
#!/usr/bin/env bash
# .claude/hooks/guard-bash.sh : blocks dangerous shell commands (needs jq)
set -euo pipefail
COMMAND=$(jq -r '.tool_input.command // empty')
case "$COMMAND" in
*"terraform apply"*|*"terraform destroy"*)
echo "Blocked: terraform apply/destroy is not allowed from the agent. Run a plan instead." >&2
exit 2 ;;
*"git push --force"*|*"git push -f"*)
echo "Blocked: force pushes are not allowed. Push a new commit." >&2
exit 2 ;;
esac
exit 0 # no objection; the normal permission flow still applies
Register it, plus a formatter that runs after every edit so style rules do not need to live in prose at all:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/guard-bash.sh" }
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
]
}
]
}
}
Save that as .claude/settings.json, run chmod +x .claude/hooks/guard-bash.sh, and commit both. Substring matching like this is a guardrail against mistakes, not a security boundary; a determined agent can spell a command differently. For untrusted runs, the real boundary is the environment: credentials the agent does not have and a sandbox it cannot leave. I walk through that for CI in How to Run an AI Coding Agent in GitHub Actions Safely, and the policy side in Policy as Code for AI Agents.
Other agents have their own equivalents (Codex has approval modes and sandbox settings, Cursor has team rules that can be enforced from the dashboard), but the principle is the same everywhere: prose for guidance, configuration for enforcement.
Step 6: Test that the files load and agents follow them
Treat instruction files like any other configuration: lint them, then test behaviour. This script checks size limits, finds referenced paths that no longer exist, and confirms the Claude import is present:
#!/usr/bin/env bash
# scripts/check-agent-docs.sh : static checks for agent instruction files
set -euo pipefail
fail=0
# 1. Size: Claude Code suggests < 200 lines per file; Codex stops at 32 KiB combined by default
for f in AGENTS.md CLAUDE.md; do
if [ -f "$f" ] && [ "$(wc -l < "$f")" -gt 200 ]; then
echo "WARN $f has more than 200 lines"
fi
done
total=$(find . -name AGENTS.md -not -path './node_modules/*' -exec cat {} + | wc -c)
if [ "$total" -gt 32768 ]; then
echo "FAIL AGENTS.md files total $total bytes (> 32 KiB Codex default)"; fail=1
fi
# 2. Stale paths: every backticked src/, infra/, scripts/, migrations/ path must exist
for p in $(cat AGENTS.md CLAUDE.md .claude/rules/*.md 2>/dev/null \
| grep -oE '`(src|infra|scripts|migrations)/[^` *]+`' | tr -d '`' | sort -u); do
if [ ! -e "$p" ]; then echo "FAIL referenced path does not exist: $p"; fail=1; fi
done
# 3. Claude Code import present
if ! grep -q '^@AGENTS.md' CLAUDE.md 2>/dev/null; then
echo "FAIL CLAUDE.md does not import @AGENTS.md"; fail=1
fi
exit "$fail"
Then a behavioural smoke test. Claude Code's print mode runs one prompt non-interactively, which is enough to check that the instructions reached the model:
# Ask a question only the instruction file can answer; expect the exact command back.
claude -p "Which command runs a single unit test file in this repo? Reply with the command only." \
| grep -F 'pnpm test -- --run'
Expected output when the file loaded (the exact path will vary):
pnpm test -- --run src/billing/invoice.test.ts
For Codex, the docs suggest codex --ask-for-approval never "List the instruction sources you loaded.", and --cd services/payments to check nested overrides. Interactively in Claude Code, run /context and look under Memory files, or /memory for the full list. Recent versions also have /doctor prompt-audit (v2.1.283 or later), which reports contradictions and references to files that do not exist without changing anything.
The behavioural test costs tokens, so I would run it when instruction files change rather than on every commit. If you already run evals in CI, add a handful of questions like this to that suite; How to Run LLM Evals in CI shows the wiring.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
Claude Code ignores AGENTS.md entirely |
A CLAUDE.md, .claude/CLAUDE.md or CLAUDE.local.md exists on the path, so AGENTS.md is skipped by default |
Add @AGENTS.md to the CLAUDE.md, or set Project instructions to claude-md-and-agents-md |
| AGENTS.md not read on an older Claude Code | Native support needs v2.1.277; some Bedrock or no-telemetry sessions needed v2.1.281 | Run claude --version, update, or use the import |
| Instruction followed sometimes, not always | Vague wording, or two files contradict each other | Rewrite as a checkable command; search all levels and .claude/rules/ for conflicts; run /doctor prompt-audit |
Subdirectory CLAUDE.md seems ignored |
Subdirectory files load on demand, only after Claude touches a file there | Expect a Loaded line when it triggers; test by asking Claude to read a file in that directory |
| Codex misses nested AGENTS.md content | Combined size hit project_doc_max_bytes (32 KiB default), or an AGENTS.override.md shadows the file |
Trim files, or raise project_doc_max_bytes in ~/.codex/config.toml; check for override files |
| Cursor rule never applies | File is .md rather than .mdc, or globs do not match |
Rename to .mdc; check the pattern and alwaysApply value |
| Copilot code review ignores new instructions | Review reads instructions from the PR head branch | Commit the instruction change on the branch being reviewed |
| Agent still runs a forbidden command | Prose is guidance, not enforcement | Add a PreToolUse hook or a permission deny rule |
| Agent "forgets" rules late in a long session | Instructions buried under accumulated tool output | Start a fresh session or compact; move long procedures into skills so the core file stays short |
FAQ
Should I use AGENTS.md or CLAUDE.md?
Use AGENTS.md as the canonical file because Codex, Cursor, Copilot and most other agents read it, and add a two-line CLAUDE.md that imports it with @AGENTS.md. That keeps one source of truth and still gives you a place for Claude-only instructions.
How long should an AGENTS.md or CLAUDE.md be?
Short. Claude Code's docs suggest under 200 lines per file, Cursor suggests rules under 500 lines, and Codex stops reading at 32 KiB by default. The 2026 AGENTS.md study found that overviews added cost without improving results, so keep commands, unusual conventions and hard don'ts.
Is .cursorrules still supported?
Cursor's current rules docs describe .cursor/rules/*.mdc and AGENTS.md and do not cover .cursorrules. Claude Code's /init can still import an old .cursorrules. Migrate to .mdc or AGENTS.md rather than relying on the legacy file.
Does /init write a good CLAUDE.md?
It writes a reasonable starting point and suggests improvements if a file exists. Edit the result hard: delete anything the agent could discover from the code, since the AGENTS.md study found LLM-written overviews tended not to help. Keep the commands it found and add the rules only your team knows.
When an agent ignores an instruction in one of my repos, the first thing I check is whether the file loaded at all (/context in Claude Code), and the second is whether the rule was something that should have been a hook. In production I keep the instruction file under 100 lines, put anything destructive behind a hook or a sandbox, and run the static check in CI whenever the files change. The official references are the Claude Code memory docs, the Claude Code hooks guide, agents.md, the Codex AGENTS.md docs, Cursor rules and GitHub Copilot custom instructions.
Related: Coding Agents in 2026, Prompt Management in 2026 and How to Run an AI Coding Agent in GitHub Actions Safely (2026).
I'm Ajay Kumar — I build and operate PandaStack, an open-source Firecracker microVM cloud for AI agents, and write about the infrastructure and tooling around it.
Need this kind of infrastructure work? See what I do or email hello@ajayk.sh.
Related
How to Build an AWS VPC With Terraform: Public and Private Subnets (2026)
Build a 3-AZ AWS VPC in Terraform with terraform-aws-modules/vpc 6.7.3 and AWS provider 6.70: public and private subnets, NAT per AZ vs single vs regional, a free S3 gateway endpoint, flow logs, outputs, an SSM connectivity test and fixes for common errors.
16 minOct 31, 2026Best MCP Servers for DevOps in 2026: 7 Official Servers, Read-Only First
The official MCP servers worth connecting for DevOps work in late 2026: GitHub, Kubernetes, AWS, Terraform, Grafana, Sentry and Datadog. What each exposes, current versions, how to run them read-only, and the risks to plan for.
12 minOct 31, 2026How to Build a CI/CD Pipeline With GitHub Actions: Step-by-Step (2026)
Build a CI/CD pipeline with GitHub Actions from scratch: lint and test every pull request, Docker Buildx with the GHA cache, push to GHCR, staging and production environments with required reviewers, deploy by digest over SSH, concurrency, SHA-pinned actions and fixes for common errors.
18 min