Skip to content

Reading what the agent remembers

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 [1]. Other coding agents keep notes under other names and in other places. The review works the same way there.

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 [1].

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 [1].

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) [1].

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 [1] [2]. 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 · run it

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

Terminal window
python3 startup.py
Output
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)

Output verified in CI from site/examples/customizing-agents/memory-review/startup.py.

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

- [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 [1].

Terminal window
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.

Terminal window
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 [1]. A key you pass with --settings as inline JSON counts for that session only, and Claude Code writes it to no file [3]. 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:

Terminal window
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 [1]. 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.

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)

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
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.

A remembered fact doesn’t warn you when it goes out of date. Long-term notes need updating as the world changes [4], 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 [1].

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.

Terminal window
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.

Terminal window
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:

Terminal window
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 [1]. Remove the index line too, since the index is the part that loads.

Checkpoint · choice

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 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 [1]. 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 [1].

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:

# 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 · predict

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

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()}")

Output verified in CI from site/examples/customizing-agents/memory-review/imports.py.

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 [1].

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

# 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:

- 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.

Terminal window
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 [1]. 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 covers what happens inside one long session when it is compacted.

Checkpoint · sort

Place each memory note where it belongs.

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 [1].
  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 [1].
  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 [1].

You can now

  • Manages what the agent carries between sessions

  1. Anthropic. How Claude remembers your project. Claude Code documentation. Reference. Claude Code memory
  2. Anthropic. Explore the context window. Claude Code documentation. Reference. Claude Code context window
  3. Anthropic. Settings files and precedence. Claude Code documentation. Reference. Claude Code settings
  4. Addy Osmani, Ivar Soares Urdalen, Leo Simons. Memory and context: context engineering, memory kinds, memory versus RAG, context rot. Agent Engineer Course. Course. AEC-05