Skip to main content
The three memory calls. Each takes --space, --api-key, --base-url and --json, plus the global options. A flag you do not give is left out of the request, so the server’s own defaults apply. A malformed value (a date that does not parse, a --metadata that is not a JSON object, an empty tag) exits 2 and sends nothing. Dates are ISO 8601: 2026-06-01, 2026-06-01T09:00:00Z or 2026-06-01T09:00:00+02:00, sent as you typed them. See What each package has.

record

Store a memory. A write is extracted into the facts it contains rather than stored verbatim, so one sentence can become two memories.
record prints what was stored, and the memory ids:
A write that extracts to nothing is not a success. Short, context-free content often produces no fact at all. The API accepts the request with status: "nothing_extracted" and no ids; record prints the API’s advice on stderr and exits 3. The usual fix is to record again with a sentence of context: what the thing is, or why it matters. Empty content, from any of the three sources, exits 2. --json: {"memory_id", "memory_ids": [...], "status", "message"?, "usage"}. With --async: {"job_id", "status"}.

Background writes

A plain record waits for extraction, which is one model call. --async queues the write and returns as soon as the server has accepted it:
Add --wait to queue it and then poll until it finishes. Polling a job is a read: it costs nothing and is safe to repeat. The exit code then reports what the job did: 0 stored, 3 completed but stored nothing, 1 failed or was cancelled, 8 still running when --wait-timeout ran out (check later with anona jobs get). --wait on a plain record exits 2, since a plain record already waits. With --wait --json, the document is {"submitted": <the queued response>, "jobs": [<one jobs get document per job>]}.

Batch ingest

--batch FILE records up to 100 memories in one queued call. The file is JSON Lines: one item per line, either a JSON string (the content alone) or an object with content and, optionally, any of context, timestamp, metadata, tags, user_id, agent_id, session_id. Blank lines are skipped.
The whole file is checked before anything is sent: a line that is not valid JSON, an unknown field, an empty content, an empty file or more than 100 items exits 2, names the line, and sends nothing. Split a larger export into files of 100. --tags, --timestamp and --metadata cannot be combined with --batch; put them on each line. --user-id, --agent-id and --session-id apply to every item. --json: {"job_id", "job_ids", "status", "accepted"}, or with --wait the submitted / jobs document above. For very large imports, see Bulk import with webhooks.

retrieve

Search your memories by meaning.
Plain output is one memory per line, with its relevance score and the first eight characters of its id:
A search that matches nothing prints No memories matched. and exits 0. Scores are close to two-valued: about 1.1 for a near-verbatim match, about 0.0001 for a correct match worded differently. Most --min-score floors therefore keep only the near-verbatim matches. See the retrieve API before setting one. A search carrying a scope id always matches tags strictly, whatever --tags-match says. --as-of is about when a memory was recorded; --occurred-after / --occurred-before about when the thing it describes happened. History imported today has today’s record time and its own event time. --tag-groups takes a JSON array of {"tags": [...], "match": ...}, {"and": [...]}, {"or": [...]} and {"not": {...}} expressions; a single object is taken as a one-element array. Only the shape is checked locally, the grammar and limits are the server’s:
--format block prints the context string itself, ready to paste into a prompt:
--max-tokens without --format block exits 2. --json: {"results": [{"memory_id", "content", "relevance_score", "memory_type", "tags", ...}]}, every row as the retrieve API returns it. With --format block: {"results": [...], "context", "token_estimate"}. An empty search is {"results": []} with exit 0.

reason

Ask a question and get an answer synthesized from your memories. Use it when no single memory holds the answer.
reason is an agent loop rather than a lookup, so it takes tens of seconds and sometimes longer. It says so on stderr while it works, so anona reason "..." > answer.md captures only the answer. --depth thorough is the second look to ask for when an answer reads stale. --json: {"insights", "sources": {"models", "memories", "notes"}, "rules_applied": [...], "model", "usage"}. sources says what the answer was built from, which the plain output does not show.