Skip to main content
The Memory API exposes the read surfaces over an agent’s episodic and markdown memory: a health snapshot that scores how usable the memory is, a hybrid recall search that fuses two retrieval engines, and the version audit trail for canonical memory files. The mutating restore endpoint lives on the Admin reference because it requires OWNER/ADMIN.
Every endpoint requires authentication and workspace context. workspace_id is accepted only by the workspace middleware (query parameter, path context, or X-Workspace-ID); it is never part of a memory operation’s payload. crew_id, when set, is validated against the caller’s workspace (cross-tenant lookups return 404).

Endpoints

Export and import require OWNER or ADMIN (the route’s manage role). The workspace is selected by the authenticated session’s workspace context; workspace_id is not part of either operation’s request payload. Both require crew_id; an empty agent_slug addresses crew-shared memory.

Memory portability

GET /api/v1/memory/export

Request: no body. Required query parameter crew_id identifies a crew in the caller’s workspace; optional agent_slug selects an agent within that crew. With no format (or any value other than zip), the response is 200 OK, application/json:
documents and skipped are always arrays. Document fields are path, tier, and body, with scope, title, tags, and sources omitted when empty. Each skipped entry has source and reason. With format=zip, a non-empty scope returns 200 OK with Content-Type: application/zip, Content-Disposition: attachment, and a Content-Length; the body is the OKF ZIP bundle, not JSON.

POST /api/v1/memory/import

Request: application/json, capped at 32 MiB:
crew_id, agent_slug, and documents are request fields; every document requires path, tier, and body. The operation is per-document rather than transactional. 200 OK returns:
detail is omitted when empty; a successful response can contain rejected or failed documents. Prompt-injection findings are reported in rejected with kind: "prompt_injection".

Health

Read-only snapshot for the memory health dashboard. Backed by internal/consolidate.ComputeHealth. The five aggregate queries it runs are cheap, so the handler recomputes on every request rather than reading the persisted memory_health_snapshots table — those snapshots exist for time-series plots, not real-time reads. See Episodic memory — health scoring for the formula and operator interpretation.

Get health snapshot

Query parameters: Auth: Every workspace member can read. The response contains only counts and ratios, no raw entry content. Response: 200 OK
There is no separate band field — clients categorise locally: The CLI uses these exact thresholds (internal/cli colour helpers) and the FE follows. Errors:
Single-shot memory recall that fuses two retrieval engines and merges their results with Reciprocal Rank Fusion (RRF, k = 60):
  • FTS5 / BM25 — the workspace-tier full-text index over markdown memory.
  • Episodic recall — dense-vector + BM25 recall over the crew journal.
The handler degrades gracefully: if only one engine is wired (no embedder, or no FTS engine for the workspace), it returns that engine’s results alone; if neither has matches it returns 200 with an empty hits array and count: 0 — the same shape the sidecar /memory/search uses. Auth: required + workspace context (MEMBER+). Every query is anchored on the caller’s session workspace, so a foreign workspace_id cannot be smuggled through the body. Request body:
Response: 200 OK
The unused half of each hit is omitted, not emitted as null (fts / episodic both carry omitempty): an FTS-sourced hit has no episodic key and vice-versa.

Memory versions audit trail

The HTTP mirror of crewship memory log/show. Workspace is anchored from the session — query strings never carry workspace_id, so a cross-workspace probe can’t smuggle a foreign id through. Restore (POST /api/v1/memory/versions/{sha}/restore) is documented separately on the Admin reference because it requires OWNER/ADMIN and mutates canonical state; the two read endpoints below are MEMBER+.

GET /api/v1/memory/versions

Returns the audit chain for one canonical memory path, newest-first. Auth: required + workspace context. Query parameters: Response: 200 OK
projection — whether an empty entries may be read as a fact. memory_versions is a projection of the .memory tree, not the tree itself: a file appears only if some writer records it. An unprojected path and a path nobody has written to both answer {"entries": []}, and a client cannot tell them apart — so the server says which it is. Clients must not hard-code the list of projected tiers; it is a property of the writers and it changes.

GET /api/v1/memory/versions/{sha}

Returns the raw blob bytes for one historical version. Pipe-friendly: the body is the historical content, metadata travels in headers so a CLI pipe to a file produces the exact bytes that were written. Auth: required + workspace context. Path parameters: Query parameters: Response: 200 OK — raw bytes, Content-Type: application/octet-stream.
The restore endpoint (POST /api/v1/memory/versions/{sha}/restore) is OWNER/ADMIN-only and applies extra server-side path confinement to refuse canonical targets outside the configured memory root. See the Admin reference for the full mutation surface.

Tenancy

  • workspace_id is always pulled from the session — never accepted as a query parameter or body field.
  • crew_id, when set, is validated via crewBelongsToWorkspace (same helper as the Paymaster API). Cross-tenant lookups return 404.