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.

Current knowledge inventory

GET /api/v1/agents/{agentId}/memory

Reads the agent’s current knowledge and its crew’s shared knowledge. It does not start or provision a container. Requires an authenticated workspace member; agentId must belong to the workspace resolved from the session and workspace_id query parameter or X-Workspace-ID header. No request body. Both routes also include workspace knowledge when its storage root is configured. The CLI for both is crewship memory inventory --agent|--crew. Personal users/ and peers/ files are excluded: read your preferences through the /api/v1/users/me/user-model and /api/v1/users/me/peer-cards endpoints. Persona is edited through the agent or crew persona API. Response status codes for both routes: Reads are bounded to 64 KiB per document and 512 KiB per scope. Directory inventories above the supported bound are unavailable rather than partial counts. Symlinks are excluded. Responses use Cache-Control: private, no-store. History may be unavailable even when current content is readable.

GET /api/v1/crews/{crewId}/memory

Reads the crew’s shared knowledge. Requires an authenticated workspace member; crewId must belong to that workspace. The workspace selection and response contract are the same as the agent inventory. No request body. Response: 200 JSON with source, scopes, documents and peer_generation, using the inventory fields documented above. There is no agent scope on this route. Example for a new crew:
General member version-history routes reject personal users/ and peers/ paths with 403; use the self-service privacy APIs. Explicit administrator compliance routes retain their separate authorization.

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".

POST /api/v1/memory/initialize

Auth: OWNER or ADMIN in the target workspace. Used by crewship seed --server <url> --with-memory; all files belong to the server’s storage root. Request: application/json, capped at 128 KiB:
crew_id identifies a crew in the authenticated workspace. Optional agent_slug selects an agent in that crew. documents contains 1–8 entries, each with path and a non-empty body. Crew scope accepts CREW.md (4 KiB) and learned.md (8 KiB). Agent scope accepts AGENT.md (4 KiB), PERSONA.md (1536 bytes), pins.md (8 KiB), and daily/YYYY-MM-DD.md (32 KiB). Every document is validated before writes begin. Each missing file is published durably without replacing an existing file; retries preserve operator edits. Symlink parents and leaves are refused. The batch is not transactional: a storage failure can leave earlier documents initialized; retrying safely completes the missing documents. Fresh installation seeding initializes memory before container provisioning takes ownership of its tree. This endpoint is for host-writable bootstrap storage. A missing document in an already provisioned tree owned by the runtime user can return 409; it does not change ownership or permissions. Use the ordinary memory import API for live runtime edits. Response: 200 OK, with counts covering every requested document:

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.