
Most repositories that have an AGENTS.md file use it for house style. Package manager, commit format, tabs or spaces, folders not to touch. That is worth doing and it removes a slice of the corrections a reviewer would otherwise write by hand.
The higher-value use is quality. An agent that writes a feature and then writes a test for it makes decisions you would not let a new engineer make unsupervised in their first week. Which command runs the suite. Whether a red test means the application broke or the test went stale. Whether it is acceptable to soften an assertion to get green. Those decisions get made silently on every task, and the repository is the only place you can settle them once instead of in every chat.
What the file is, and which agents read it
AGENTS.md is a plain markdown file at the root of a repository containing instructions for coding agents. There is no schema. The published format says as much: it is standard markdown, use whatever headings you like, the agent reads the text you wrote.
It is read natively by OpenAI Codex, Cursor, GitHub Copilot, Amp, Zed, Aider, Jules, Devin and a longer list that keeps growing, across more than 60,000 open-source repositories including projects like Apache Airflow. The reason it spread is unglamorous: every agent vendor had invented its own dotfile, and one filename most tools already read is worth more than a better format nobody reads.
Two mechanics matter in practice. First, nesting: you can put an AGENTS.md in a subdirectory, and the closest one to the file being edited wins. A monorepo can give its API package different testing instructions from its web app without either file getting long. Second, precedence: a direct instruction in the chat overrides the file. The file is the default, not a lock.
Claude Code reads CLAUDE.md. The common resolution is a one-line symlink, ln -s AGENTS.md CLAUDE.md, committed to the repository, so both filenames resolve to the same content and there is one file to edit. That is what we do in our own repositories.
How it differs from rules and skills
Three formats get confused because they all look like markdown telling an agent what to do. The distinction that matters is when they load.
AGENTS.md is always-on context. It is in the window for every task, whether the task touches tests or not. That is its value and its cost. Anything you write there is guaranteed to be seen, and anything you write there is paid for on every request.
Rules are conditional context. Cursor's .mdc files under .cursor/rules can attach to a glob, so a rule can apply only when a file under tests/ is open. .cursorrules, the older single file, is legacy and Cursor's own guidance points at the newer directory. Rules give you scoping that AGENTS.md cannot express, at the cost of being one vendor's format.
Skills are invoked procedures. A skill is a folder with a SKILL.md that the agent loads when it decides the task calls for it. Only a short description sits in context by default. Skills are the right home for a multi-step process: how to add a new end-to-end test to this repository, how to seed the database for a data-heavy flow, how to triage a failing CI run.
The split for testing writes itself. The contract goes in AGENTS.md, because it has to be true whether or not the agent thought about testing. The procedure goes in a skill, because it only matters once the agent has decided to write a test. A rule of thumb: if forgetting it produces a bad commit, it is contract; if forgetting it produces a slow one, it is procedure.
Why the contract belongs in the repository, not a console
Some testing platforms let you configure agent behaviour in their dashboard: policies, guardrails, prompt overrides. A repository file beats that for reasons that are structural rather than a matter of preference.
It versions with the code. When the auth fixture changes, the instruction about the auth fixture changes in the same commit, and a reviewer sees both. A console setting drifts from the codebase the moment either one moves, and nothing tells you it has.
It branches. A refactor that reorganises the test directory updates the contract on the branch, so the change lands when the refactor lands, not before.
It is reviewable. "Never edit an assertion to make a test pass" is a policy statement about your engineering standards, and it should go through review like any other one.
And it is portable. The same file governs whichever agent an engineer happens to be using, and it keeps working if they switch. A console setting governs the one vendor.
What belongs in the testing section
Five things, in roughly this order of value.
How to run the suite. The exact commands, including the one for a single file, and any setup the command does or does not do for you. Most wasted agent turns in a test task are spent discovering this. An agent that guesses npm test in a pnpm workspace burns two tool calls and sometimes starts a second dev server on a port that is already taken.
Where tests live and what shape they take. Directory, naming convention, one file per flow or per page, where fixtures and factories are. Without this, agents put tests in a new folder they invent, and you end up with three conventions.
Auth and fixture setup. This is the single most common reason an agent-written end-to-end test fails on the first run and then gets "fixed" in a way that makes it worse. State plainly how authentication works in tests, how to regenerate expired state, and that credentials never go in a test file.
Which flows are critical. Not all coverage is equal. Name the flows where a regression costs real money, and say what that implies: a change touching billing needs the checkout tests green locally before a pull request opens. This is the part that turns a style file into a quality gate.
What the agent must never do. The prohibitions earn their space more than anything else in the file, because the failure modes are specific and predictable. Editing an assertion to match broken behaviour. Adding test.skip to get a clean run. Inserting a fixed timeout to paper over a race. Deleting a test that has become inconvenient. Each of those is an agent doing exactly what you asked, faster than you can review it, in the direction that destroys the value of the suite.
One more line is worth its space: what to do when the agent cannot tell whether a failure is a real regression. The default behaviour is to pick one and proceed. The instruction you want is to stop and report both readings with the evidence.
A worked example
This is a testing section from a real shape of repository, a TypeScript web application with unit and end-to-end tests. It is about 250 words, which is roughly the right size.
## Testing
**Run it.** `pnpm test` runs unit tests (~40s). `pnpm test:e2e` runs
end-to-end tests against a local server, and starts that server itself,
so do not start one first. Single file: `pnpm test:e2e tests/checkout.spec.ts`.
**Where tests live.** Unit tests sit next to the source as `*.test.ts`.
End-to-end tests are in `tests/`, one file per user flow. Fixtures and
seeded accounts are in `tests/fixtures/`; read `tests/fixtures/README.md`
before adding a new one.
**Auth.** End-to-end tests reuse the storage state in `tests/.auth/`,
generated by `pnpm test:auth:setup`. A test that fails with a redirect
to `/login` has expired state: regenerate it, do not work around it.
Credentials never go in a test file.
**Critical flows.** Signup, checkout, subscription upgrade, invoice
export. Their tests are tagged `@critical`. Any change under
`src/billing/` requires checkout and upgrade to pass locally before a
pull request opens.
**Never:**
- Edit or weaken an assertion to make a failing test pass. Diagnose it.
If the application is wrong, fix the application or report it. If the
test is wrong, say why in the pull request body.
- Add `test.skip`, `.only`, or `waitForTimeout`.
- Delete a test. Removing coverage is a human decision.
- Mock the payment provider in an end-to-end test. Use the sandbox
account in `tests/fixtures/stripe.ts`.
**When a failure is ambiguous** (application bug or stale test), stop
and report both readings with the evidence rather than choosing one.Notice what is absent: no explanation of why testing matters, no testing philosophy, no catalogue of every package.json command. Every line either changes what the agent does or should be deleted.
Keeping it inside the context budget
Always-on context competes with the task. A 3,000-word AGENTS.md is loaded before the agent has read a single line of your code, and its instructions compete for attention with everything that follows. Long instruction files also degrade in a specific way: the middle stops being followed first, and you cannot tell from the outside.
Four habits keep it usable:
- Write the rule, not the rationale. "Never add
waitForTimeout" is followed. Two sentences about why fixed waits cause flakiness are not more followed. - Link out for depth. Point at
tests/fixtures/README.mdrather than restating it. The agent can open a file. - Push procedures into skills. If a section has numbered steps, it is a skill trying to escape.
- Nest instead of accumulating. A monorepo puts package-specific testing instructions in that package's
AGENTS.md, where they load only when relevant.
A practical ceiling for the whole file is around 500 words, with testing taking a third of it. If yours is longer, the parts that are not being followed are already invisible to you.
How to tell whether the agent is honouring it
Instructions in a file are not the same as behaviour, and the gap is easy to miss because both look like a green build.
Ask it to restate the rules. In a fresh session, ask what this repository's testing rules are before giving it a task. If the answer is generic, the file is not landing, and the usual cause is length or a filename the agent does not read.
Plant a canary. Add one specific, harmless, checkable instruction, for example that every new end-to-end test file opens with a one-line comment naming the flow it covers. Then look at the next few agent-authored files. A canary tells you the file is being read at all, which is the failure you cannot otherwise distinguish from the agent choosing to ignore a rule.
Grep the diff, not the repository. Before merging agent-authored work, check the diff for the prohibited patterns: test.skip, .only, waitForTimeout, and assertions changed inside a test file that the feature work should not have touched. That last one is the important signal. A pull request that modifies both src/billing/total.ts and the assertion in tests/checkout.spec.ts that was failing is the exact shape of the contract being broken.
Watch what happens on a genuinely broken build. Introduce a real regression on a scratch branch and hand it to the agent. Whether you get a diagnosis or a quietly adjusted test is the answer to whether the contract is real.
Where this fits with Shiplight
A contract in AGENTS.md sets the policy. It does not give the agent the ability to follow it. An agent told to diagnose a failure rather than edit the test still needs to see the application to do the diagnosis, and text-only agents cannot.
Shiplight for AI coding agents installs as a browser MCP server plus skills, so the agent walks the running application, writes end-to-end tests as readable YAML in your repository, and reproduces failures against the live UI. Because the tests are files, the same AGENTS.md rules that govern your source govern them. When Shiplight diagnoses a failing test in CI, a broken application produces a bug report rather than an edited test, which is the prohibition above enforced by the tool instead of trusted to the prompt.
Two limits worth stating. Authoring runs through the coding agent's own subscription and needs no Shiplight account, but executing a test file needs an LLM key, ours or your own. And it covers web applications, so native mobile and desktop are out of scope.
FAQ
What is AGENTS.md?
A plain markdown file at the root of a repository holding instructions for AI coding agents. It has no required schema, and it is read natively by Codex, Cursor, Copilot, Amp, Zed and many other tools, across more than 60,000 open-source projects. Nested files are supported, and the one closest to the edited file wins.
Do I need both AGENTS.md and CLAUDE.md?
You need the content once. Claude Code reads CLAUDE.md while most other agents read AGENTS.md, so the usual fix is a committed symlink from one to the other. Maintaining two files with the same content is how they drift.
What is the difference between AGENTS.md and a skill?
AGENTS.md is always-on context loaded for every task; a skill is a procedure the agent loads when it decides the task calls for it. Put the rules that must hold regardless of what the agent is doing in AGENTS.md, and put multi-step processes in a skill. See Agent Skills for the format.
How long should the testing section be?
Around 150 to 250 words. Write the rules and drop the rationale, link out to fixture documentation rather than restating it, and move anything with numbered steps into a skill. Long instruction files fail quietly in the middle, so length is a reliability problem before it is a cost problem.
What is the most important line to include?
The prohibition on editing a test to make it pass. It is the failure mode with the highest cost and the lowest visibility, because the result looks exactly like a fixed build. Pair it with an instruction to report both readings when a failure is ambiguous.
How do I check the agent is actually following it?
Plant one specific canary instruction and look for it in the next few agent-authored files, then grep merged diffs for test.skip, .only and assertions changed alongside the feature code that was failing. The strongest check is handing the agent a real regression on a scratch branch and seeing whether you get a diagnosis or a quietly softened test.


