Skip to main content

Memory Portability

Overview

Crewship stores agent memory as plain markdown on disk — AGENT.md, CREW.md, pins.md, PERSONA.md, daily/<date>.md, peers/<user>.md. Memory portability turns that into something you can move: export writes a bundle you can read, diff and keep in git, and import brings memory in from another harness that stores it the same way. This is deliberately not a backup. crewship backup produces an encrypted archive built for disaster recovery — correct for restoring an instance, useless for reading. A portability bundle is the opposite: no encryption, no database, just the files, with a YAML header on each one saying what it is. The format is OKF (Open Knowledge Format, published by Google Cloud in June 2026) — a vendor-neutral spec for agent knowledge as markdown plus YAML frontmatter. Using a published spec rather than our own directory convention is the whole point: a bundle should outlive the tool that wrote it.

When to use it

  • Moving an agent between instances — export from one, import into another.
  • Migrating from another harness — you have memory in NanoClaw or OpenClaw and want it to be your agent’s starting knowledge.
  • Reviewing what an agent knows — a bundle in a git repo makes memory drift visible in a diff.
  • Leaving — your agents’ knowledge is yours; this is how it walks out the door.

Export

The result is a directory mirroring the memory layout, plus an okf.yaml manifest:
Each file carries a header naming its tier and where it came from:
Exporting the same memory twice produces byte-identical output, so a bundle kept in git shows real changes rather than reshuffled keys.
Export is OWNER/ADMIN only. It reads every private note an agent holds, including operator-model peer cards about named people — that is not member-grade data.

Import

Known limitation (#1741). --apply writes into the memory tree from the host process. On deployments where that tree is owned by the container user — which is the current default, see #1623 — the server can read it but not write it, and every document is refused with “write failed on the server”.crewship memory export is unaffected and works today. Verified end to end on a dev instance: export succeeds against the same directory the import cannot write.
Import reads a source directory on your machine, maps it onto Crewship’s tiers, shows you the plan, and only writes when you say so.
Nothing is written without --apply. An import lands in the context an agent reasons from; reviewing it afterwards is too late. The default run prints the mapping and exits.
The plan names every target and its sources, and everything being left behind:

Supported sources

The layout is detected from the directory’s shape; --format overrides the guess. An unrecognised tree is refused rather than guessed at.

How sources map onto tiers

A live .memory tree is read as plain markdown and passed through byte for byte — a note that opens with a --- thematic break keeps it. Only bundles (which carry the manifest) are parsed for frontmatter. When several source files collapse into one canonical file, each gets a ## <source> heading so you can still tell them apart afterwards.

Choices the import will not make for you

  • Which NanoClaw group. A source holding more than one group is refused until you pass --group. Merging two groups produces one agent that believes it was in both conversations, and no later edit untangles that.
  • Who an operator card belongs to. OpenClaw’s USER.md describes a person. Without --operator <slug> it is skipped rather than filed under a guessed name.
  • Whether to touch crew-shared memory. Importing into --agent alex holds back crew-tier documents; every agent in the crew reads those. Pass --with-crew to include them — they are written to the crew tier, not into the agent’s directory.

Policy on the way in

Imported documents go through the same writer an agent’s own memory writes use, and the same guards:
  • A closed allowlist of paths. AGENT.md, CREW.md, PERSONA.md, pins.md, daily/<name>.md, peers/<name>.md, and the crew’s <slug>/topics/pins.md. Anything else is refused and named — the same answer every other write surface in the product gives. A path must arrive in canonical form, so what you saw in the plan is what lands on disk.
  • Consolidator-owned files are refused. lessons.md, learned.md and learned-<topic>.md carry a YAML schema and their own locking; replacing one with freeform markdown would destroy the store and break every later lesson write. They export (so your bundle is complete) and they do not import.
  • Symlinks do not redirect a write. Parent directories are created one segment at a time and the final target is re-checked against the canonicalised root, so a link planted inside .memory cannot send an imported document into another crew’s tree.
  • Per-file size ceilings — the same ones agents live under (AGENT.md 4 KB, pins.md 8 KB, daily logs 30 KB).
  • Secret scanning in block mode — a document carrying a live credential is refused and named, not silently redacted. If a token was in your notes, you want to know.
  • Prompt-injection scanning — the same scan every memory write runs. Foreign memory is the least trustworthy input this feature has; a payload that got through would be blanked at load time while sitting in the search index.
  • Atomic replace + version record — an import is visible in crewship memory versions like any other write.
Refusals and rejections are reported per document and the command exits non-zero. A document that fails does not stop the ones after it: the operator is told exactly which landed and which did not, because a half-applied import reported as a clean failure is how memory silently diverges from what you think it holds.

Reading is confined too

Export never follows a symlink out of the tree it was asked for. The directory being read is one the agent itself owns, so a .md pointed elsewhere would otherwise return another crew’s memory inside a bundle scoped to one agent. Links are skipped and listed under NOT exported rather than failing the whole export — a planted link should not become a denial of service against the operator.

API

The server reads and writes only its own memory tree. Recognising a foreign layout happens in the CLI, against files on your machine — the wire carries already-mapped documents, so no foreign directory structure ever reaches the server.

Limits

  • Import replaces, it does not merge. A document that already exists is overwritten. Export first if you want the old copy.
  • No transcripts or embeddings. Conversation history and vector indexes are derived data; Crewship rebuilds its own.
  • One group per import. Run it again for the next one.
  • Consolidator-owned files export but do not import. See the allowlist above.
  • An import is not transactional. Each document is replaced atomically on its own; there is no rollback across the set. The response names every document that landed.