Try this first
Close Rover. Open it again. Ask it what you were working on.
Nothing. Every session starts from zero, because the transcript was the only memory and you
just threw it away.
Memory is a file
Everything so far has been about one session. Memory is about the next one, and the mechanism
is unglamorous: the agent writes things to a file, and reads that file next time.
That is it. There is no special storage. Give it a tool:
MEMORY = Path("MEMORY.md")
def remember(note):
"""Append a note for future sessions."""
with open(MEMORY, "a") as f:
f.write(f"- {note}\n")
return f"Noted: {note}"
And load it at the start:
if MEMORY.exists():
system += f"\n\nThings you learned in earlier sessions:\n{MEMORY.read_text()}"
Two functions. That is a persistent agent.
Some providers define a memory tool for you
Anthropic, for example, has a pre-defined memory tool you switch on rather than describe:
# Anthropic-specific.
{"type": "memory_20250818", "name": "memory"}
It is client-executed — you still write the storage, exactly as above. What you get is a
standard set of operations the model is already familiar with, instead of an interface you
designed.
Use one if your provider has it and you want a full memory directory. Use the two functions
above when you want to understand what is happening, which is now — and when you want the same
code to work on every provider.
The hard part is not storage
Writing to a file is easy. Deciding what to write is the entire problem, and agents get it
wrong in both directions.
Writing too much. Every session appends five notes. After a month, MEMORY.md is nine
hundred lines, it goes into the system prompt on every request, and it is now a context
problem pretending to be a memory feature.
Writing the wrong thing. “The user asked me to fix the login bug.” That was true on
Tuesday. It is noise now.
What is worth remembering
The test: would this still be true and useful next month?
| Worth writing | Not worth writing |
|---|---|
“Tests are run with make test, not pytest directly” |
“The user asked me to fix a bug” |
“The API client is in lib/http.py, not api/“ |
“I read three files” |
“Do not edit generated/ — it is rebuilt from schema.sql” |
“The tests passed” |
| “The user prefers small commits with a body” | “I was working on the login page” |
Left column: durable facts about the project and the person. Right column: events, which the
transcript already covered and which expire.
That distinction is worth putting in the tool description, because the model applies it:
"description": (
"Save something for future sessions. "
"Only save durable facts about this project or the user's preferences — "
"things that will still be true next month. "
"Do not save what you did today; that is not useful later."
)
Keep it small on purpose
Memory is loaded into every request, so it competes directly with the work. Two habits:
Update rather than append. If a note is wrong, fix it. Do not add a correction underneath
and leave both.
Cap it. A hard limit — fifty lines, say — forces the question “is this worth more than
what it displaces?” every time.
An agent’s memory file should read like a good README, not a diary.
Memory is a file the agent writes and reads. The mechanism is trivial; deciding what
deserves a line is the whole skill.
Try this before the next lesson
Add the memory tool with the description above. Use Rover for three real sessions on the same
project.
Then read MEMORY.md. Delete every line that fails the “still true next month” test. What is
left is what your description should have asked for — tighten it.