What belongs in AGENTS.md, and what to move out

SAMI
August 29, 2026 9 mins to read
Share

My AGENTS.md was 340 lines. I know exactly how it got there. The agent did something I didn’t like, I added a rule, and I repeated that for a few months. Nobody ever deleted anything, and two of the rules contradicted each other.

That file goes into every session, before the first token of actual work. So it is worth about an hour of deliberate editing. Here is the method I use now, and the three mechanisms that explain why a fat file makes agents worse rather than better.

the file, in one minute

AGENTS.md is plain markdown at the root of a repository. It has no required fields and no schema: agents just read the text. It is an open format, stewarded by the Agentic AI Foundation under the Linux Foundation, and it appears in more than 60,000 public repositories. Codex, Cursor, Amp, Jules, Aider, goose, Zed, Warp, Gemini CLI and the GitHub Copilot coding agent all read it.

Claude Code is the one exception you will hit in practice. It reads CLAUDE.md, not AGENTS.md, and the feature request to support both is still open. I cover the workaround below.

three reasons a big file performs worse

the instruction budget

Kyle at HumanLayer put a number on this in writing a good CLAUDE.md, based on this instruction-following research: frontier thinking models follow roughly 150 to 200 instructions with reasonable consistency. Smaller and non-thinking models follow fewer, and degrade faster.

The detail that should worry you is how they degrade. Quality drops uniformly. The model does not politely ignore the instructions at the bottom of your file, it starts ignoring all of them a bit. HumanLayer counts about 50 instructions in Claude Code’s own system prompt, so a chunk of the budget is spent before your repository says anything.

Count instructions, not lines. A 40-line file with 35 imperatives is heavier than a 90-line file with 12.

the relevance filter

This is the part I wish I had known a year ago. HumanLayer proxied the Claude Code CLI and found that the file is injected with a system reminder telling the model the context may not be relevant and not to respond to it unless it is highly relevant to the task.

Your repository file is a suggestion the model is explicitly allowed to decline. And the more non-universal content it contains, the easier it is for the model to classify the whole thing as noise. Padding does not just cost tokens, it costs credibility for the lines that mattered.

staleness poisons

Documentation rots. A human reading a stale doc is skeptical. An agent reading it on every request is confident and wrong, and file paths rot fastest of all. If the file claims authentication lives in src/auth/handlers.ts and someone moved it last sprint, the agent will look there and then invent a story about what it found.

Anthropic’s own tooling now encodes this. The /doctor trim check in Claude Code (v2.1.206 and later) proposes cutting content the agent can derive from the codebase, such as directory layouts, dependency lists and architecture overviews, while keeping pitfalls, rationale and conventions that differ from tool defaults. That is a good filter to run by hand, whatever tool you use. Domain vocabulary is safer than structure. If “workspace” and “organization” mean different things in your product, document that, because the agent cannot guess it and it does not change every sprint.

what stays in the root file

Be ruthless. My current list:

  • one sentence on what the project is and who uses it, which acts as a role prompt for everything that follows
  • the package manager and runtime, if they are not the obvious default
  • the commands to verify a change (build, typecheck, test), if they are not standard
  • pitfalls that cost you a bad afternoon and that no amount of reading the code would reveal
  • short pointers to where the rest lives

That is close to everything. HumanLayer keeps their root file under 60 lines. The informal community ceiling is 300, and Anthropic’s docs note that files over 200 lines consume more context and may reduce adherence. Mine sits at 45 and I have not missed the other 295.

# AGENTS.md

Internal risk dashboard for the trading desk. Read-only against the
warehouse; never writes to production tables.

## Setup
- pnpm workspaces (not npm)
- `pnpm dev` runs the app and the mock warehouse together

## Verify before finishing
- `pnpm typecheck && pnpm test --filter <package>`

## Pitfalls
- `packages/pricing` runs on Node 20 only, the rest is on 22
- Dates in the warehouse are UTC, the UI renders Europe/Paris

For API conventions, see docs/api.md.
For test patterns, see docs/testing.md.

where everything else goes, and the import trap

The usual advice is to move rules into separate files and link to them. That is right, but the mechanism you pick decides whether you actually saved anything.

Claude Code supports @path/to/file imports. They look like progressive disclosure and they are not: the docs are explicit that imported files load at launch and enter the context window anyway. Splitting a monster file into imports makes it pleasant for humans to maintain and changes nothing for the agent. What actually reduces the load is path-scoped rules, .claude/rules/*.md with a paths frontmatter field of glob patterns, which load only when the agent touches matching files.

where you put itwhen it loadsuse it for
root AGENTS.md or CLAUDE.mdevery sessionproject one-liner, package manager, verify commands
a file named in prose (“see docs/testing.md”)when the agent decides it is relevantdomain rules, conventions
@import in CLAUDE.mdevery session, expanded inlineorganizing a large file, not saving context
.claude/rules/*.md with paths globswhen the agent touches matching fileslanguage and layer specific rules
nested AGENTS.md in a packagewhen working inside that packagemonorepo package specifics
a skillwhen the agent invokes itmulti-step procedures and workflows

One more rule from HumanLayer that I have adopted: prefer pointers to copies. Do not paste code snippets into these docs, they go stale within weeks. Reference file:line and let the agent read the authoritative version.

monorepos

You are not limited to one file. Every package can have its own, and agents.md states that the nearest file in the tree takes precedence, with explicit chat prompts overriding everything. The main OpenAI repository ships 88 of them.

Be careful here, because harnesses differ on whether nested files merge or override, and Claude Code reads memory files recursively up from the working directory. Do not assume, check what your tool actually loaded (/memory in Claude Code) before you build a nesting strategy on top of a guess.

Keep the root for what applies everywhere: what the monorepo is, how packages are laid out at the conceptual level, the shared tooling. Keep each package file for that package. Do not overload either.

do not send an agent to do a linter’s job

Code style guidelines are the single most common thing I see in these files, and they are the easiest deletion. Linters are faster, cheaper and deterministic. Biome, ESLint, Ruff and your formatter enforce quoting and semicolons perfectly for zero tokens.

Models are in-context learners. Given a few searches of your codebase, they follow the surrounding patterns without being told. If you want a guarantee, wire a Stop hook that runs the formatter and hands the errors back, or put the guidelines in a slash command you invoke on the diff. Either beats spending a third of your instruction budget on quote style.

keeping one file across tools

One canonical AGENTS.md, thin adapters around it:

  • Claude Code: create a CLAUDE.md containing @AGENTS.md. Imports nest up to five levels and are ignored inside code blocks. A symlink also works, but the import leaves room for the two or three Claude-specific lines you will inevitably want.
  • Aider: read: AGENTS.md in .aider.conf.yml.
  • Gemini CLI: { "context": { "fileName": "AGENTS.md" } } in .gemini/settings.json.
  • Migrating from an older name: mv AGENT.md AGENTS.md && ln -s AGENTS.md AGENT.md.

What you should not do is maintain the same rules in five files. They diverge within a month and you end up debugging which one the agent read.

the cleanup pass

Roughly an hour, in this order:

  1. Count the imperatives in your current file. That number, plus about 50 for the harness, is what you are asking the model to hold.
  2. Delete everything a linter or formatter already enforces.
  3. Delete everything the agent can derive by reading the repository: directory trees, dependency lists, architecture summaries.
  4. Find contradictions. Two developers added opposing rules six months apart and neither noticed. Decide which one you actually want.
  5. Group what survives by trigger. Ask when each rule matters. If the answer is not “every task”, it moves out to a scoped file.
  6. Rewrite the root file from scratch against the list above rather than editing the old one down. Editing down preserves the ball of mud.
  7. Run one real task and watch what the agent reads.

If you want to hand the first pass to the agent itself, this prompt works:

Refactor my AGENTS.md for progressive disclosure.

1. List every distinct instruction in the file, numbered.
2. Flag the ones a linter, formatter or type checker already enforces.
3. Flag the ones describing structure the repository already shows
   (file paths, directory trees, dependency lists).
4. Flag contradictions and ask me which version to keep.
5. Of what remains, mark each one: does it apply to every task in this
   repo, or only to a domain (tests, API, migrations, CI)?
6. Output a root file containing only the every-task items, plus one
   line pointing to each domain file, and the domain files themselves.
7. Do not add anything I did not write.

Point 7 matters. Left alone, the agent will helpfully reintroduce the generic advice you spent the hour removing.

the habit that keeps it small

Before adding a line, I ask which task it applies to. If the answer is not “all of them”, it does not go in the root file. That single question has done more for my agent output than any rule I ever wrote in it.

The counter-intuitive part is that this file is most useful when it is nearly empty. It exists to orient the agent, not to control it. Control comes from hooks, linters and tests, which do not degrade when you add the fifteenth one.

sources

Leave a comment

Your email address will not be published. Required fields are marked *