# Reading what the agent remembers

> Read the auto-memory notes a coding agent keeps for a project, delete the two that have gone stale, and move a team fact into a context file that the instruction file imports.

Page: https://schubergphilis.github.io/ai-training/customizing-agents/memory-review/
License: CC BY-SA 4.0, https://creativecommons.org/licenses/by-sa/4.0/

In this lesson we read the notes a coding agent keeps for itself and
clean them up. The notes belong to the to-do project from earlier lessons,
and four of them are planted for you: one is still right, two have gone
stale, and one holds a fact the whole team should have. You delete the
stale two and move the team fact into a file in the repository, where
it is versioned and reviewed like code. On the way you meet the import
syntax that pulls such a file into the agent's instruction file.

Where the notes are kept, what loads when, and the import syntax are
Claude Code's, checked against the vendor's documentation on the date at
the end of the lesson (How Claude remembers your project, Claude Code documentation). Other coding agents keep
notes under other names and in other places. The review works the same
way there.

## Where the notes are

**Auto-memory** is the set of notes an agent writes for itself in one
session and reads again in later ones. Claude Code's version is called
auto memory, and it is switched on unless you turn it off. The agent
picks what to save: your corrections, your preferences, and facts about
the project that the code doesn't show. The instruction file, `CLAUDE.md`
or `AGENTS.md`, is the other kind of memory, and a person writes that
one. A new session starts with both in its context window. To the model
they are text like your own messages, and Claude Code doesn't enforce
anything they say (How Claude remembers your project, Claude Code documentation).

In Claude Code the notes for a project are in
`~/.claude/projects/<project>/memory/`. The `<project>` part comes from
the git repository, so two worktrees of one repository, or two of its
subfolders, read and write the same notes. The folder is on your own
machine. A colleague who clones the repository has a folder of their
own, with their own notes (How Claude remembers your project, Claude Code documentation).

The folder holds an index file, `MEMORY.md`, with a line for each note,
and next to it one Markdown file per note, which the vendor calls a topic
file. A header at the top of each topic file has a `type` field that says
what kind of note it is. There are four values: `user` (who you are and
how you like to work), `feedback` (a correction you made), `project`
(work in progress, deadlines and decisions) and `reference` (a pointer to
a tracker or a dashboard outside the repository) (How Claude remembers your project, Claude Code documentation).

At launch the session reads the start of the index file and no other
file from the folder. The start is the first 200 lines, or fewer when
those lines are more than 25KB. A topic file stays on disk until the
work calls for it and the agent opens it (How Claude remembers your project, Claude Code documentation)
(Explore the context window, Claude Code documentation). So the index line is what every session
sees, and a wrong index line is wrong in every session.

The planted notes are in the course repository at
`site/examples/customizing-agents/memory-review/notes/`. The program
`startup.py` next to that folder applies the loading rule to them. Its
complete source is in the same folder.

#### Example: What a session starts with

Run this from `site/examples/customizing-agents/memory-review/`, and
compare what you see with the output below.

```sh
python3 startup.py
```

Output:

```text
loaded at start: MEMORY.md, 4 of 4 lines
read when needed: project_done_rewrite.md (project)
read when needed: project_item_length.md (project)
read when needed: project_tests_touch_data.md (project)
read when needed: user_diff_first.md (user)
```

The index is short, so all of it loads. Here it is, as every session in
the project sees it:

```markdown
- [Diff first](user_diff_first.md) — show the diff before explaining a change
- [done is being rewritten](project_done_rewrite.md) — leave done() alone; the rewrite is on the done-v2 branch
- [Tests touch the data](project_tests_touch_data.md) — back up todos.json before a test run and restore it after
- [Item length](project_item_length.md) — keep item text at 80 characters or fewer for the phone widget
```

Now put the notes where an agent reads them. Make a fresh copy of the
fixture directory,
`site/examples/coding-with-agents/first-session/fixture-repo/`, outside
the course repository, change into it, and give it a first commit, as in
the earlier lessons of this course. Put the copy in a folder with no
`CLAUDE.md` in it or above it, such as your home folder. The last step of
the lesson needs the agent to read the copy's `AGENTS.md`, and a
`CLAUDE.md` above the copy stops that (How Claude remembers your project, Claude Code documentation).

```sh
git init -q && git add -A && git commit -q -m "fixture"
```

Then copy the planted notes to a folder of their own in your home
folder. Replace `<course>` with the path of your copy of the course
repository. The same command puts the four notes back if you try the
lesson a second time.

```sh
mkdir -p ~/memory-review-notes && cp <course>/site/examples/customizing-agents/memory-review/notes/*.md ~/memory-review-notes/
```

Claude Code's `autoMemoryDirectory` setting points auto memory at a
folder you pick, written as a full path or as a path that starts with
`~/`, and the `--settings` flag may set it (How Claude remembers your project, Claude Code documentation). A key
you pass with `--settings` as inline JSON counts for that session only,
and Claude Code writes it to no file (Settings files and precedence, Claude Code documentation). So this
command starts the agent in your copy with the planted notes as its
memory, and your own memory folders stay as they are:

```sh
claude --settings '{"autoMemoryDirectory": "~/memory-review-notes"}'
```

Type `/memory` to see the memory files the session knows about. The
list also has an option that opens the auto memory folder
(How Claude remembers your project, Claude Code documentation). For this lesson, open `~/memory-review-notes` in
your editor yourself and read the four topic files. Then ask the agent
what the notes mean for a task, before it does any work.

```text
Before you change anything: if I ask you to fix the bug in the done
command, which of your memory notes apply? Quote each one and say what
you would do because of it.
```

The answer below is illustrative, written for this page and not recorded
from a model. Yours differs in wording.

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

```text
Before you change anything: if I ask you to fix the bug in the done
command, which of your memory notes apply? Quote each one and say what
you would do because of it.
```

#### Response

````text
```text
Three notes apply.

- "Leave done() alone; the rewrite is on the done-v2 branch." I would not change done() on this branch. I would tell you the fix belongs in done-v2 and wait.
- "Back up todos.json before a test run and restore it after." Before running the tests I would copy todos.json to todos.json.bak, and copy it back after.
- "Show the diff before explaining a change." If you tell me to go ahead anyway, I will show the diff first.
```
````

The agent says all of this with the same confidence. It can't see from
its window that two of the three facts stopped being true.

## Delete what has gone stale

A remembered fact doesn't warn you when it goes out of date. Long-term
notes need updating as the world changes (Memory and context: context engineering, memory kinds, memory versus RAG, context rot, Agent Engineer Course), and nothing in the
feature does that for you. The index line is in the window at the start
of every session, and the model reads it as context like anything else
there. A note that was right in June and wrong in September is applied
in September as firmly as in June, in every session, until someone edits
it. Claude Code's cleanup of old session transcripts leaves the memory
folder alone, so a note doesn't expire by itself (How Claude remembers your project, Claude Code documentation).

So check each note against the thing it describes. The two `project`
notes about `done()` and the tests make claims the copy can confirm or
contradict. Leave the session open, and run the shell commands from here
on in a second terminal in your copy. The rewrite note names a branch.

```sh
git branch --list done-v2
```

The command prints nothing: there is no `done-v2` branch, and the rewrite
the note waits for isn't happening here. The test note says the tests
write `todos.json`.

```sh
grep -c todos.json test_todo.py
```

It prints `0`. The tests build their items as lists and never open the
file, and `AGENTS.md` says not to edit `todos.json`. Both
notes were true once, before plans changed, and both now make the agent
do the wrong thing. One makes it refuse a bug fix, and the other makes it
copy a file the instructions say to leave alone.

Delete both topic files in `~/memory-review-notes`:

```sh
rm ~/memory-review-notes/project_done_rewrite.md ~/memory-review-notes/project_tests_touch_data.md
```

Then open `~/memory-review-notes/MEMORY.md` in your editor and delete
the two lines that point at those files. The notes are ordinary Markdown
files, and the vendor says you may read and change them by hand
(How Claude remembers your project, Claude Code documentation). Remove the index line too, since the index is the
part that loads.

#### Pitfall: The note that skipped the tests

A team's test suite once took ten minutes, because it ran against a
shared database. A developer told the agent to run only the test for the
function it changed, and the agent saved that as a memory note. Months
later the tests used an in-memory database and finished in two seconds,
and nobody edited the note. The agent kept running one test per change,
and a change to one command broke another command's test. Any note that
lets the agent skip a check deserves a check of its own at every review,
and a date inside the note tells a reviewer how old the claim is.

#### Checkpoint: Why does the old note win?

Your agent refuses to fix a bug in `done()` and quotes a memory note:
"the rewrite is on the done-v2 branch". That branch was deleted weeks
ago. Why does the agent still follow the note?

- The model learned the note in an earlier session, and its weights still hold the rewrite plan.
- Notes in auto memory outrank the instruction file, so the agent has to follow them.
- The note is loaded as context in every session, and nothing in the window says it is out of date.
- The agent listed the branches, found done-v2 still open, and decided to wait for it.

## Move a team fact into a context file

The diff note and the item length note are left. "Show the diff before
explaining a change" is one person's working preference, and a personal
note is what auto memory is for. "Keep item text at 80 characters or
fewer" is different. It is a decision about the product, because the
phone widget cuts longer text for everyone. Each person on the team
needs it in each session, on each machine. In auto memory it reaches
only the agent on this one machine, and nobody reviews it.

**Context files** are the files a person keeps for the agent to read:
project instructions, design notes, a plan, a glossary. They are in the
repository, so a change to one is a commit that someone can review, and
every clone has the same text. The team fact belongs in one. The fixture
has an `AGENTS.md`, and neither the copy nor a folder above it has a
`CLAUDE.md`. In that case Claude Code, from version 2.1.277, reads
`AGENTS.md` as the project's instructions (How Claude remembers your project, Claude Code documentation).
You could add the rule to `AGENTS.md` directly. For a decision that has a
reason and a date, a notes file of its own keeps `AGENTS.md` short, and
the import syntax loads it with `AGENTS.md`.

The import syntax is an `@` sign directly in front of a path. A line in
`AGENTS.md` that ends in `@docs/decisions.md` puts the whole of
`docs/decisions.md` into the session's context at launch, next to
`AGENTS.md` itself. A path that doesn't start with `/` starts from the
folder of the file that contains it. So an `@glossary.md` inside
`docs/decisions.md` means `docs/glossary.md`, whichever folder you
launched the agent from. An imported file may contain imports of its own,
and the session follows those too. Inside backticks the `@` does nothing:
`` `@CHANGELOG.md` `` names the changelog and loads nothing. An
`AGENTS.md` that Claude Code reads directly follows the same rules
(How Claude remembers your project, Claude Code documentation).

Here are those rules as a small program, applied to a sample project in
`site/examples/customizing-agents/memory-review/imports/`. The complete
file is `imports.py` in the same folder. The project's `AGENTS.md` is:

```markdown
# Agent instructions for todo

- Python 3, standard library only. No new dependencies.
- Run the tests with `python3 -m unittest -q`.
- Add a line to `@CHANGELOG.md` for every change a user can see.
- Team decisions that the code doesn't show: @docs/decisions.md
```

`docs/decisions.md` holds the 80-character rule and the line "The words
used here are defined in @glossary.md". The project has two glossaries:
`glossary.md` at the top, an old one, and `docs/glossary.md`, next to
`docs/decisions.md`. It also has a `CHANGELOG.md` at the top.

#### Checkpoint: Which files load?

What does this print, one line per file the session loads?

```python
for path, parent in load(ROOT / "AGENTS.md"):
    name = path.relative_to(ROOT).as_posix()
    if parent is None:
        print(name)
    else:
        print(f"{name}, imported by {parent.relative_to(ROOT).as_posix()}")
```

`CHANGELOG.md` isn't loaded, because its `@` is inside backticks. That
line only names the file. The glossary that loads is the one in `docs/`,
because `@glossary.md` is in `docs/decisions.md` and resolves from
`docs/`. Moving text into an imported file doesn't make the session any
lighter. The imported file enters the window at launch with the rest, so
what you gain is a shorter `AGENTS.md` to read and review, and the
context used stays the same (How Claude remembers your project, Claude Code documentation).

Now do the move in your copy. Make the folder with `mkdir docs`, and
create `docs/decisions.md` in it:

```markdown
# Decisions

- Keep item text at 80 characters or fewer. The phone widget that shows
  the list cuts longer text.
```

Add this line at the end of `AGENTS.md`, with nothing after the path:

```markdown
- Team decisions that the code doesn't show: @docs/decisions.md
```

Then delete `~/memory-review-notes/project_item_length.md` and its line
from `MEMORY.md`, so the fact is in one place. Commit the two repository
files, which is the step that makes the fact reviewed and shared.

```sh
git add AGENTS.md docs/decisions.md && git commit -q -m "Record the item length decision"
```

Quit the session and start a new one with the same `claude --settings`
command. Run `/context`: its list of memory files shows the instruction
files the session loaded, and `AGENTS.md` is in it
(How Claude remembers your project, Claude Code documentation). The list may leave out `docs/decisions.md`, so
the real check is a question. Ask the agent the limit on item text and
which file states it. The answer names `docs/decisions.md`. The notes folder holds
`MEMORY.md` and `user_diff_first.md`, plus any note the agent saved this
session. Memory notes and context files keep facts from one session for
the next. The next lesson asks when an agent may act on a note without
checking it, and a later one covers what happens inside one long session
when it is compacted.

#### Checkpoint: Keep, delete or move?

Place each memory note where it belongs.

Buckets:

- Keep in auto memory
- Delete it
- Move to a context file

Items:

- Show the diff before explaining a change
- Leave done() alone because of a rewrite on a branch that no longer exists
- Keep item text at 80 characters, because the team phone widget cuts it
- The user is new to Python and wants each standard library call explained
- Back up todos.json before tests that no longer open any file
- The team agreed that every new command prints exactly one line

## Exercise

In a fresh copy of the fixture with its own first commit, copy the
planted notes to `~/memory-review-notes`, start the agent with
`claude --settings '{"autoMemoryDirectory": "~/memory-review-notes"}'`,
and open `~/memory-review-notes` in your editor. Check each `project` note
against the copy, delete the two stale notes and their index lines, move
the item length rule into `docs/decisions.md` with an import from
`AGENTS.md`, delete that note too, and commit. The work is about ten
minutes and touches one memory folder and two repository files. Doing it
once by hand shows you what a review of an agent's memory looks like, and
which facts should never have been left in it.

A good result: the notes folder holds `MEMORY.md` and
`user_diff_first.md`, plus any note the agent saved this session, and
`MEMORY.md` has a line for each of those notes and no other.
`git log --oneline` shows your commit above `fixture`. A new session names
`docs/decisions.md` when you ask where the item length rule comes from.
Reflection: which fact does your agent rely on today that you told it
once and never wrote down anywhere a colleague could read?

Stretch: Run `python3 startup.py` with the memory folder of one of your own projects as its argument, a folder under `~/.claude/projects/` that has a `MEMORY.md`. It only reads the folder. Then read every note the index points to and mark each one keep, delete or move.

## Recap

1. Auto memory is notes the agent writes for itself. In Claude Code they
   are in one folder per repository on your machine, with a `MEMORY.md`
   index and one topic file per note, and the feature is on by default
   (How Claude remembers your project, Claude Code documentation).
2. A session loads the first 200 lines or 25KB of `MEMORY.md` at start,
   and reads topic files only when it needs them. The index line is what
   every session sees (How Claude remembers your project, Claude Code documentation).
3. A stale note is applied in every session with the same confidence as a
   true one, because the model reads it as context. Check each note
   against what it describes, and delete the file and its index line.
4. A fact the whole team needs belongs in a context file in the
   repository, where it is versioned and reviewed. An instruction file
   loads it with `@path`, resolved from the importing file's folder, and
   a path in backticks stays text (How Claude remembers your project, Claude Code documentation).

#### Habit

The next time an agent follows a memory note you didn't expect, open
that note and check what it claims against the code. Delete it if it is
stale, and move it into the repository if the team needs it.

## References

- How Claude remembers your project, Claude Code documentation, https://code.claude.com/docs/en/memory
- Explore the context window, Claude Code documentation, https://code.claude.com/docs/en/context-window
- Settings files and precedence, Claude Code documentation, https://code.claude.com/docs/en/settings
- Memory and context: context engineering, memory kinds, memory versus RAG, context rot, Agent Engineer Course, https://lsimons.github.io/agent-engineer-course/05-memory-and-context/
