Read a stratified pack from CortexDB. Returns layers, context block, provenance, and diagnostics.

POST /v1/recall

The single read endpoint. Returns a stratified pack — the requested memory layers (events, episodes, facts, beliefs, understanding) plus a narrative context_block, full provenance, and diagnostics. Replaces the older /v1/recall and /v1/search.

For Recall + LLM in one call, use POST /v1/answer.

Capability

  • scope.read.local (always)
  • scope.read.holistic when view=holistic
  • scope.read.descend when view=descend
  • diagnostics.read when diagnostics ≠ "none"

Request

{
  "scope": "org:acme/dept:eng/user:alice",
  "view": "holistic",
  "query": "What did we decide about the Q3 launch?",
  "include": ["beliefs", "facts", "episodes"],
  "exclude_content": false,
  "temporal": {
    "as_of": null,
    "valid_during": null,
    "natural": "last 30 days",
    "reference_date": null
  },
  "filters": {
    "metadata": {
      "observed_actor": ["user:alice", "agent:planner_v3"],
      "labels": ["q3-launch"]
    }
  },
  "budgets": {
    "max_tokens": 4000,
    "per_layer_limits": { "events": 0, "episodes": 5, "facts": 20, "beliefs": 10, "understanding": 3 }
  },
  "citation_mode": "inline_with_markers",
  "diagnostics": "summary",
  "stream": false,
  "idempotency_key": "recall-alice-q3-001"
}
FieldTypeNotes
scopestringRequired.
viewenumraw / granular / holistic / descend / structured. Default holistic.
querystringOptional natural-language query. Without it, recall returns the bounded slice defined by temporal + filters.
includestring[]Layers to populate; absent = all per the view.
exclude_contentboolOmit large content/summary strings; return IDs + metadata only.
temporalobjectas_of, valid_during, natural, reference_date. See Bi-temporal model.
filtersobjectExactly one field: metadata — a map of attribute → string or list of strings. Accepted attributes: observed_actor, caller, modality, labels, intent. Attributes are ANDed; values in one list are ORed. labels matches the exact stored label string (what you wrote in context.labels — note you store labels top-level but filter them under filters.metadata.labels). Boolean AND/OR trees and comparison operators (gte etc.) are not accepted; there is no confidence filter. Unknown fields or attributes are rejected with 422.
budgets.max_tokensintToken budget for the rendered context_block and event retrieval. Derived layers are capped per-item via per_layer_limits, not token-counted — a full cross-layer token knapsack is planned but not yet implemented.
budgets.per_layer_limitsmapHard caps per layer.
citation_modeenumnone, inline_with_markers, block_at_end, structured_only.
diagnosticsenumnone (default for non-admin), summary, full.
streamboolSee POST /v1/recall/stream below.
idempotency_keystringRepeated calls within 60 s return the same pack_id and cached pack.

Views

ViewWhat it doesTraversal cap
rawSingle scope, full event payloadsnone
granularSingle scope, all layersnone
structuredSingle scope, facts + beliefs onlynone
holisticScope plus ancestors in the pathscope.read.holistic
descendScope plus descendantsscope.read.descend

Response — the Stratified Pack

{
  "pack_id": "pack_01HX...",
  "scope": "org:acme/dept:eng/user:alice",
  "view": "holistic",
  "as_of": "2026-05-15T10:42:09Z",
  "layers": {
    "events":        [ /* MemoryEvent records */ ],
    "episodes":      [ /* Episode records */ ],
    "facts":         [ /* Fact records (bi-temporal triples) */ ],
    "beliefs":       [ /* Belief records with confidence + supports */ ],
    "understanding": [ /* Concept nodes */ ]
  },
  "context_block": "On 2026-05-13 the team upgraded Acme to 200 seats [1]. Earlier that quarter the POC was extended (ep_01HX...) [2]. ...",
  "provenance": {
    "trail":     [ { "step": "plan",  "filter": "...", "kept": 318 }, ... ],
    "citations": { "[1]": { "layer": "fact",  "id": "fact_01HX..." }, "[2]": { "layer": "episode", "id": "ep_01HX..." } }
  },
  "diagnostics": {
    "time_ms": { "plan": 4, "fetch": 36, "score": 18, "pack": 9 },
    "layers_requested": ["beliefs", "facts", "episodes"],
    "policy_attribution": [ { "capability": "scope.read.holistic", "decided_by_tier": "scope" } ]
  }
}

Degraded recalls

When a retrieval source fails, the recall still returns — partially — and says so in diagnostics:

{
  "diagnostics": {
    "_partial": true,
    "degraded_sources": ["coordinator_recall: <error detail>"]
  }
}

Check diagnostics._partial if you need to distinguish "nothing matched" from "a source was down."

pack_id can be reused by /v1/answer via use_pack_id to skip recall (60 s TTL; the pack must belong to the same scope as the request).


POST /v1/recall/stream

Server-Sent Events. Same request body. Per-layer events arrive as soon as each layer scores; done event carries the full pack.

event: plan
data: { "scope": "...", "filters": "...", "estimated_layers": ["facts", "beliefs"] }

event: layer
data: { "layer": "facts", "items": [...] }

event: layer
data: { "layer": "beliefs", "items": [...] }

event: context_block
data: { "text": "..." }

event: provenance
data: { "trail": [...], "citations": {...} }

event: diagnostics
data: { "time_ms": {...} }

event: done
data: { "pack_id": "pack_01HX..." }

See Streaming for reconnection + backpressure semantics.