Claude's memory tool runs client-side, so your application executes every file operation and /memories is a prefix you map onto real storage. That makes path traversal your bug to prevent, and the documented example handlers skip the validation on purpose.
A directory the model can read and write
Context isolation makes the case for keeping durable information out of the conversation: a note is re-read when needed, while a message array is re-sent every turn. This page is how that is wired up.
Anthropic ships it as the memory tool. The entire configuration is one entry
in tools:
{ "type": "memory_20250818", "name": "memory" }
There is no input schema to write. It is an Anthropic-provided tool, available on Claude 4 and later.
You are the filesystem
The memory tool is client-side, and this is the part people miss. Claude does
not write files. It emits a tool_use block asking for a file operation, your
application performs it against storage you control, and you return the result
in a tool_result.
So /memories is not a real path. It is a prefix your handler maps onto whatever
you use: a per-user directory, rows in a database, objects in a bucket,
encrypted blobs. Two conversations share memory when your handler serves them the
same store, and not otherwise.
That is more work than a managed feature, and it is also the reason the feature is usable. The data never leaves your infrastructure, so per-user isolation and retention are decisions you already know how to make.
Six commands to implement
| Command | What it does |
|---|---|
view | list a directory, or read a file with line numbers |
create | write a new file |
str_replace | swap one exact string for another |
insert | insert text after a given line |
delete | remove a file or directory |
rename | move a file or directory |
The return strings are specified, down to the line-number format: six characters wide, right-aligned, tab-separated, one-indexed. Claude reads whatever text you return, so you can deviate, but the specified strings are what it was trained against.
Four SDKs provide helpers so you implement storage rather than the tool
interface. Python and TypeScript also ship a local-filesystem implementation,
BetaLocalFilesystemMemoryTool, which is enough to try the feature in an
afternoon and not what you deploy.
Path traversal is your problem
A request for /memories/../../secrets.env is a request your handler will
serve if you let it. You are executing file operations on behalf of a
model that reads untrusted content, which is the classic shape of this bug.
Validate every path on every command:
- Require the path to start with
/memories - Resolve to canonical form and confirm it stays inside the memory root
- Reject
../,..\\, and their URL-encoded forms such as%2e%2e%2f - Use the platform's own facilities, such as Python's
pathlib.Path.resolve()withrelative_to()
The demonstration handlers in the documentation skip this deliberately, so do
not lift one into production. Two further limits belong in the same handler:
reject a delete or rename whose target is the memory root, and cap how large
a file may grow.
The prompt is written for you
Adding the tool makes the API append a memory protocol to your system prompt. You do not send it. Its operative line is worth reading:
ASSUME INTERRUPTION: Your context window might be reset at any moment, so you risk losing any progress that is not recorded in your memory directory.
That framing is the design. Memory is not a convenience store of preferences; it is the recovery mechanism for a session that ends without warning.
Pairing it with compaction
The two features solve neighbouring problems and are meant to run together. Compaction keeps the active context small by summarizing older turns, and a summary is lossy. Memory holds the things that must survive being summarized, because they live in a file rather than in the transcript.
The practical division: if losing it would break the next session, write it to memory. If it only mattered this turn, let compaction take it.
Housekeeping nobody does until it hurts
Three maintenance jobs that are yours, not the model's.
Expire it. Delete memory files that have not been read in a long time. Nothing does this for you, and a memory directory only grows.
Cap the read. Limit how much view returns and let Claude page with
view_range. An unbounded read puts the whole file back in the window, which
defeats the point of having moved it out.
Watch what gets written. Claude usually refuses to write sensitive data to memory. Usually is not a guarantee, and this store may now hold customer information under whatever rules that data came with. Validate before you write.
Further reading
- Anthropic, Memory tool: the tool entry, all six commands and their return strings, and the path traversal warning.
- Context isolation: why a note beats a message, and the other separations.
- Memory systems: what to write down, and when.
- Compaction: shrinking the window the other way.
Knowledge check
Question 1 of 3
Sign in to save your progress and pick up where you left off.