Memory governance
Share a memory, explain how it is known, tail the change feed, review quarantined memories and run retrieval evaluations.
| Method | Path | Capability |
|---|---|---|
POST | /v1/memory/{id}/share | share |
GET | /v1/memory/{id}/explain | read |
GET | /v1/memory/changesets | read |
POST | /v1/memory/{id}/review | curate |
POST | /v1/memory/evals/run | read |
Share a memory
POST /v1/memory/{id}/share — raise a memory's visibility. Supports Idempotency-Key.
{ "workspaceId": "…", "visibility": "workspace", "applicationId": null, "agentId": null, "userId": null }Visibility only widens: private → agent → user → workspace → tenant. The caller needs the share capability and must own the memory (or be a tenant admin); tenant also requires promote.
| Status | Meaning |
|---|---|
200 | { "id": "…", "visibility": "workspace" } |
400 | Unknown visibility value. |
403 | Missing capability, or policy_denied (not the owner). |
404 | Unknown or not visible to the subject. |
422 | The target is not above the current visibility. |
A share writes a history row and a share row in the change feed. MCP: share_memory. SDKs: share(). See Identity and visibility.
Explain a memory
GET /v1/memory/{id}/explain?workspaceId=… — "how do you know this?" for one memory. Optional query: applicationId, agentId, userId.
The response contains:
| Field | Contents |
|---|---|
memory | The memory with its provenance and temporal fields. |
trust | The read-time trust breakdown: composite, confidence, evidence, freshness, utility, contradictionRisk, sourceAuthority. |
lineage | origin (run, episode, entry it was promoted from), derivedFrom, derivedInto, supersededBy, supersedes, and recorded evidence sources. |
evidence | The originating episode and its first events, sourceRef and how the memory was extracted. |
history | The memory's history rows. |
usage | Usage count, last access, how often it was injected, used or ignored, and recent outcomes of runs it was delivered to. |
contradictions | Open contradictions. |
dependents | How many memories derive from it, with a sample. |
Every linked memory is authorized for the caller separately. A link to a memory you may not see is returned with "redacted": true and its type, excerpt and lifecycle state nulled — "not visible" and "no longer exists" are deliberately indistinguishable. When episode events were withheld, evidence.redacted is true and the episode's goal and summary are null. 404 for an unknown or foreign memory.
MCP: explain_memory. SDKs: explain().
Change feed
GET /v1/memory/changesets?workspaceId=… — the workspace's change feed, oldest first. Content never enters the feed; rows carry policy fields only.
| Query | Notes |
|---|---|
workspaceId | Required. |
action | One of create, update, delete, share, promote, policy_change. |
memoryId | Only changes to this memory. |
since | Only rows created at or after this instant. |
cursor | The nextCursor of a previous page. |
limit | 1–500, default 50. |
{
"rows": [
{
"seq": "1042",
"id": "…",
"memoryId": "…",
"action": "delete",
"actor": "support-bot",
"actorRole": "agent",
"oldValues": { "lifecycle_state": "Active" },
"newValues": { "lifecycle_state": "SoftDeleted", "dependents_flagged": "2", "dependents_flagged_ids": "…,…" },
"reason": null,
"createdAt": "2026-10-01T09:00:00Z"
}
],
"nextCursor": "1042",
"hasMore": false
}nextCursor is returned whenever a page is non-empty and echoed back when nothing is new, so tailing the feed is a single loop: keep the cursor and call again. A malformed cursor, action or limit is 400.
- Blast radius of a delete:
?memoryId=<id>&action=delete— the delete row lists the dependents that were flagged stale. - Tenant-level rows (a tenant convention's promotion) are not in a workspace feed; they surface in the console.
MCP: get_changesets.
Review a quarantined memory
Appended content is screened for prompt-injection and data-exfiltration patterns. Flagged content is stored quarantined: never recalled, merged, consolidated, promoted or shared until reviewed.
POST /v1/memory/{id}/review
{ "workspaceId": "…", "action": "release", "applicationId": null }| Field | Notes |
|---|---|
action | release makes the memory live; reject keeps it out. Anything else is 400. |
Response: { "id": "…", "status": "released" } or "rejected". A memory that is not quarantined (or not in this workspace) answers 404. Requires the curate capability.
Retrieval evaluation
POST /v1/memory/evals/run — a retrieval regression run. You supply queries and the memory IDs each one should surface; the product runs its own retrieval for each case (deterministic, at the maximum token budget) and scores the results. No LLM judge, no side effects: evaluation reads create no receipts, touch no usage counters and earn no credit. One metered operation per run.
{
"workspaceId": "…",
"agentId": "support-bot",
"k": 10,
"datasetVersion": "2026-10-01",
"cases": [
{
"query": "what can Alex eat?",
"expectedIds": ["8b0c1c0e-…"],
"forbiddenIds": ["…"],
"staleIds": ["…"]
}
]
}| Field | Notes |
|---|---|
cases | 1–200 cases. Each needs a non-empty query and expectedIds; forbiddenIds must never surface; staleIds are out-of-date memories. |
k | Cut-off, clamped to 1–100. Default 10. |
agentId | The agent whose view is evaluated. |
applicationId, datasetVersion | Optional. |
The response includes passed (false if any forbidden ID appears in any case's top k), hitRate, recallAtK, precisionAtK, mrr, ndcgAtK with 95% bootstrap intervals, abstentionAccuracy, forbiddenRate, staleRate, zeroResultRate, latency percentiles, meanContextTokens, llmCalls, a manifest and perCase results. Two runs are comparable only when their manifest.comparableKey matches.
Use it as a CI gate after a configuration change or an upgrade.