Skip to content

Project instructions: AGENTS.md

In your first session you gave the agent context by hand, from the files that mattered to the test command and the branch to leave alone. In this lesson we write that context down once, in a file the agent reads at the start of every session. We also look at what belongs in that file and what doesn’t, and at what to do when a written rule isn’t enough.

You don’t run anything in this lesson. The examples are file contents, and the fixture is a small fictional project called invoice-mailer: a Python service that renders invoices to PDF and sends them over SMTP. You can reproduce every step in an empty directory with a text editor.

Most coding agents look for a Markdown file at the root of the repository and load it into their context before the first user message. The convention differs by tool: some look for AGENTS.md, some for CLAUDE.md, some for both. The content is the same either way, so the common pattern is to write AGENTS.md and make CLAUDE.md a symlink to it, or to have one contain one line pointing at the other.

The file is the briefing you would give a capable contractor on their first morning. They can read code. They can’t know which command your team runs before pushing, which directory is generated, or which obvious-looking fix has already been tried and reverted twice. That’s the gap the file fills.

Here is the smallest useful version for our fixture:

# invoice-mailer
Renders invoices to PDF and sends them over SMTP. Python 3.13, uv.
## Commands
- Test: `uv run pytest`
- Lint and format: `uv run ruff check . && uv run ruff format .`

An agent that reads these few lines runs the right test command on the first try instead of guessing between pytest, python -m pytest and make test. That alone pays for the file.

Everything in the file should be something the agent can’t work out from the code, or could work out but gets wrong often enough that you are tired of correcting it. In practice that’s four kinds of content.

Commands. How to install, test, lint, build, and run. One line each, with the exact invocation. If the project has a task runner, name it and say that the runner is the source of truth.

Structure. Where things live, at the level of directories, not files. Which directories are generated and must not be edited by hand. Where new code of each kind goes.

Conventions. The rules the code follows that a reader would not infer from one file: the commit message format, the branch naming scheme, the test naming scheme, and which style choices are deliberate.

Rules that remove a recurring mistake. This is the most valuable category and the hardest to write in advance. Every time the agent does the same wrong thing twice, add one line that stops it. “Don’t add retries around SMTP calls. The queue already retries” is a good rule. It is specific, it says what to do instead, and it exists because of a real incident.

Build one now. Tick what’s true for a project you know, fill in the short fields, and read the result as if you were the agent seeing it for the first time.

Tick what is true for your project and fill in the short fields. The file on the right updates as you type.

Commands
Rules
AGENTS.md

Notice how short the output is even with every box ticked. That’s the target. A real project’s file grows over time, but it grows one line per lesson learned, not one paragraph per feature.

Claude Code can write a first draft of the file with its /init command, from what it finds in the repository. Treat that draft as a list of candidates and delete every line the agent could have found itself. The vendor’s own advice matches the exercise at the end of this lesson: start a project without the file and add one line each time you have to correct the agent [1].

The failure mode of instruction files isn’t that they’re missing. It is that they’re long. Every line costs context on every turn of every session, and an agent given two pages of prose follows some of it and silently drops the rest.

Leave these out:

Anything the agent can read from the code. The list of dependencies is in the lockfile. The function signatures are in the source. The API routes are in the router. Pointing at the file (“routes are registered in app/routes.py”) is fine; copying its contents isn’t, because the copy goes stale and the agent then has two conflicting sources.

Long prose. Architecture essays, project history, the reasoning behind every decision. If the reasoning matters, put it in a design document and link to it. The agent reads it when the task calls for it.

Restating the obvious. “Write clean code.” “Follow best practices.” “Make sure tests pass.” A capable agent already does these, and the lines teach nothing about your project. They also dilute the lines that do.

Checkpoint · repair

This is the current AGENTS.md of invoice-mailer. The agent keeps running python -m pytest (wrong) and committing to main. It also wraps mail calls in retry loops. Rewrite the file so that each of those stops, and so that nothing in it restates what the agent could read from the repository.

A repository with more than one project in it needs more than one file. The tools handle this the same way: the agent always reads the file at the repository root, and it also reads a file in a subdirectory when it works on files under that directory. Closer wins on conflict.

That gives a natural split. The root file holds what’s true everywhere: the task runner, the commit convention, the branch rule. Each project’s file holds only what differs: its own test command, its own language, its own recurring mistakes.

repo/
AGENTS.md # task runner, commit format, branch rule
services/
invoice-mailer/
AGENTS.md # uv run pytest; no SMTP retries
web/
AGENTS.md # bun test; never edit generated/ by hand

Resist the urge to copy the root rules into each child file so that it reads standalone. The agent sees both; the copy only adds a second place to keep in sync.

Your personal preferences belong in neither file. Claude Code also reads a user-level CLAUDE.md from your home configuration directory, in every project and only for you. How you like a change explained or which shell you use goes there. The shared file then holds only what the whole team needs [1].

An instruction is a request. The agent reads it, usually follows it, and sometimes doesn’t, particularly late in a long session when the file has scrolled far back in its context. If a rule is one you can’t afford to have skipped even once, don’t rely on prose for it. A hook runs a command of yours at a fixed point in the agent’s loop, such as before a tool call or after an edit. When it runs before a tool call, it can block the action outright. For example, a hook that runs before every shell command, inspects the command the agent is about to run, and exits with code 2 when it matches git push to main means the push never happens, however far back the instruction file has scrolled [2]. “Never push to main” in AGENTS.md is advice. The hook enforces it. A hook that runs the formatter after every edit works the same way for a procedure the agent often forgets. The message a blocking hook prints goes back to the agent, so it learns why the action was refused and can change course instead of retrying. Hooks in the project’s shared settings file are committed with the code. Everyone who clones the repository gets the same enforcement without setting it up [1]. And when a rule isn’t a prohibition but a procedure, a multi-step thing the agent should do the same way every time, it is better packaged as a skill: a named, self-contained set of instructions the agent loads only when the task calls for it, so it doesn’t sit in every session’s context. The next lesson is about writing one.

Exercise

In an empty directory, create a throwaway project: any language, a test command that works, one source file. Run a coding agent in it and give it three small tasks without any instructions file. Note every time it guesses wrong (test command, file location, style, branch). Then write an AGENTS.md of at most fifteen lines that would have prevented each wrong guess. Delete the project’s git history and repeat the same three tasks.

A good result: the second run makes none of the wrong guesses from the first, and every line in your file traces back to one of them. If a line doesn’t, it is a candidate to delete.

Stretch: Now add one more rule that is enforced rather than advised: an agent hook that blocks the action, or a CI check that fails when the rule is broken, and remove the equivalent line from AGENTS.md.

Recap

  1. The agent reads AGENTS.md (or CLAUDE.md; same content, different tool convention) at the start of every session; it is the briefing for a capable contractor’s first morning.
  2. Put in it what the agent can’t read from the code: commands, structure, conventions, and one line for every mistake it keeps making.
  3. Leave out what the code already says, long prose, and rules that apply to every project on earth. Short files get followed; long ones get skimmed.
  4. In a monorepo, the root file holds what’s shared and each project’s file holds only what differs, and on conflict the closer file applies.
  5. A rule you can’t afford to have skipped belongs in a hook rather than in prose, and a procedure the agent should repeat belongs in a skill.

You can now

  • Writes instructions that remove a recurring agent mistake

  1. Anthropic. Claude Code 101. Claude Academy. Course. Academy claude-code-101
  2. Anthropic. Hooks reference. Claude Code documentation. Reference. Claude Code hooks