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 byinternal/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
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:
Hybrid search
k = 60):
- FTS5 / BM25 — the workspace-tier full-text index over markdown memory.
- Episodic recall — dense-vector + BM25 recall over the crew journal.
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
null
(fts / episodic both carry omitempty): an FTS-sourced hit has no
episodic key and vice-versa.
Memory versions audit trail
The HTTP mirror ofcrewship 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_idis always pulled from the session — never accepted as a query parameter or body field.crew_id, when set, is validated viacrewBelongsToWorkspace(same helper as the Paymaster API). Cross-tenant lookups return404.
Related
- Episodic memory guide.
crewship memory health— CLI wrapper.- Crew Journal — source of indexed entries.