A coding agent starts every session knowing nothing about your project, so the repository has to answer its questions. This post describes a small set of files that give those answers, and argues that you should design them like an API: a few clear entry points that make the right context cheap to find.
The gist
Split what an agent needs to know into a few files by how fast each one changes, and make the agent's instruction file a short list of pointers to them.
- Keep stable knowledge and daily work in separate files. Principles, architecture and decision records change slowly. The task list changes every day. When they share a file, all of it looks out of date.
- Write down why each important decision was made, and which options you rejected. An agent that can't see the reason will try to "fix" the decision, and it will try again in every session.
- Keep
AGENTS.mdshort and make it point to the other files. The agent reads it at the start of every session, so every extra line costs space on every task. - Enforce the rules that matter with checks, not only with sentences. A lint rule, a test or a hook makes sure a rule is followed. The document explains why the rule exists.
- Add each file only when you need it. Start with a short
AGENTS.md, and add the others when the same problem appears twice.
Every session starts from zero
A human developer who joins a team learns the project slowly. They ask colleagues, they remember last week's discussion, and after a few months they know why things are the way they are. A coding agent does none of this. It starts each session with an empty context window (the text the model can see at one time), and everything it knows about your project must come from what it reads in that session.
So the agent does what a new developer would do on their first day, but every day: it reads files, searches the code and guesses. When the answer to its question is written down in a place it can find, it works well. When the answer is not written down, it guesses. When the answer is written down in five places that disagree, it picks one of them, and you cannot know which.
The code itself answers some questions. It says what the system does. It rarely says why it does it that way, what rules the team follows, or what the current work is. Those answers used to live in people's heads, in chat threads and in meetings. An agent reads none of them.
The mental model: an API for context
A repository used by AI (artificial intelligence) agents should be designed as an API (application programming interface) for context. A good API has a small number of well-named entry points, each one does one job, and you don't need to read the implementation to use it. The same rules work for the knowledge in a repository:
- Each file answers one question. "How do we think?", "How does the system work?", "Why did we choose this?", "How should an agent work here?", "What are we doing now?"
- There is one entry point. The agent always starts at the same file, and that file tells it where to go next.
- The entry point is small. It points to the other files; it doesn't copy them.
The goal is not more documentation. The goal is that the correct answer costs the agent one or two file reads, not a search through the whole repository. Anthropic's guide to context engineering says the same thing from the model's side: context is a limited resource, and good context engineering means "finding the smallest possible set of high-signal tokens" (the smallest amount of useful text) for the task[1].
Here is what that looks like during one task. The agent reads the entry point first, and it opens the other files only when the task needs them:
Stable knowledge and changing work
Before looking at each file, separate two kinds of information. They behave very differently, so they should never share a file.
- Stable knowledge changes slowly: the team's principles, the shape of the system, and the reasons behind big decisions (kept in Architecture Decision Records, or ADRs). It can stay correct for months or years.
- Changing work changes every day: what to build next, what is half done, what "done" means for this feature.
When a file mixes the two, the fast-changing part makes the slow-changing part look out of date, and readers stop trusting all of it. A task list inside the architecture document is out of date by Friday, and the agent cannot tell which lines are still true.
| File | Question it answers | How often it changes | Kind |
|---|---|---|---|
PRINCIPLES.md | How do we think? | Stable knowledge | |
docs/decisions/ (ADRs) | Why did we choose it? | Stable knowledge | |
ARCHITECTURE.md | How does the system work? | Stable knowledge | |
AGENTS.md | How should an agent work here? | Entry point | |
TASKS.md | What do we do now? | Changing work |
The baseline layout
Five files at the root and one folder of decision records are enough for most projects:
/
├── AGENTS.md
├── ARCHITECTURE.md
├── PRINCIPLES.md
├── TASKS.md
├── DECISIONS.md
└── docs/
└── decisions/
├── 001-use-react-query.md
├── 002-modal-stack-model.md
└── ...
The files depend on each other in one direction. Principles shape the architecture and the agent's rules. Decisions explain the architecture. The architecture tells the agent what it must respect. And the agent's rules shape how it does the current task:
The sections below follow the same order, from the most stable file to the least stable one.
PRINCIPLES.md: how we think
PRINCIPLES.md holds the engineering beliefs behind the project. These are the rules you would still follow if you rewrote the whole system in a different framework. Typical examples:
- Simplicity. Prefer the boring solution; add a dependency only when it removes more code than it adds.
- Composition. Build big components from small ones; don't add options to one large component.
- Accessibility. Every interactive element works with a keyboard and a screen reader.
- Testing. Test behaviour through the public interface, not the internal details.
- Consistency. A second way to do something needs a good reason; "I prefer it" is not one.
Principles are what an agent uses when no rule covers the case. An agent that knows "we prefer composition" makes a better choice in a situation nobody predicted than an agent with a hundred specific rules and none that apply.
Keep the file short, and make each principle something you could break. "Write good code" is not a principle, because no one would disagree with it. "Prefer duplication over the wrong abstraction" (Sandi Metz's rule) is one, because a reasonable team could choose the opposite.
ARCHITECTURE.md: how the system works
ARCHITECTURE.md describes the structure of the system at the level where an agent can make a mistake that tests will not catch. It covers:
- Modules — the main parts, and what each one is responsible for.
- Boundaries — which parts may import which other parts, and which may not.
- Dependencies — the libraries that carry the most weight, and what they are used for.
- Data flow — how data enters, moves through and leaves the system.
- Core concepts — the few ideas you must understand to read the code, such as "every modal goes through the modal stack".
This file describes the system as it is now. It does not explain history. When a reader asks "why is it like this?", the file points to the decision record that answers it. That keeps the file short, and it keeps each fact in one place.
ADRs: why we chose it
An ADR (Architecture Decision Record) is a short document that records one important decision: the situation, what was decided, the options that were rejected, and what follows from the choice. Michael Nygard proposed the format in 2011 with four sections: context, decision, status and consequences[2]. Many teams add a fifth, the options that were rejected, and for agents it is the most useful one. I have written about ADRs before. Each record is one numbered file in docs/decisions/:
# 002. Modal stack model
Status: Accepted (2026-03-14)
## Context
Several features open modals on top of other modals. Each feature
managed its own open/closed state, and closing one modal sometimes
closed the wrong one.
## Decision
All modals go through a single stack (`useModalStack`). Components
push and pop entries; nothing renders a modal directly.
## Alternatives rejected
- One boolean per modal: simple, but it cannot express order.
- A routing-based approach (a URL per modal): good for deep links,
but it breaks modals that hold unsaved form state.
## Consequences
- The Escape key and focus return work the same way everywhere.
- Opening a modal outside React components needs the stack's
imperative API.
ADRs matter more with agents than they did with humans alone. Nygard described what happens when a team doesn't know why a decision was made: people either "blindly accept the decision" or "blindly change it"[2]. An agent tends to do the second. It sees a pattern that looks more complex than necessary, it knows a simpler one, and it "improves" the code. Without the historical reasoning, an agent will keep trying to fix a deliberate trade-off, and every session can make the same mistake again.
The "Alternatives rejected" section is the part that prevents this. When the agent thinks "one boolean per modal would be simpler", it finds that exact idea in the record, with the reason it was dropped. The question is answered before the agent writes any code, and you don't have to review and reject the same change a third time.
AGENTS.md: the entry point
AGENTS.md is an open format for instructions to coding agents; its own site calls it "a README for agents"[3]. It tells an agent how to work in this repository:
- Commands — how to install, build, test and lint.
- Rules — what the agent must never do, such as editing generated files or skipping hooks.
- Conventions — naming, file layout and commit messages.
- Workflow — the order of work, for example "run the tests before you open a pull request".
- Pointers — which file holds the answer to which kind of question.
AGENTS.md should stay small: it is the router for context, not the place where all the knowledge lives. The pointers are the most important part. Instead of copying the architecture into the file, tell the agent when to read it:
Before modifying architecture:
- Read ARCHITECTURE.md
- Respect PRINCIPLES.md
- Check relevant ADRs
- Update documentation if architecture changes
There is a practical reason for this. The agent reads AGENTS.md at the start of every session, for every task, so every line in it costs context each time, even when the task doesn't need it. The Claude Code documentation recommends keeping its equivalent file under 200 lines, because "longer files consume more context and reduce adherence"[4]: the agent follows a long file less reliably. A file that only routes can stay small, and the detailed files are read only when a task needs them.
TASKS.md: what to do now
TASKS.md holds the current state of work: what needs doing, in what order, what is in progress, and how you will know each item is finished. It is the only file in this set that is meant to change every day.
The most useful part of a task entry is its acceptance criteria: the checks that decide when the task is done. An agent is good at producing code and bad at knowing when to stop. "Add animation to the modal" can mean ten different things. "Fade in over 150 ms, no animation when the user prefers reduced motion, focus moves to the first field when the animation ends" means one.
When a project grows, one file becomes too long. Then TASKS.md becomes a folder, with one file per task:
tasks/
├── active/
│ └── modal-animation.md
├── backlog/
└── done/
A task moves from folder to folder as its state changes:
Each task file then holds its own context: the goal, the acceptance criteria, the constraints ("don't change the public API of the modal stack"), links to the ADRs it touches, and implementation notes that the agent adds while it works. That last part is useful. When a session ends in the middle of a task, the next session reads the notes and continues from where the previous one stopped.
Six improvements to the baseline
The layout above works as it is. After using it on real projects, I would change six things.
DECISIONS.md is only an index
Don't write decisions in DECISIONS.md. Use it as a table of contents for docs/decisions/: one line per ADR with its number, title, status and a one-sentence summary. The agent scans the index, then opens only the one or two records that matter. Without the index, the agent has to open every record to find the right one, which is exactly the expensive search this design tries to avoid.
Never rewrite an accepted ADR; replace it
A decision record is history. When the team changes its mind, write a new ADR. In the old one, change only the status line, to "Superseded by 007". Nygard's original format already has this status[2]. If you rewrite the old record instead, the agent loses the reason the old option failed, and that reason is often the most useful part.
Keep one instructions file for every tool
Many tools have their own instructions file: CLAUDE.md for Claude Code, and other names for other agents. Don't keep two copies of the same rules; they will slowly become different. Put the rules in AGENTS.md, and make the tool-specific file point to it. In Claude Code, a CLAUDE.md that contains the line @AGENTS.md imports the whole file[4].
Put small AGENTS.md files next to the code
In a monorepo (one repository that holds many packages), one root file cannot describe every package without becoming large. Add a short AGENTS.md inside each package. Agents read the nearest file in the directory tree, so the closest one wins[3]. The root file keeps the rules that apply everywhere, and each package file adds only its own commands and rules.
Turn the rules that matter into checks
A sentence in AGENTS.md is a request; the agent may not follow it. If breaking a rule causes real damage, don't only write it down: enforce it with a lint rule, a test, a hook or a CI (continuous integration) check. For example, "the user interface (UI) package must not import from the data package" belongs in a lint rule that fails the build. The document then explains why the rule exists, and the check makes sure it is followed. I covered this move from written rules to enforced ones in Customizing Claude Code.
Decide where tasks live
TASKS.md competes with the issue tracker you already use. Both are reasonable; what is not reasonable is keeping the same task in both places.
| Tasks in the repository | Tasks in an issue tracker | |
|---|---|---|
| Agent can read it without extra tools | ||
| Changes reviewed with the code, in the same pull request | ||
| Visible to people who don't use the repository | ||
| Works for a team with product managers and support staff |
For a solo project or a small team of developers, tasks in the repository are simpler. For a bigger team, keep the tracker as the list of tasks, and give each active task a file in the repository that holds the context and notes the agent needs.
Signs the design is failing
This design fails in predictable ways. Watch for these:
- The entry point keeps growing. Every time the agent makes a mistake, someone adds a line to
AGENTS.md. After six months it has 600 lines and the agent follows less of it. Move each detail to the file where it belongs and leave a pointer. - The same fact lives in two files. One copy gets updated and the other does not. Now the agent has two answers and will pick one of them. Each fact should have one home; the other files link to it.
- Documents are out of date. An out-of-date architecture document is worse than none, because the agent trusts it. Put "update documentation if architecture changes" in the workflow, and check it in code review.
- Documentation for its own sake. A file that no task ever needs is not free: someone has to keep it correct. If you cannot say which question a file answers, delete it.
Where to start
You don't need all of this on day one. Add each file when you feel the lack of it, in this order:
- Write a short
AGENTS.mdwith the commands and the three or four rules the agent breaks most often. - Write an ADR the next time you reject an agent's "improvement" for the second time. That repeated rejection shows a decision the agent cannot see.
- Write
ARCHITECTURE.mdwhen you notice you explain the same module boundaries in every task. - Add
PRINCIPLES.mdwhen you find yourself correcting the agent's judgement, not its facts. - Add
TASKS.mdwhen work regularly spans more than one session.
Each step solves a problem you have already had. That is the real test of this design: the goal is not to write more documentation, but to make the correct context cheap to find, so the agent doesn't rediscover or contradict decisions you have already made.
