You restart the process that runs your research agent. Maybe you deployed a fix, maybe the node was preempted overnight. The next morning the agent formats Maya's sweep report the way she told it not to yesterday. What did it actually keep?
The short answer: an agent remembers what your application wrote to storage and reads back on the next turn. The model itself keeps nothing. Every request to a model starts from the text you send with it. Anything that feels like memory is something your code saved and chose to include again.
That makes the useful question a concrete one. For each thing the agent seemed to know, where did it live?
Three places "memory" can live
| Where it lives | Example | After a restart |
|---|---|---|
| The model | Nothing of yours. The weights do not change when you chat | Unchanged, and never held your data |
| The process | A Python list of conversation turns, a cached tool result, a variable holding "the current task" | Gone |
| Storage | A row in a database, a file on disk | Still there, if it was committed before the process stopped |

Most first agents keep the conversation in a list and pass the whole list to the model on each turn. It works in a demo because the demo never restarts. The first preemption empties the list, and the agent greets a returning researcher as a stranger.
A small example you can run
This script needs only Python's standard library. It has no model call, no API key and no network access, because the point is what survives, not what the model says. Save it as restart_memory.py.
import sqlite3
import sys
import time
SCHEMA = """
CREATE TABLE IF NOT EXISTS preferences (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session TEXT NOT NULL,
name TEXT NOT NULL,
value TEXT NOT NULL,
source TEXT NOT NULL,
created REAL NOT NULL,
active INTEGER NOT NULL DEFAULT 1
);
CREATE UNIQUE INDEX IF NOT EXISTS one_current_value
ON preferences(session, name) WHERE active = 1;
"""
def remember(db, session, name, value, source):
# Retire the old value and add the new one together, or not at all.
with db:
db.execute(
"UPDATE preferences SET active = 0 WHERE session = ? AND name = ? AND active = 1",
(session, name),
)
db.execute(
"INSERT INTO preferences (session, name, value, source, created) VALUES (?, ?, ?, ?, ?)",
(session, name, value, source, time.time()),
)
def current(db, session):
rows = db.execute(
"SELECT name, value, source FROM preferences WHERE session = ? AND active = 1 ORDER BY name",
(session,),
)
return rows.fetchall()
db = sqlite3.connect("agent.db")
db.executescript(SCHEMA)
conversation = [] # lives in this process only
if sys.argv[1:] == ["first-run"]:
conversation.append("Maya: report last night's sweep as plain text")
conversation.append("Maya: actually, use a table with 95% intervals")
remember(db, "maya", "report_format", "plain text", "researcher message 1")
remember(db, "maya", "report_format", "table with 95% intervals", "researcher message 2")
print("conversation turns in this process:", len(conversation))
print("current preferences:", current(db, "maya"))
print("versions on file:", db.execute("SELECT COUNT(*) FROM preferences").fetchone()[0])
db.close()Put %%writefile restart_memory.py as the first line of a cell above the code and run it to save the file. Then run each process from its own cell with a leading !, as in !python restart_memory.py first-run. Each !python starts a fresh Python process, which is exactly the restart you want to see.
python restart_memory.py first-run records two turns of conversation in a list and stores Maya's preference twice: first "plain text", then her correction to a table with intervals.
python restart_memory.py starts a new process with nothing in memory and opens the same agent.db file.
Look at three numbers: the conversation turns, the current preference and the versions on file.
$ python restart_memory.py first-run
conversation turns in this process: 2
current preferences: [('report_format', 'table with 95% intervals', 'researcher message 2')]
versions on file: 2
$ python restart_memory.py
conversation turns in this process: 0
current preferences: [('report_format', 'table with 95% intervals', 'researcher message 2')]
versions on file: 2I ran this with Python 3.12.13, the Python line Colab uses, on September 30, 2026. Delete agent.db to start again.
What the two runs show
The conversation did not survive. The second process starts with zero turns. If the agent's only record of Maya's preference had been those two lines of chat, it would now format the report the old way, or ask her again.
The preference survived, and so did its correction. The second process reads the table format, the value Maya changed her mind to, with a note of where it came from. It does not read "plain text," even though that row is still in the file.
The old value is history, not a second opinion. The unique index allows any number of retired versions but only one active value per session and name. Both writes in remember sit inside one transaction, so a crash between them cannot leave Maya with two current formats or with none. Update and insert in two separate commits and that gap exists, and a preemption is exactly when you find it.
Storage is not yet context. Nothing in this script sends the preference to a model. On a real turn your code selects the rows that matter for this session and puts them in the request. A fact that is stored but never selected is, from the model's side, forgotten. Choosing which rows to send is a retrieval problem, and Chapter 5 measures it.
Writing a chat summary to disk when the process exits works only when the process exits politely. Preemption, a kill signal or a crash skips that step. Store each fact when you learn it.
Check your understanding
Where this stops
- A stored statement is not evidence of an action: "Maya prefers tables with intervals" tells you what she said. It does not tell you that last night's report was sent, or that the sweep it describes finished. Whether a job ran is a question for the scheduler's record, not the agent's memory. An accepted agent draft still needs an action boundary works through that line.
- Only committed data survives: A process killed halfway through a transaction loses that transaction. That is the behavior you want, and it means the write has to finish before the agent tells anyone it has remembered something.
- This is not deletion: Setting
active = 0stops a value from being current. The row, your backups and any request already sent to a model provider still hold it. Removing personal data for real is a separate job. - One file on one machine: The example does not cover several processes writing at once, a database on a network drive or a lost disk.
- Let people, not the model, write facts at first: Here only a researcher's message becomes a preference. If a model can save its own guesses as facts, the next process will read a guess back as something Maya said.
Why this matters in a lab
Research agents run on preemptible machines, inside jobs that restart, across sessions that span days. "What survives a restart" is the first question in any agent design review, and the answer has to be specific: which facts are in which table, written in which transaction, and selected by which rule. An interviewer who asks how your agent keeps state is checking for exactly that: that you separate model, process and storage, that you know correction is one transaction, and that you do not treat memory as proof that something happened.
Once facts outlive a process, they can also go stale. Giving every memory an owner and an expiry rule covers who decides what is still true.
Build the full version
The free book builds this mechanism properly. Chapter 5, "Memory and retrieval", first derives BM25 and the ranking metrics and measures retrieval on a real model, then builds preferences with provenance, correction in one transaction, a bounded context, and a way to forget a preference so that an older summary cannot bring it back. The chapter is a manuscript draft with runnable code.
When you want to practice, Unit A of the Chapter 5 exercises has you build durable memory, and Unit B has you measure a retriever before trusting it. Reading and the exercises need no account.
If your question is a different one, such as whether an action really completed or how an agent picks up after a crash, the book's question map points to the chapter that answers it.
Measure retrieval, then build correctable preferences, a context budget and real forgetting on top of the table you just ran. Free to read, no account.

