Agent Memory

Identity and access

Who can reach a piece of memory, and where each access decision is enforced.

This page explains who can reach a piece of information and where that is enforced. Agent Memory decides access at three layers: which tenant, workspace and application a credential can reach, which operations it may perform, and who per-record visibility allows to see a memory.

Credentials

CredentialWho uses it?How is it sent?
API key (amk_…)Agents, SDKs, server applicationsAuthorization: Bearer amk_…
External identity provider JWTEnterprise integrations (if configured)Authorization: Bearer <jwt>
Console sessionHuman users (console)Cookie; sign in with Google, Microsoft/OIDC or an email code
Development tokenScripts, Development environment only (running locally)POST /dev/auth/token

Only a hash of an API key is stored; the key is shown once, when it is created. A key can be given an expiry date and can be revoked from the console; a revoked key gets 401.

API key scope

A key is bound to:

BindingEffect
A single workspaceAny request with a different workspaceId returns 404.
Optionally, a single applicationA key bound to an application cannot request another applicationId (404). If no application is set, the key works with the shared pool.
Permissionsread, write, feedback, curate, delete, share, promote. Console defaults: read, write, feedback, curate on; delete, share, promote off.
Bound agents (optional)Which agent names the key may act as. The first one is the default. A key with no bound agents acts under its own identity and cannot claim another agentId.
Act for usersRequired to send a userId.

In the console, keys are created on the API Keys page. An operation the key lacks permission for returns 403.

Agent and end-user identity

  • Don't send agentId. The key's default agent performs the operation. If the key is bound to several agents, pass the agent you are acting as. A name the key is not bound to:

    {"title":"policy_denied","status":403,
     "detail":"Policy denied assert_identity: this credential is not bound to agent 'docs-agent-b' (identity-binding).",
     "code":"policy_denied","action":"assert_identity","rule":"identity-binding"}
  • userId is the person the memory is about. To send it, the key needs the act for users permission; otherwise you get the same kind of 403.

Memory visibility

visibilityWho sees it?Note
workspace (default)Any identity with access to the workspace.
privateOnly the agent that wrote the memory.Another agent's key in the same workspace does not see it in search, cannot read it by ID and cannot delete it (404).
agentThe agent that owns the memory.Currently behaves the same as private.
userOnly calls reading on behalf of that userId.
tenantAny identity with access to the workspace.Does not carry over to other workspaces; for tenant-wide sharing use the rule flow below. Writing it requires the promote permission.

Visibility is applied in every search leg before ranking; a memory you cannot see never appears with its content in any result, explanation or relationship chain (in explanations it shows up as redacted: true). Tenant admins are exempt from visibility rules.

Deduplication does not merge memories with different visibility; derived memories (e.g. consolidation facts, abstractions) take the most restrictive visibility of their sources.

Sharing

Visibility can only be widened (e.g. private → workspace):

curl -s -X POST "$API/v1/memory/$ID/share" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
  -d "{\"workspaceId\":\"$WS\",\"visibility\":\"workspace\"}"
# {"id":"…","visibility":"workspace"}

This requires the share permission and ownership of the memory (promote for tenant). Attempting to narrow visibility returns 422. MCP: share_memory(memoryId, visibility). Every share is recorded in the history, the change feed (share) and as a webhook event.

Don't confuse filters with access control

This is access controlThis is a filter
Tenant boundary (row-level security in the database + query filters)Searching with userId: narrows to that user's memories. Without userId, memories with workspace visibility are returned regardless of which user they belong to.
The key's workspace and application bindingapplicationId: the application's memories + the shared pool. The shared pool is open to every application.
Permissions (read … promote)facet and tags: narrowing labels.
Memory visibility (private, agent, user)runId: a namespace; anyone in the workspace can name any run.
Agent and user identity bindingclassification: stored and returned, but currently not part of access decisions.

If you want to protect an end user's data from other users, use visibility: "user"; passing a userId alone provides no protection.

404 or 403?

SituationResponse
Unknown workspace/application or one belonging to another tenant; a workspace you have no access to404 (existence is not leaked)
A memory not visible to you (visibility, workspace boundary) or a quarantined memory404
The credential lacks the relevant permission403 (no body)
Policy denial on a visible memory (e.g. sharing a memory you don't own)403 policy_denied
Acting as an agent or user the credential is not bound to403 policy_denied (identity-binding)
Missing, invalid, expired or revoked credential401

Organization, members and roles

  • Organization members are invited from the console (Settings → Members). Roles: tenant-admin and member. Members are granted access per project (workspace).
  • A tenant admin performs administrative operations such as approving promotions, sharing, export, deleting projects and settings; tenant admins are exempt from memory visibility.

Tenant-wide rules (sharing across workspaces)

The only channel for information across workspaces is tenant-wide rules:

  1. When the same decision or approved pattern appears in at least two different projects, consolidation produces a candidate.
  2. A tenant admin approves or rejects the candidate on the console's Promotions page. It can optionally be approved as a "floor".
  3. An approved rule appears in every project of the tenant as tenantEntries; floors appear in every context as tenantFloors.
  4. Candidates expire if no decision is made within 14 days.

Floors are also used during consolidation to flag workspace memories that contradict them.

Tenant isolation and placement

  • On the standard tier, tenants are separated in a shared database with row-level security (RLS); application queries additionally apply tenant and workspace filters.
  • On the dedicated tier, a tenant's data lives in a separate database. If placement is not ready, requests get 503 PLACEMENT_UNAVAILABLE.

Limits

  • Classification (classification) does not affect access.
  • Permissions from source systems (e.g. a document's original access list) are not synchronized into memory. The writing application decides the visibility of memories.
  • Console members' permissions within a project are currently a fixed set (read, write, feedback, curate, delete).
  • With an API key, the /v1/mcp/<application-name> URL does not select the application; use a key bound to the application.

On this page