Agent Memory
Concepts

Identity and visibility

How credentials bind to agents and end users, and how per-memory visibility decides who can recall, update, share or delete a memory.

Two questions are answered on every request:

  1. Who is calling? The credential proves it — an API key or an OAuth access token. Request fields never do.
  2. Who may see this memory? The memory's visibility, its owner agent and its end user decide.

Credentials are bound to agents

Every credential is bound to a list of agent IDs when it is created. The first one is the credential's default agent.

You sendWhat happens
no agentIdThe credential's default agent acts. This is the normal case.
an agentId the credential is bound toThat agent acts. Use this only when one key serves several agents.
an agentId the credential is not bound to403 with code policy_denied (rule identity-binding).

A key created without any agent IDs acts only as itself (apikey:<keyId>). The SDKs never send an agent ID unless you configure one, and the MCP tools only accept agentId so that a multi-agent key can pick one.

Binding is set when the credential is created

In the console, choose the agents (and whether the key may act for end users) in the Create API Key dialog. Programmatically, pass agentIds and canActForUsers when minting a key or upserting a grant — see Provisioning.

End users: userId

userId is the end user a memory is about — a customer, a player, a patient — never the agent. It is accepted on append, retrieve, by-ID reads and the user-profile endpoints.

  • A credential may name a userId only if it has canActForUsers (a backend serving many end users), or if the userId equals the user the credential itself proved (an OAuth sign-in).
  • Otherwise the request is refused with 403 policy_denied. Keys are created with canActForUsers off unless you enable it.
  • On retrieve, a userId includes that user's profile and narrows workspace memory to rows carrying exactly that user. Tenant conventions still apply, since they belong to everyone.

Visibility levels

Each memory has a visibility, narrowest first:

VisibilityWho may recall it
privateOnly the exact agent that created it.
agentEvery instance of the owning logical agent.
userAgents acting for the same end user (userId).
workspaceEvery agent in the workspace. The default.
tenantEvery agent in the tenant. Writing or sharing at this level needs the promote capability.

Visibility is compiled into every search leg before retrieval runs, so a memory another agent wrote as private never appears in your results — not even as a count. Tenant administrators see every row.

Set visibility when you write:

{ "type": "preference", "content": "Prefers window seats", "userId": "alex", "visibility": "user", "…": "…" }

Owner and classification

  • ownerAgentId — the agent that wrote the memory. Ownership matters for private/agent visibility and for sharing.
  • classification — public, internal (default), confidential or restricted. It is stored and returned on every entry, but no policy enforces it yet.

Both are returned on every memory alongside visibility.

Reading, updating and deleting

By-ID operations (GET, PUT, DELETE on /v1/memory/{id}, explain and erasure status) apply the same rules and take optional agentId / userId query parameters naming the subject:

  • A memory the subject cannot see answers 404 — existence never leaks.
  • A memory the subject can see but the policy refuses to change answers 403 with code policy_denied and action / rule extension members.

Tenant-level rows (tenant conventions and floors) are readable by every workspace but cannot be updated, shared or deleted through a workspace credential — that answers 403. See Updating and forgetting.

Sharing: visibility only widens

POST /v1/memory/{id}/share raises a memory's visibility along private → agent → user → workspace → tenant. It requires the share capability (off by default) and ownership of the memory (or tenant admin); tenant also needs promote. A target at or below the current level is rejected with 422. Every share writes a history row and a share entry in the change feed.

There is no "unshare". To narrow a memory, delete it and write a new one with the narrower visibility.

Derived memory never widens

Episodes and procedures that consolidation derives from memories inherit the intersection of their sources' policies: a derivative is never more readable than its most restricted source. Two agents' private facts are abstracted separately rather than blended, and tenant promotion only considers memories that are already workspace- or tenant-visible.

Capabilities

Separately from identity, every API key or grant carries capabilities:

CapabilityAllowsDefault on new keys
readRetrieve, get, explain, list episodes/procedures/files, change feedon
writeAppend, update, blocks, profiles, categories, file docs, procedure validationon
feedbackOutcomes and retrieval feedbackon
curateConsolidate, curate blocks, review quarantined memorieson
deleteDelete memoriesoff
shareRaise visibilityoff
promoteTenant-level visibilityoff

A missing capability answers 403. Over OAuth, the same names appear as memory:read, memory:write, and so on. See Authentication.

On this page