crewship memory
Access memory FTS5 indexes on the local filesystem without a running server — useful for development, debugging, and scripting — plus the server-side reads that work from any machine:inventory, health, hybrid and versions.
Subcommands
search
FTS5 search across memory with scope control.
Examples:
status
Show memory index statistics.--path and --scope decide together) and the cause — the directory does not exist, is not a directory, cannot be entered, or holds an index.sqlite that cannot be opened. When every scope fails the command exits 3; a partial failure exits 0 with the successful scopes on stdout. SQLite’s own unable to open database file (14) is never what you see: that string is identical for all four causes and names none of them.
When the base path itself is missing, that is a mistyped --path and the message says so:
reindex is the fix and it creates the directory itself:
health
Print the 5-metric memory health score for the caller’s workspace. Hits the running server (requirescrewship login and a workspace context) — unlike search/status/reindex which read local FTS indexes, health calls GET /api/v1/memory/health, which recomputes fresh on every request from five aggregate SQL queries. The persisted memory_health_snapshots table is for trend graphs, not for this command.
The global
--format flag is honoured (table, json, yaml, ndjson).
Example:
77/100 is colour-coded — red below 50, yellow 50–74, green 75 and above. The colour is applied via terminal escape codes; in pipes (| cat or --format json) it disappears. See Episodic memory — health scoring for what each metric measures and the weighted-composite formula.
reindex
Rebuild FTS5 index from markdown files. Signal-aware (responds to SIGINT/SIGTERM)..memory a crew has never had is one reindex away rather than a mkdir you have to work out. It will not create the base path: a --path whose own directory is absent is a typo, and inventing the tree would hide it.
Creating .memory needs the base path to exist and be writable by you. When it is not, reindex says so rather than reporting the directory as merely missing — that wording advises running reindex, which is the command that just failed:
3 when the reason is that no scope had a directory to index, which is the code status uses for the same condition, and 1 otherwise. Per-scope failures go to stderr with the same actionable wording status uses.
hybrid
Search workspace memory through the server’s hybrid engine — full-text chunks plus episodic journal recall, merged and ranked. Unlikesearch (local filesystem FTS), this requires a login token and works from any machine.
inventory (server API)
List the current knowledge documents of one agent or one crew, as the server reads them right now — the same read the crew Memory tab makes, overGET /api/v1/agents/{agentId}/memory or GET /api/v1/crews/{crewId}/memory.
Requires a login token and a workspace; works from any machine. It never
starts or provisions a container.
Exactly one of the two is required. Both add the workspace-wide documents
when the server has a workspace memory root configured.
What is listed:
AGENT.md, CREW.md, BRIEF.md, LEAD.md, pins.md,
lessons.md, learned-*.md and daily/*.md (workspace scope: every .md
except PERSONA.md). Personal users/ and peers/ files are never included
— read your own through crewship privacy; personas have crewship persona.
Human output leads with one line of per-scope states and then one row per
document:
A document row’s
STATE is available or unavailable: an unreadable or
oversized file (over 64 KiB, or past the 512 KiB per-scope budget) is listed
with no content, which is not the same as empty content. REVISION is the
first 12 hex characters of the content’s SHA-256; the full digest, the
content itself and the history_path to pass to
memory versions list are in --format json.
--format quiet prints the bare document ids.
Exit codes: 3 when the agent or crew does not resolve in the workspace;
non-zero with the server’s sentence on 503 memory storage unavailable.
versions (server API)
Thememory versions group mirrors log/show/restore over the running server’s API — use these from any machine; the direct-DB commands below only work on the server host. The workspace comes from the auth context.
restore requires OWNER/ADMIN, prompts for confirmation (--yes skips), and the server confines <canonical-path> to its configured memory root.
list columns: SHA256, WRITTEN, BYTES, WRITTEN BY. --limit defaults to 20 and the server clamps it to 1–1000.
Projection state — “nothing here” vs “we could not look”
list leads with a projection state whenever it changes how the list should be read. An empty version history has two completely different meanings and they used to print the same empty table:
Recorded paths are
agent:<slug>/… or crew:<crew_id>/… ending in AGENT.md, CREW.md, pins.md, learned-*.md, or daily/*.md. Everything else — lessons.md, PERSONA.md, peers/* — is unrecorded and has its own history surface; the reason text names it.
The state and its reason are printed above the table in human output and carried verbatim in --format json:
A server predating this field answers without it. The CLI reads that as
recorded — the state every path had when the only writers were recording ones — so an older server is never reported as having versioning switched off.log
List thememory_versions audit chain for a path, newest-first. Reads the server the CLI targets, via GET /api/v1/admin/memory/versions (ADMIN+).
Until #2086 this
command opened
~/.crewship/crewship.db directly and ignored --server /
CREWSHIP_SERVER / --profile — while the route above already existed and
had no CLI command at all. On any host where crewshipd runs with its own
DATABASE_URL (every development clone uses file:./crewship.db) it
therefore reported an audit chain that was not the one being audited.--local is the old behaviour, asked for explicitly: it reads the database
file on this host, works with the server down, and prints the path it opened.
It is also the only path that reports payload_ref — the API deliberately
does not hand out on-disk blob locations.<path> is the audit-trail identifier the consolidator + approve flow record under. For canonical learned files this is crew:<crew_id>/learned-YYYY-MM-DD.md (see internal/consolidate.canonicalAuditPath); for pins it’s crew:<crew_id>/pins.md.
Empty result prints
no versions for <ws> @ <path> to stderr and exits 0.
Partial results on a very busy workspace. The route filters by path
prefix while this command wants one exact path, and rows come back ordered
by Exit code stays
(written_at, id) across the whole workspace rather than per path. So a
rarely-written file can sit behind a long run of unrelated versions. The CLI
walks at most 200 pages of 500 rows; if it stops there it prints the matches it
found and warns on stderr:0 and stdout still carries only rows, so --format json | jq
is unaffected — check stderr before treating a short list as the whole chain.
--local has no ceiling: it queries the file directly.show
Print the raw content of one historical version to stdout. The canonical file on disk is not touched — this is the “preview without restoring” path.(path, sha) through
GET /api/v1/admin/memory/versions, then its bytes are streamed from
GET /api/v1/admin/memory/versions/{id}/content. Two calls because the content
route is keyed by row id while the arguments here are the audit chain’s own
coordinates — which is what memory log puts in front of you.
--local reads the database file and blob store on this host instead.
Stdout = raw blob bytes (pipe-friendly). Stderr carries status/errors. Exit codes:
0— blob found and streamed1— version not found or read error2— invalid usage
log. That is still 1 / version not found — the ceiling’s stderr
warning prints first, so a not-found that might be a truncation artefact says
so rather than masquerading as a different error.
restore
Atomically replace the canonical memory file at<canonical-path> with the content of version <sha>, then write a fresh memory_versions row so the chain stays forward-only — history is never rewritten.
--server / CREWSHIP_SERVER / --profile names a server it
refuses rather than restore from another instance’s history; --local is how
you say you mean this host. Stop the server first: the command writes the
database file, and a running server owns the only writer.
The path guard rejects empty strings, any path containing
.., and any target whose absolute form does not start with {blob-root}/.. (the data dir, one level above versions).
export
Write memory out as a portable OKF bundle — markdown with YAML frontmatter, readable and git-friendly. Goes through the server, so it works from any machine the CLI can reach.
OWNER/ADMIN only — the bundle contains every private note the agent holds.
The same export is available in the dashboard: an agent’s Memory tab has an Export button that downloads the bundle. Import has no UI equivalent — see Memory Portability.
import
Read a memory directory produced by another harness, map it onto Crewship’s tiers, and write it in. Recognisescrewship, okf, nanoclaw and openclaw layouts.
--apply requires OWNER/ADMIN, the same as export — it writes into the context an agent reasons from.
Imported documents pass through the same guards an agent’s own writes do: a closed allowlist of paths, per-file size ceilings, secret and prompt-injection scanning, and symlink-safe confinement. Refusals are listed per document and the command exits non-zero; a failed document does not stop the rest. Full mapping table and limits: Memory Portability.
Scope and Path Resolution
The meaning of--path depends on the selected scope: