# Writing project instructions the agent reads every session

> Read two coding agent sessions on the same small repository, find the mistake the agent makes in both, fix it with one line in the project's instructions file, and keep later sessions short enough that the agent keeps following that file.

Page: https://schubergphilis.github.io/ai-training/coding-with-agents/project-instructions/
License: CC BY-SA 4.0, https://creativecommons.org/licenses/by-sa/4.0/

In this lesson we read two sessions a coding agent ran on the same small
repository and find the one mistake it made in both. We fix that mistake
once, with one line in the file the agent reads at the start of every
session. Then we start a fresh session and check that it follows the line
without being told. The last two sections are about keeping a session
lean enough that the agent keeps following the file, and about recording
a decision where the next session finds it.

The file is the project's **project instructions**, `AGENTS.md` or
`CLAUDE.md` at the root of the repository. How to write one from nothing,
and what belongs in it, is the subject of
[the customizing-agents lesson on AGENTS.md](https://schubergphilis.github.io/ai-training/customizing-agents/instructions/).
This lesson starts where that one stops: the file exists, and you are the
engineer who runs sessions against it and notices what it fails to say.

The file works because the agent grounds its work in what is in its
context, as [the retrieval lesson](https://schubergphilis.github.io/ai-training/concepts/retrieval/#grounding-and-what-it-doesnt-fix)
showed for a chat model. A rule in the instructions file is in the context of every
session. A correction you typed in an earlier session is not. Where this
lesson names a Claude Code feature it says so, and the vendor pages are
checked on the date at the end of the lesson.

## The file the agent reads first

The fixture is the to-do program from
[*Telling the agent where the task is and where it stops*](https://schubergphilis.github.io/ai-training/coding-with-agents/scoping-and-referencing/),
after its `undo` change. `docs/SPEC.md` now specifies
two more commands that nobody has built: `rename <n> <text>` and
`remove <n>`. The repository is in the course repository under
`site/examples/coding-with-agents/project-instructions/fixture-repo/`.
Copy that directory to a place of its own and change into it. Then give
the copy one commit, so that `git status` can show what a session changed:

```sh
git init -q && git add -A && git commit -qm start
```

Delete the copy and copy again to reset. Then read the instructions file.

#### Example: Read the instructions file

Print the file from inside the copy.

```sh
cat AGENTS.md
```

Output:

```text
# Agent instructions for todo

- Python 3, standard library only. No new dependencies.
- Tests use `unittest`. Run them with `python3 -m unittest -q`.
- `docs/SPEC.md` is the specification for the commands. Follow it.
- `legacy/` is the old single-file version, kept for reference. Never edit it
  and never import it.
- Do not edit `todos.json`; the tests use their own lists.
```

The file has five rules, and each is a fact the agent can't read from the
code. That is a good file by the measure of the customizing-agents lesson,
and it is short.

Most coding agents load this file before your first message. Claude Code
loads its instructions files at the start of every session, reads
`AGENTS.md` when the repository has no `CLAUDE.md`, and in an interactive
session prints a line that names the `AGENTS.md` it loaded
(How Claude remembers your project, Claude Code documentation). Its `/context` command shows what is in the
context window, so you can confirm the file is there
(Best practices for Claude Code, Claude Code documentation). Other agents have their own file names and
their own way to show it. With any agent you can check what it took from
the file by asking before the task starts, for example "What does the
instructions file say about `todos.json`?". An agent that quotes the last
rule has most likely read the file, and in Claude Code `/context` shows it
for certain.

An agent can have the file in its context and still do what the file was
meant to prevent. The sessions below show how.

## One mistake, two sessions

The course has the logs of two sessions on fresh copies of the fixture.
The first added `rename`, and the second added `remove`. Each had a short,
scoped brief and the verification command. The logs are in the course
repository, in `sessions/` next to `fixture-repo/`, so an agent that works
in your copy never reads them. They are illustrative: the author wrote
them to show what such sessions look like, and the course runs the program
to check every output line in them.

#### Example: Read the second session

Print the log without its header, from
`site/examples/coding-with-agents/project-instructions/` in the course
repository.

```sh
tail -n +4 sessions/session-2.txt
```

Output:

```text
you: Add the remove command that docs/SPEC.md specifies. Done when
     python3 -m unittest -q prints OK.

read AGENTS.md
read docs/SPEC.md
read todo.py
read test_todo.py
edit todo.py: add remove(items, number) after undo, and a remove branch
     in main after the undo branch
write test_remove.py
run python3 -m unittest -q
  OK
run python3 todo.py remove 3
  removed #3: Renew the passport
run python3 todo.py list
  1. [ ] Buy milk
  2. [x] Call the plumber
  3. [ ] Water the plants
  2 open, 1 done

agent: remove is in todo.py, with two tests in test_remove.py. The suite
     passes, and I ran the command against the list to confirm it works.
```

Each session on its own looks fine. The agent read the instructions first
and followed the spec, and its tests pass.
A mistake that repeats doesn't show in one session. It shows when you put
two next to each other and look for what they have in common. Start with
the commands the agent ran against the program.

#### Example: List what the agent ran in both sessions

Run this from `site/examples/coding-with-agents/project-instructions/` in
the course repository.

```sh
grep -H '^run python3 todo.py' sessions/*.txt
```

Output:

```text
sessions/session-1.txt:run python3 todo.py rename 1 "Buy oat milk"
sessions/session-1.txt:run python3 todo.py list
sessions/session-2.txt:run python3 todo.py remove 3
sessions/session-2.txt:run python3 todo.py list
```

In both sessions the agent tried the new command once by hand, which is a
good habit, and it ran the command with no `TODO_FILE`. `docs/SPEC.md` says the
program then reads and writes `todos.json` next to the scripts, the list
committed to the repository. `git status` at the end of each session shows
the result. The course replays both sessions on fresh copies and prints it.

#### Example: What each session left behind

The course applies each session's change to its own copy and runs every
command in the log the way the agent ran it. It fails if an output differs
from the log. Then it runs this in each copy.

```sh
git status --short
```

Output:

```text
session-1.txt
 M todo.py
 M todos.json
?? test_rename.py
session-2.txt
 M todo.py
 M todos.json
?? test_remove.py
```

`todos.json` changed in both sessions, and neither report mentions it.
Session 1 renamed an item in the committed list, and session 2 deleted
one. A reviewer who reads the diff catches it. The next session makes the
same mistake again, because nothing it loads says otherwise.

#### Checkpoint: Why didn't the rule stop it?

Both sessions read `AGENTS.md`, and both left `todos.json` changed. What
went wrong?

- The agent never loaded the instructions file in these two sessions.
- The rule is lost among the other lines, because the file is too long.
- The rule forbids editing the file, and the agent changed it by running the program.
- The test suite wrote to the file when the agent ran it after the change.

## Fix it once, in the file

A mistake the agent makes in two sessions is a fact about the project
that the instructions file doesn't state yet. What kind of fact belongs
there is in
[the customizing-agents lesson](https://schubergphilis.github.io/ai-training/customizing-agents/instructions/#what-belongs-in-it),
and this section is about when to add one. Claude Code's documentation
gives a similar trigger for its own instructions file: a mistake the agent
has made before, or a correction you already gave in an earlier session
(How Claude remembers your project, Claude Code documentation). The agent-engineering course says the same about
`AGENTS.md`: start small, and add a line when you see an agent repeat a
mistake (AGENTS.md: contents, monorepo hierarchies, with a builder widget, Agent Engineer Course).

A correction in the next brief fixes one session. The line in the file
reaches each session after it, including a teammate's, because the file is
in the repository. So the fix goes in the file, and it is one line.

The line needs to be specific enough that you can check the agent against
it. The existing rule says what not to do in words the agent read
narrowly. The fix names both ways the file changes and says what to do
instead. Claude Code's documentation ties how reliably the agent follows a
rule to how exact and short it is (How Claude remembers your project, Claude Code documentation). Replace the last line of `AGENTS.md` with
this one:

```md
- Never change `todos.json`, by hand or by running `todo.py`. To try a command, copy the list first: `cp todos.json /tmp/todos.json`, then run `TODO_FILE=/tmp/todos.json python3 todo.py ...`.
```

#### Checkpoint: Fix the rule

In another project, `seed.py` fills the database that `DATABASE_URL`
names with sample data, and `test.db` is a local database for trying
things. In two sessions the agent ran `seed.py` against the shared
database to "check the data", although `AGENTS.md` has the line below.
Rewrite the line so it names the action the agent took and what to run
instead.

```text
- Tests must not touch production data.
```

Commit the line. The next session starts from the committed file.

```sh
git commit -qam "docs: say how to try a command without changing todos.json"
```

Start a fresh session and give it the brief of session 2, word for word.
The brief says nothing about `todos.json`.

#### Prompt (illustrative, not a recorded transcript)

```text
Add the remove command that docs/SPEC.md specifies. Done when
python3 -m unittest -q prints OK.
```

#### Response

```text
I read `AGENTS.md`, `docs/SPEC.md`, `todo.py` and `test_todo.py`.

Added `remove(items, number)` to `todo.py` after `undo`, and a `remove`
branch in `main`. Added `test_remove.py` with two tests.
`python3 -m unittest -q` prints `OK`.

I tried the command on a copy of the list, as `AGENTS.md` says:
`cp todos.json /tmp/todos.json`, then
`TODO_FILE=/tmp/todos.json python3 todo.py remove 3`, which printed
`removed #3: Renew the passport`. `todos.json` is unchanged.
```

Like the logs, this exchange is illustrative, and your agent phrases it
differently. Check the repository, because the report is the agent's
account of what it did.

#### Example: What the fresh session left behind

The course commits the new line in its own copy, applies the change of
session 2, runs the command the way the new line says, and then runs
`git status`.

```sh
cp todos.json /tmp/todos.json
TODO_FILE=/tmp/todos.json python3 todo.py remove 3
git status --short
```

Output:

```text
removed #3: Renew the passport
 M todo.py
?? test_remove.py
```

The command still printed the message the spec asks for, and
`todos.json` is gone from the list of changed files. The brief was the same
as in session 2. The one thing that changed is a line in the file the
agent loads before the brief, and later sessions load that line too.

#### Pitfall: The file that grew a line per mistake

For a year, a team adds a line to its instructions file after each
mistake and never removes one. The file grows to three pages, some
of them about code that no longer exists and two that contradict each
other. The agent starts to break rules that are in the file, and the team
adds emphasis to those rules, which makes the file longer again. Claude
Code's documentation names this failure: a file that is too long gets
half its rules ignored, and in a long file, a rule the agent keeps
breaking is a sign the file needs pruning (Best practices for Claude Code, Claude Code documentation).
The agent-engineering course adds that a stale line misleads the agent
more than a missing one (AGENTS.md: contents, monorepo hierarchies, with a builder widget, Agent Engineer Course). The rule: each time you add a line,
delete the lines the agent gets right without them and the lines that no
longer describe the project.

## Keep the session lean

The instructions file is loaded once, at the start. What comes after it
in the session goes into the same context window: the files the agent
reads, the command outputs and your corrections. As that window fills, the
agent follows earlier instructions less well, and Claude Code's
documentation says so for its own tool (Best practices for Claude Code, Claude Code documentation). The
file you just fixed is in the context, and so are forty tool outputs after
it.

Context rot is the drop in how well the agent follows its instructions as
the context window fills. **Avoiding context rot** is keeping the context
lean so the agent keeps following its instructions and keeps the goal in
view. These habits keep a session lean.

- One task per session. When `rename` is done and committed, start a new
  session for `remove`. Claude Code has `/clear` for this, and its
  documentation advises clearing between unrelated tasks
  (Best practices for Claude Code, Claude Code documentation).
- Summaries instead of raw logs. Paste the three lines of a failing test
  that matter, or ask the agent for a short account of a long log.
- Point at files by path instead of pasting them. The agent reads a file
  when it needs it.
- When the agent ignores a rule it followed an hour ago, or you have
  corrected the same thing twice, compact or restart. Claude Code
  compacts the conversation on its own near the limit, and `/compact`
  with instructions does it when you choose. Its documentation advises a
  fresh session with a better prompt after two failed corrections
  (Best practices for Claude Code, Claude Code documentation).

The instructions file makes a restart cheap. Claude Code reads the root
instructions file from disk again after `/compact`, and an instruction you
gave only in the conversation can be lost in the summary
(How Claude remembers your project, Claude Code documentation). A rule in the file comes back in the next session.
A rule you typed in chat does not. Anthropic's course *Claude Code in
action* has a module on steering long sessions for more on this
(Claude Code in action, Claude Academy).

#### Checkpoint: The agent edits legacy/ again

What do you do?

- Tell it a third time, in capitals, that legacy/ is off limits.
- Paste the whole instructions file into the chat again.
- Add emphasis to every rule in the instructions file.
- Revert the edit, then start a fresh session with a brief that says what you learned.

## Record the decision where the agent reads it

The instructions file also holds the reasons behind the project's
structure, at least where to find them. Suppose the `remove` session
proposed moving the list from `todos.json` into an SQLite database, and
you said no: one JavaScript Object Notation (JSON) file keeps the program
to the standard library, and the diff of `todos.json` shows every change
in review. That reason is now in a transcript, and the next session that
finds the JSON file slow will propose the database again.

Write the decision down in the repository and point at it from the file.
One line in `AGENTS.md` is enough for the pointer:

```md
- The list stays one JSON file. Read `docs/decisions/` before you change how `store.py` saves it.
```

The last lesson of this part,
[*Staying the engineer who understands the system*](https://schubergphilis.github.io/ai-training/coding-with-agents/keeping-understanding/),
shows
the decisions folder and a decision file in full. The part that belongs
here is the direction: a decision you want every session to respect goes
in a file the session loads or is pointed at, because the transcript of
the session where you made it is in nobody's context.

#### Checkpoint: Where does the reason go?

Where should the decision and its reasons go?

- A decision file in the repository, with a line in the instructions file that points at it.
- The transcript of the session with the decision, linked from the next pull request.
- The agent's private memory on the engineer's own machine, where it keeps its notes.
- The engineer's next brief, which repeats the reason whenever the store comes up.

## Exercise

Run the two sessions yourself. Reset the copy of the fixture, start your
coding agent in it, and give it the brief of session 1 from
`sessions/session-1.txt`. When it is done, save its report and the output
of `git status --short`. Reset the copy, start a fresh session, and do the
same with the brief of session 2. Plan on fifteen minutes.

Put the two reports and the two status lists next to each other and find
the one thing that went wrong in both. It may be `todos.json`, as on this
page, or something else your agent does, such as a wrong test command or
a file it edits that the task didn't need. Write the one line that fixes
it, specific enough to check. Delete the copy and copy the fixture again.
Add or change the one line in its `AGENTS.md`, commit it with the command
above, then start a fresh session with the brief of session 2. Check
`git status --short` again.

A good result: the fresh session's status no longer shows the mistake,
the brief was word for word the one from before, and `AGENTS.md` is one
line different from the original. Delete the copy when you are done. Then
answer one question: if your agent made no mistake in both sessions, what
did you check to be sure, and what would you add to the file if a third
session made one?

Stretch: Do the same in a repository of your own. Read your last two agent sessions side by side, find one thing the agent got wrong in both, and fix it with one line in the instructions file. In the same edit, delete one line the agent gets right without it.

## Recap

1. The project instructions file is loaded at the start of every session, so a rule there reaches every later session, and a correction in the chat reaches one (How Claude remembers your project, Claude Code documentation).
2. A mistake that repeats shows when you put two sessions side by side. Fix it once, with one line in the file (AGENTS.md: contents, monorepo hierarchies, with a builder widget, Agent Engineer Course).
3. Write the line so you can check the agent against it: name the action the agent took and what to do instead.
4. A long file gets its rules ignored. When you add a line, delete the ones the agent no longer needs (Best practices for Claude Code, Claude Code documentation).
5. Keep the context lean: one task per session, summaries instead of raw logs, and compact or restart when the agent stops following rules it followed earlier.
6. Record a decision in the repository and point at it from the instructions file, because the next session never reads the transcript where you made it.

#### Habit

The next time you correct a coding agent, check whether you made the same correction in an earlier session, and if you did, put it in the instructions file as one line.

## References

- How Claude remembers your project, Claude Code documentation, https://code.claude.com/docs/en/memory
- Best practices for Claude Code, Claude Code documentation, https://code.claude.com/docs/en/best-practices
- AGENTS.md: contents, monorepo hierarchies, with a builder widget, Agent Engineer Course, https://lsimons.github.io/agent-engineer-course/15-agents-md/
- Claude Code in action, Claude Academy, https://academy.claude.com/courses/claude-code-in-action
