How a target is resolved
Every command that takes<run-id|stream> resolves it the same way:
- If the value contains a
/, it is used as a stream name verbatim. No lookup happens. - Otherwise the store’s stream list is searched for an exact name match.
- Failing that, it is searched for any stream ending in
/runs/<value>.
receipt trace agents/triage/runs/run_abc addresses a stream directly, while receipt trace run_abc searches for it.
Reading a chain
receipt trace
unknown when a receipt has none:
{ "stream": "…", "receipts": [ { "index", "ts", "isoTs", "type" } ] }.
receipt replay
{ "stream": "…", "receipts": [ … ] }.
receipt replay is always JSON. --json is accepted by the parser and then ignored — there is no text mode, whether or not you pass the flag.receipt inspect
{ "stream": "…", "count": <n>, "head": <receipt body|null> }.
receipt fork
--atis required (--at is required) and must be a finite, non-negative number (--at must be a non-negative number). It is floored.--atpast the end of the chain is rejected by the runtime withCannot fork <stream> at <n>; valid range is 0..<length>.--namedefaults to<stream>/branches/fork_<base36 timestamp>_<index>.
{ "ok": true, "stream": "…", "at": <n>, "branch": "…" }.
Auditing every chain: receipt dst
receipt simulate is an undocumented alias for the same command.
It walks every stream in the receipt store — optionally narrowed to those whose name starts with a prefix, given positionally or with --prefix — and audits each one for three things: chain integrity, replay, and determinism. --context additionally audits the Factory task context packets (manifest, context pack, prompt, memory script).
The report counts streams by kind. The kinds it recognises are:
factory.objective, job, agent.history, agent.control, eval.run, computer_use.session, generic
Streams are sorted failures first, then by descending receipt count, then by name, so the interesting ones are at the top of both output modes.
--limit <n> affects text output only; the text renderer shows 20 streams by default and appends - ... <n> more stream(s) omitted when it truncates. The JSON report always contains every stream.
--strict is the gate
Without --strict, receipt dst reports failures and exits 0. With --strict, it prints the report first and then throws when any of the integrity, replay or deterministic failure counts is non-zero — including the equivalent counts from the --context audit when you asked for one:
1. --strict is the flag to put in a check script.
Driving jobs: receipt jobs
list is also the default when you give no subcommand. Anything unrecognised throws Unknown jobs subcommand '<x>'.
Every subcommand reads and writes the job queue in Postgres, so all of them work with no Resonate server running. Only enqueue also asks Resonate to dispatch the new job, and that request is fire-and-forget: with no broker reachable the job is still recorded as queued, the command still succeeds, and nothing starts the work. Every jobs and abort call opens a Resonate poll connection regardless, so with the broker down each one also prints a Resonate poll disconnected; retrying warning to standard error.
receipt jobs list
--limit defaults to 50 and is clamped to 1…500; a non-numeric value falls back to 50. --status is passed straight through without validation. Output is always JSON: { "jobs": [ … ] }.
receipt jobs enqueue
agent id is required. --payload-json defaults to {} and must parse as a JSON object: valid JSON that is not an object throws --payload-json must be a JSON object, and text that is not JSON at all surfaces the parser’s own JSON Parse error: …. --max-attempts defaults to 2 and the backend clamps it to 1…8; a non-numeric value throws --max-attempts must be a number before anything is enqueued. Output is { "ok": true, "job": { … } }.
receipt jobs wait
job id is required; an unknown one throws job not found: <jobId>. Always JSON: { "job": { … } }.
receipt jobs steer and receipt jobs follow-up
steer or follow_up queue command against the job, attributed to receipt-cli. An unknown job throws job not found: <jobId>. Output is { "ok": true, "jobId": "…", "commandId": "…" }.
receipt jobs abort and receipt abort
--reason defaults to abort requested, and the command is attributed to receipt-cli. A missing id throws job id is required.
Memory: receipt memory
memory subcommand is required; an unknown one throws Unknown memory subcommand '<x>'.
Every call needs a scope and an actor
All subcommands exceptprefs take a <scope> positional; without it they throw memory scope is required.
All of them, prefs included, require an actor identity — a user id and an organization id, from flags or from the saved CLI session. The errors name the subcommand:
prefs the prefix is memory.prefs.<sub> instead. Because the saved session seeds RECEIPT_CONNECT_USER_ID and RECEIPT_CONNECT_ORGANIZATION_ID, signing in with receipt login is normally enough and you never pass the flags. Every call records an audit entry carrying the user id, organization id, source: "cli", actor: "cli" and the command name.
The subcommands
read, search, summarize and diff are always JSON and honour --output-file. commit prints its JSON directly and ignores --output-file.
receipt memory prefs
list; an unknown one throws Unknown memory prefs subcommand '<x>'.
--scope defaults to layered and takes three values:
layered— the repo scope first, then the global scoperepo— the repo scope onlyglobal— the global scope only
--repo-root or the detected git root. list returns { "scopes": [ … ], "entries": [ … ] }. add requires --text or trailing text (memory prefs add requires --text or trailing text) and returns { "entry": … }. remove requires an entry id (memory prefs remove requires an entry id) and rejects an unknown one with Unknown preference entry '<id>', returning { "removed": …, "entryId": "…", "scope": "…" }.
Session search: receipt sessions
sessions queries the projected session messages in Postgres directly and needs no actor identity. A missing subcommand throws sessions subcommand is required; an unknown one throws Unknown sessions subcommand '<x>'.
searchruns a Postgres full-text search and requires a query, from--queryor trailing text (sessions search requires --query or trailing query text).--limitdefaults to 10, clamped 1…100. Output is{ "results": [ … ] }.readrequires a target (sessions read requires a chat id or session stream). A target containing/sessions/is treated as a session stream; anything else is treated as a chat id.--limitdefaults to 200, clamped 1…1 000. Output is{ "messages": [ … ] }.
Prerequisites, by group
Without a Postgres connection string the failure is: