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.

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.
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.
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.
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.
Be ruthless. My current list:
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.
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 it | when it loads | use it for |
|---|---|---|
| root AGENTS.md or CLAUDE.md | every session | project one-liner, package manager, verify commands |
| a file named in prose (“see docs/testing.md”) | when the agent decides it is relevant | domain rules, conventions |
@import in CLAUDE.md | every session, expanded inline | organizing a large file, not saving context |
.claude/rules/*.md with paths globs | when the agent touches matching files | language and layer specific rules |
| nested AGENTS.md in a package | when working inside that package | monorepo package specifics |
| a skill | when the agent invokes it | multi-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.
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.
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.
One canonical AGENTS.md, thin adapters around it:
@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.read: AGENTS.md in .aider.conf.yml.{ "context": { "fileName": "AGENTS.md" } } in .gemini/settings.json.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.
Roughly an hour, in this order:
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.
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.