
Claude Agent Memory Stores vs the Memory Tool
A memory store is a folder Anthropic hosts for you and mounts into your agent's sandbox at /mnt/memory/, so the agent reads and writes persistent memory with the same file tools it already has. That's the whole idea. It is not the same thing as the memory tool on the Messages API — that one runs on yourdisk and your code executes every file op. Same word, two products, and picking the wrong one costs you a week. Here's the split, the setup, and the default that will eventually bite you.
What a Memory Store Actually Is
Strip the marketing off and it's a versioned directory of markdown files with an API in front of it. A store is workspace-scoped, gets an id like memstore_01Hx..., and you attach it when you create a session. From that point the agent sees a directory and treats it like any other directory.
The mount path is derived from the store's display name, lowercased with non-alphanumeric runs collapsed to a hyphen — a store called "Demo Memory" lands at /mnt/memory/demo-memory/. Read the mount_path field off the session resource instead of building that string yourself. I have watched a perfectly good agent fail because someone hardcoded a path and then renamed the store in the Console.
Two things happen automatically that are easy to miss. Anthropic appends a short note to the system prompt for every mount — display name, path, access mode, the store's description, and any session instructions — so the agent knows the folder exists without you writing that prompt. And /mnt/memory/ itself is mounted read-only: writes land inside a store directory or they fail. There is no scratch space up there.
One prerequisite people trip on: the agent toolset has to be enabled on the agent. No file tools, no memory — the store mounts and the agent has no way to touch it.
Memory Stores or the Memory Tool? Ask Who Owns the Disk
This is the actual decision, and every other difference falls out of it.
| Memory stores | Memory tool | |
|---|---|---|
| Where it runs | Managed Agents sessions | Messages API, any Claude 4+ model |
| Who stores the bytes | Anthropic | You |
| Who executes file ops | The sandbox / SDK worker | Your application code |
| Version history | Built in, 30-day retention | Whatever you build |
| Edit out of band | REST API + Console UI | Touch your own files |
| Biggest risk you own | Poisoned memory | Path traversal + poisoned memory |
If your compliance story requires the bytes to sit in your own VPC, the memory tool is still the answer and you keep writing the sandboxing yourself — I went through that build, including the path-traversal check nobody should ship without, in the memory tool and context editing write-up.
If what you actually wanted was "the agent should remember this customer next week" and you have no interest in operating a storage layer, memory stores delete a sprint of work. The part I did not expect to care about is the Console UI. Being able to open a store, read what the agent decided to remember, and fix a wrong line by hand is worth more in practice than the API is — most memory bugs are content bugs, not plumbing bugs.
Setup Is Three Calls (and One Header That 400s)
Create the store, optionally seed it, attach it at session creation. That's it.
store = client.beta.memory_stores.create(
name="Acme Account Context",
description="What we know about this account. Check before any task.",
)
# optional: seed it before an agent ever runs
client.beta.memory_stores.memories.create(
store.id,
path="/conventions/reporting.md",
content="All reports use GAAP formatting. Dates are ISO-8601.",
)
session = client.beta.sessions.create(
agent=agent.id,
environment_id=environment.id,
resources=[{
"type": "memory_store",
"memory_store_id": store.id,
"access": "read_only", # deliberate, see below
"instructions": "Account context. Read before starting any task.",
}],
)The description is not documentation for you — it's handed to the agent so it knows what the folder holds. Write it like a label on a box, not like a changelog entry. instructions is session-specific guidance shown next to it, capped at 4,096 characters.
Stores can only be attached at session creation. There is no adding or removing one mid-session, so if your product hands an agent a new project halfway through a conversation, that is a new session.
Now the header trap. Managed Agents endpoints run on managed-agents-2026-04-01. Memory store endpoints run on agent-memory-2026-07-22. Send both on a memory store request and you get a 400 — you replace the value, you don't append a second one. Attaching a store to a session is still a sessionendpoint, so that one keeps the Managed Agents header. If you use the SDKs this is handled for you; if you're driving raw cURL because you're debugging, this is the error you'll stare at.
read_write Is the Default. Change It.
Attach a store without specifying access and the agent gets write permission. For a store the agent is supposed to curate, fine. For the shared standards store attached to forty sessions, that default is a persistence mechanism for prompt injection.
The attack is boring, which is why it works. Your agent fetches a web page, or reads a support ticket, or gets a tool result from a third-party MCP server. Buried in it is an instruction. The agent writes it into memory. Next week a completely different session reads that line back as trusted context with no marker saying where it came from— and unlike a one-shot injection, this one doesn't expire when the conversation ends. You've given the attacker durable storage inside your trust boundary.
The mitigation is structural and cheap: access: "read_only". It's enforced at the filesystem level, not by asking the model nicely — a read-only mount rejects the write. Reference material, conventions, domain lookups, anything shared across sessions: read-only. Keep exactly one narrow read-write store for what that session genuinely learns, and separate stores are free.
Same principle I keep landing on with tool poisoning in MCP servers and with injection defense in n8n: a capability the agent doesn't have can't be talked into being used. Instructions in a system prompt are a suggestion. A mount that refuses writes is not.
The Limits, and the One That Fails Quietly
- 100 kB per memory — roughly 25k tokens. A single file, not the store.
- 10,000 memories per store.
- 8 memory stores per session.
- 30 days of version retention — with an exception worth knowing: recent versions of a live memory are kept regardless of age, so a file that rarely changes keeps its history longer than 30 days.
Here's the one to design around. When a store hits 10,000 memories, writes to new memories fail — and existing memories stay readable and editable.Nothing crashes. The API keeps answering. The agent keeps running. It just silently stops learning anything new, and you find out weeks later when someone says "it used to remember my preferences."
So: many small focused files rather than a few fat ones, and many scoped stores rather than one general-purpose one — each store carries its own 10,000-memory budget, so one store per user or per project buys you headroom for free. Prune with memories.delete on a schedule. When a store has outgrown its purpose, attach a fresh read-write store and re-attach the old one as read_only; the agent reads both and only writes to the new one.
Worth pricing this against context, too. Memory is only cheaper than a long context window if the agent reads three files instead of all ten thousand — the token math I walked through for subagent token cost applies here almost unchanged. A memory store full of 90 kB files is a context bomb with an audit log.
On Self-Hosted Sandboxes It Syncs — It Doesn't Mount
If you run tool execution on your own infrastructure, the mental model changes and the docs say so in a note that's easy to skim past.
There is no live mount. The SDK environment worker downloads a local copy of each store before the agent's tools run, then reconciles it after tool calls — at most once per sync interval, 15 seconds by default — plus once more when the session ends.Two sessions sharing a store see each other's writes only after both workers have synced. If your design assumes two agents coordinating through shared memory in real time, it doesn't work here, and it will appear to work in testing right up until it doesn't.
Three more self-hosted specifics, all of which cost someone an afternoon:
- The
antCLI worker does not support memory stores at all. Not "partially" — not supported. Run the SDK worker (Python, TypeScript or Go) or your stores never mount. - Self-hosted environments accept only
memory_storeresources. Include afileorgithub_repositoryresource and the session is rejected with a 400; pass external references throughmetadatainstead. - Anything written under
/mnt/memory/but outside a store directory is thrown away. The worker's file tools refuse it, and whatever abashcommand drops there is never uploaded.
You also need sudo mkdir -p /mnt/memory && sudo chown "$USER" /mnt/memory on the host before the worker starts. Skip it and the failure is a permissions error a long way from its cause. If you're still deciding between running the runtime yourself and letting Anthropic run it, I laid out that trade in Agent SDK vs the raw API.
Versions Are the Feature Nobody Uses Until They Need It
Every mutation writes an immutable version (memver_...) with attribution. Versions belong to the store, not the memory, so the trail survives deleting the file — which is exactly the case you care about when you're reconstructing why an agent started giving a wrong answer in March.
Two sharp edges. There is no restore endpoint. Rolling back means retrieving the version you want and writing its content back with memories.update — or memories.create if the parent memory is gone. Write yourself that helper before you need it at 2am.
And redactis how you scrub a secret or a piece of PII out of history while keeping the who-and-when. A version that's the current head of a live memory can't be redacted, so you write a new version first, then redact the old one. If you're under a deletion-request regime, that ordering is the whole procedure.
For anything writing concurrently — a review job and a live session on the same store — pass a content_sha256 precondition on update. The write only applies if the stored hash still matches what you read, and on mismatch you re-read and retry. Optimistic concurrency, one extra field, no lost updates. Full parameter list is in the Managed Agents docs, and it's worth reading the read-only conflict-resolution section before you go to production.
What I'd Actually Ship
A shape that has held up for me: two stores per session. One shared, read-only, holding conventions and domain facts, seeded by hand through the API and reviewed like code. One per-user, read-write, small, where the agent writes what it learned about that person. Separate lifecycles, separate blast radius, and when the per-user store goes weird you delete it without touching anything else.
Add a pruning job from day one, not day ninety. And read the store yourself in the Console in week two — the first time I did that on an agent I'd shipped, half the memories were restatements of the system prompt and one was a confidently wrong summary of a policy that had since changed. That is the normal failure mode. Memory stores are the easiest place to look for it, which might be the best argument for using them.
Everything here is beta and the headers will move. Check the version strings against the docs before you copy any of it.
Has Anyone Read What Your Agent Remembers?
Most production agents I audit have memory nobody has opened since launch — stale facts, duplicated notes, and at least one line that came in from untrusted input and never left. I'll read yours, tighten the access modes, and give you a pruning and review loop that runs without you.
Related Posts
AI Agents
Claude Outcomes: Rubric Grading for AI Agents
Outcomes hands your agent's output to a second agent in a separate context window, scored against a rubric you write. The API, the iteration cost multiplier, and the checklist item my own pipeline skipped for 27 days.
AI Agents
Claude Mid-Conversation Tool Changes: Keep the Cache
Editing the tools array invalidates the prompt cache for the whole conversation. tool_addition and tool_removal change what Claude can call without ever touching it — plus the placement rules that 400.
AI Agents
Tool Search vs Programmatic Tool Calling in Claude
One cuts tool-definition tokens, the other cuts tool-result tokens. The decision rule, the 400s that surprise people, and the MCP restriction that makes the choice for you.