Multi-Agent Memory Isolation Is a Lookup Table

John Rood··6 min read

You add a second agent. New workspace, new bot, new session store, own identity files. Everything about the setup is separate, so you assume the memory is separate too.

It is not. Memory on a shared gateway comes from a lookup, and the lookup has a default.

What is actually separate

OpenClaw gives every agent its own workspace, its own session transcripts, and its own bot account. Bindings route each incoming message to the right agent using the most specific match available, peer before account before channel before default. That part is deterministic and it works.

The memory layer sits outside all of it. The plugin resolves a vault key per request and injects what it retrieves before the model sees the prompt. Separate bots do not create separate vaults. Separate sessions do not either. The routing decides who answers. The key decides what the answer knows.

How the key gets resolved

The plugin holds one global key and an optional agentKeys map. On every hook it reads the calling agent's workspace directory, takes the basename, and looks it up in that map. A workspace named workspace-rex resolves to agentKeys.rex. That is the whole mechanism.

If the agent is not in the map, the lookup resolves the global key instead. No error, no warning, no entry in a log you would notice. It just resolves to the shared vault and answers with whatever is in there.

That fallback is the design constraint worth understanding. Every resolution has to produce a key, so there is always a default. Which means isolation is not a property of separate agents. Isolation is a property of the map, and the map is something you maintain.

The failure only goes one direction

Misconfigured routing usually fails toward sharing, and sharing is the direction that costs you.

Picture the setup: three agents, two mapped, one created last week. The new one inherits the global key and starts reading the main vault before anyone notices. Now a contractor's agent, or a client-facing bot, has the operating context of your own. Nothing broke. Nothing alerted. The recall answer looked correct because it was correct, just drawn from the wrong vault.

The opposite never happens. There is no state where a missing map entry produces a fresh empty vault and you lose continuity. The default is generous. Generosity is the wrong default for a boundary.

Why separate vaults at all

Single-agent setups have no reason to split anything, and the map costs nothing when there is nothing to map.

The case for splitting is one gateway carrying agents of different trust. A client-facing bot that should never quote your internal pricing history. A research agent that should not read the vault holding credentials-adjacent notes. A contractor's agent working a sub-project. A personal agent beside a business one. Any pair where one agent knowing what the other knows is a problem you would have to explain.

If everything on the gateway is one person's work and one level of trust, one vault is the honest answer and there is no work to do here.

Proving it, rather than assuming it

Two agents with two keys. In agent A's direct chat, store a synthetic fact: the demo release phrase is ORCHID-7419. Start a fresh A conversation and request the phrase without supplying it. Then open agent B and put the question there too.

Read the retrieval result, not the reply. A model can guess a plausible phrase or deflect, and a clean-sounding answer is not evidence the vault stayed separate. Inspect what memory_search actually returned. The isolation proof is about what the tool pulled, not about how the sentence came out.

Repeat it after any routing change, and repeat it when you add an agent. Adding an agent is a memory configuration change, which is easy to forget when the task feels like channel setup.

Two shared settings that surprise people

The density commands (openclaw mr low, openclaw mr medium, openclaw mr high) update the plugin's shared settings. Running one inside a chat scopes it to the plugin rather than to the agent you are talking to, so tuning retrieval for one workload changes it for all of them.

Deletion is also whole-vault. openclaw mr delete clears the vault for every client holding that key. That is the correct behavior for a clean rebuild and a nasty surprise if you were thinking per-agent. The --key flag targets a single vault from your main terminal, which is the supported way to work on another agent's memory without touching your own config.

What this is not

This is a deployment recipe for one gateway and one plugin, not tenant provisioning. There is no automatic per-agent vault creation, no directory service, no policy engine deciding who may read what. If two agents need different keys, someone writes two entries. If an agent is deleted, its vault stays until someone deletes it, and turning the plugin off leaves remote memory in place.

That is not a design flaw. It is a description of the thing you are actually operating, which is a lookup table with a default you set.

Where this lands with a hosted vault

The multi-agent documentation walks the full setup. The short version of what it buys you: one key per isolation boundary, an agentKeys map so hooks resolve the right vault from the workspace, and --key on the maintenance commands to upload, check, or clear a specific agent's memory from anywhere. Capture runs at agent_end per conversation, so each agent's vault fills from its own traffic, and recall searches the vault that agent resolves to. The same keys work from the OpenClaw integration page if you would rather start there.

The part that matters more than the features: the boundary is stated as a key map you can read, not as a promise that separate agents are separate by nature.

Do the check now

Run openclaw agents list and count the agents. Count the entries in agentKeys. If the first number is bigger than the second, the difference is reading the global vault.

Start a 14-day trial and put every agent on its own key. It costs $20 a month after the trial.