Writing project instructions the agent reads every session
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.
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 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
Section titled “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,
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:
git init -q && git add -A && git commit -qm startDelete the copy and copy again to reset. Then read the instructions file.
Read the instructions file
Section titled “Read the instructions file”Print the file from inside the copy.
cat AGENTS.md# 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.
Output verified in CI from site/examples/coding-with-agents/project-instructions/instructions.py.
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
[1]. Its /context command shows what is in the
context window, so you can confirm the file is there
[2]. 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
Section titled “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.
Read the second session
Section titled “Read the second session”Print the log without its header, from
site/examples/coding-with-agents/project-instructions/ in the course
repository.
tail -n +4 sessions/session-2.txtyou: 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.Output verified in CI from site/examples/coding-with-agents/project-instructions/log.py.
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.
List what the agent ran in both sessions
Section titled “List what the agent ran in both sessions”Run this from site/examples/coding-with-agents/project-instructions/ in
the course repository.
grep -H '^run python3 todo.py' sessions/*.txtsessions/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
Output verified in CI from site/examples/coding-with-agents/project-instructions/repeated.py.
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.
What each session left behind
Section titled “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.
git status --shortsession-1.txt M todo.py M todos.json ?? test_rename.py session-2.txt M todo.py M todos.json ?? test_remove.py
Output verified in CI from site/examples/coding-with-agents/project-instructions/replay.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.
Why didn't the rule stop it?
Section titled “Why didn't the rule stop it?”A small repository has an eight-line instructions file whose last rule is 'Do not edit todos.json; the tests use their own lists.' In two sessions a coding agent read that file first and added a command to the program, and in each session the committed todos.json changed.
Both sessions read AGENTS.md, and both left todos.json changed. What
went wrong?
What does the rule forbid, and what did the agent do to the file?
Fix it once, in the file
Section titled “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,
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
[1]. The agent-engineering course says the same about
AGENTS.md: start small, and add a line when you see an agent repeat a
mistake [3].
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 [1]. Replace the last line of AGENTS.md with
this one:
- 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 ...`.Fix the rule
Section titled “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.
- Run `seed.py` only as `DATABASE_URL=test.db python3 seed.py`, and never point `DATABASE_URL` at the shared database.
What did the agent do that the rule doesn't name, and what should it do instead?
Commit the line. The next session starts from the committed file.
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.
Add the remove command that docs/SPEC.md specifies. Done when python3 -m unittest -q prints OK.
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.
What the fresh session left behind
Section titled “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.
cp todos.json /tmp/todos.jsonTODO_FILE=/tmp/todos.json python3 todo.py remove 3git status --shortremoved #3: Renew the passport M todo.py ?? test_remove.py
Output verified in CI from site/examples/coding-with-agents/project-instructions/fresh.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.
Keep the session lean
Section titled “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 [2]. 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
renameis done and committed, start a new session forremove. Claude Code has/clearfor this, and its documentation advises clearing between unrelated tasks [2]. - 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
/compactwith instructions does it when you choose. Its documentation advises a fresh session with a better prompt after two failed corrections [2].
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
[1]. 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
[4].
The agent edits legacy/ again
Section titled “The agent edits legacy/ again”An engineer has worked with a coding agent in one session for two hours, on three unrelated tasks. The project's instructions file says legacy/ is never edited. The agent just edited a file in legacy/, and the engineer has already corrected the same thing twice in this session.
What do you do?
What has changed since the start of the session, when the agent followed the rule?
Record the decision where the agent reads it
Section titled “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:
- The list stays one JSON file. Read `docs/decisions/` before you change how `store.py` saves it.The next lesson, Staying the engineer who understands the system, 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.
Where does the reason go?
Section titled “Where does the reason go?”An engineer and a coding agent agreed in a session to keep a program's data in one JSON file instead of a database, for two reasons the engineer explained. The engineer wants every later session, including a teammate's, to respect the decision.
Where should the decision and its reasons go?
Which of these does a teammate's fresh session load or get pointed at?
Which responses fix the repeated mistake?
Section titled “Which responses fix the repeated mistake?”A coding agent made the same mistake in two sessions on one repository, and the engineer is choosing what to do about it. The repository has a short instructions file that the agent loads at the start of every session. The file already has the rule 'Do not edit todos.json', and in both sessions the agent changed todos.json by running the program to try a command.
Which of these fix the mistake for every later session?
Which of these reach the next session, and are specific enough to check?
Lean session or longer context?
Section titled “Lean session or longer context?”A coding agent session loads the project's instructions file at its start. What comes after that, the files it reads, command outputs and the engineer's messages, goes into the same context window, and as the window fills the agent follows its earlier instructions less well.
Sort each step by what it does to the agent’s context.
Does the step add text to the session that the task doesn't need?
Will the next session know about the JSON file?
Section titled “Will the next session know about the JSON file?”In a small to-do program, the engineer decided in one agent session to keep the list in one JSON file and not move it to an SQLite database. A fresh coding agent session loads the project's instructions file at its start and reads the files in the repository it needs or is pointed at.
Sort each place someone might keep the reason for the JSON file.
Is the reason in a file the fresh session loads, or in one it is pointed at?
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
- 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 [1].
- A mistake that repeats shows when you put two sessions side by side. Fix it once, with one line in the file [3].
- Write the line so you can check the agent against it: name the action the agent took and what to do instead.
- A long file gets its rules ignored. When you add a line, delete the ones the agent no longer needs [2].
- 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.
- 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.
You can now
- Gives the agent the files, constraints and limits the task needs
- Keeps their own understanding of the code as the agent produces more of it
References
Section titled “References”- Anthropic. How Claude remembers your project. Claude Code documentation. Reference.
Claude Code memory - Anthropic. Best practices for Claude Code. Claude Code documentation. Reference.
Claude Code best practices - Addy Osmani, Ivar Soares Urdalen, Leo Simons. AGENTS.md: contents, monorepo hierarchies, with a builder widget. Agent Engineer Course. Course.
AEC-15 - Anthropic. Claude Code in action. Claude Academy. Course.
Academy claude-code-in-action