receipt factory is how you drive Factory from a terminal: create an objective, watch it work, steer or abort a running job, read back what happened from the receipt chain, and — through receipt factory agent — do all of that from a script that reads one predictable JSON envelope.
Reaching the subtree
From a checkout, any of these work:There is one difference between them worth knowing. The CLI discovers
.receipt/config.json by walking up from the working directory, so where you stand matters — except that the .receipt/bin/receipt wrapper changes to its own checkout’s root and exports RECEIPT_REPO_ROOT before it starts, and bun run receipt:factory is that same wrapper. So the first and third forms always target the checkout the wrapper lives in, while bun src/cli.ts factory … follows your current directory. --repo-root or RECEIPT_REPO_ROOT pins the location either way.How flags are parsed
receipt factory uses the developer CLI’s own parser, described on The in-repo developer CLI. Two of its rules shape the flags on this page: a repeated flag becomes an array, which is what makes --check a --check b and repeated --initial-task accumulate, and a numeric flag throws --<key> must be a number on a non-numeric value before clamping.
An unrecognised subcommand fails with Unknown factory subcommand '<x>'.
Shared flags
--execution-target conflicts with the two flags it subsumes:
--execution-target conflicts with --execution-path--execution-target conflicts with --computer-provider
--model is not a receipt factory flag. The Factory worker model is set only through the RECEIPT_FACTORY_TASK_MODEL environment variable.Initialization
receipt factory init
.receipt/config.json. It resolves the repository root from --repo-root, then the git root of your current directory, then the directory itself, and requires a git repository. --data-dir defaults to .receipt/data relative to that root. --codex-bin takes the flag, then codex if it is on PATH, then RECEIPT_CODEX_BIN, then the literal codex.
Interactively, and without --yes, it prints Receipt Factory setup and prompts for the data directory and the Codex executable. Cancelling prints Factory setup canceled. and throws Factory setup canceled. It then shows a spinner labelled Profiling repository: collecting repository status and Factory defaults, followed by Repository profile collected in <dur> and a summary:
Use detected validation commands?; declining prompts for Validation commands (comma or newline separated).
Without --force, an existing file refuses with Factory config already exists at <path>.
Output:
--jsonreturns{ok, config, profileSummary, environment}, whereenvironmentcarriesbunRuntime,codexPath,codexAvailable,openAiReady,sourceBranchandsourceDirty.openAiReadyis hard-codedfalseand tells you nothing.- Interactively and without
--yes, it printsFactory config written to <path>,Next: bun run factoryandCreate objective: bun run factory run --title "Mission" --prompt "Describe the change". - Otherwise — non-interactively, or with
--yes— it printsfactory config written: <path>.
› glyph becomes > when RECEIPT_FORCE_ASCII=1 or TERM=dumb.
Creating objectives and staying attached
receipt factory run
--prompt, then --problem, then the trailing words; with none of them it fails with factory run requires --prompt or trailing prompt text. The title comes from --title, otherwise from the prompt’s first sentence clipped to 96 characters with ….
How it stays attached depends on the terminal. On an interactive terminal — stdin and stdout both TTYs — and without --json, run opens the board TUI focused on the new objective and leaves when the objective reaches a terminal state. Everywhere else it waits headlessly and reports one progress line:
--json suppresses the progress line entirely and prints only the closing snapshot. Either way it polls every 2000 ms and also wakes on runtime events.
Exit codes:
Exit code 2 is not a failure. It means Factory stopped and is waiting for you — either the objective is blocked on operator guidance, or it is ready and auto-promotion is off, which is the normal case in a stock checkout.
completed, failed, canceled or blocked and no audit job exists yet: payload kind factory.objective.audit, agent factory-control, lane collect, session key factory:audit:<objectiveId>, singleton mode steer, one attempt. It then waits up to 10 seconds for that job, unless you passed --json. If the terminal receipt snapshot is missing it throws cannot audit <objectiveId>: terminal receipt snapshot is unavailable, which is reported as factory audit enqueue failed after terminal objective: <message> and does not change the exit code.
receipt factory create
The same flag surface as run, but it returns as soon as the objective is created. Missing prompt: factory create requires --prompt or trailing prompt text.
receipt factory compose
--objective it creates a new objective. With --objective <id> it reacts to the existing objective, attaching the prompt as an operator note. Missing prompt: factory compose requires --prompt or trailing prompt text.
Reading an objective
receipt factory watch and receipt factory inspect
factory watch requires <objective-id> / factory inspect requires <objective-id>.
watch prints a one-shot snapshot with --json, or whenever the session is not an interactive terminal, and opens the TUI focused on that objective otherwise. inspect never opens the TUI. With --watch it re-renders on an interval — --interval-ms, default 1000, clamped 250 to 60000 — printing only when the rendered output changes, separated by a --- line in text mode.
Panels. Exactly nine values are accepted:
overview, report, tasks, candidates, evidence, activity, live, debug, receipts
With --panel omitted, the default is report for an investigation objective that has a synthesized report, or is completed with reports — unless the latest handoff body looks like a Markdown table, in which case it is overview.
The JSON payload is {objectiveId, panel, data}, where data is the panel’s own value: the tasks, candidates, evidence cards, activity, live projection, debug projection or recent receipts respectively; overview returns {header, prompt, checks, policy, blockedExplanation, latestDecision} and report returns {objectiveId, objectiveMode, severity, report, synthesized, reports, artifacts}.
Text mode prints a header followed by a == <Panel> == section:
Read and analysis commands
Target resolution
parse, investigate, doctor and a targeted audit accept any of an objective id, task id, candidate id, job id, run id, chat id or a raw stream name, and resolve them in this fixed order:
- Empty, or the literal
latest— the newest objective stream. With none:No objective receipt streams found under <dataDir> - An exact stream name
factory/objectives/<id>jobs/<id>- Any stream ending
/runs/<id> - Any stream ending
/sessions/<id>that has no/runs/in it - Ids starting
task_or containing_candidate_, by scanning objective chains - A substring match on stream names
- Otherwise:
Unable to resolve factory receipt target '<id>'
matchedBy field, so you can see when a fuzzy match found something you did not mean.
receipt factory investigate
--compact changes two defaults: the timeline limit from 20 to 12 (clamped 1–1000) and the context characters from 1200 to 700 (clamped 200–20000). --as-of-ts <epoch-ms> replays the chain as of a timestamp.
Text output opens # Factory Receipt Investigation with ## What Happened, ## Latency and ## Assessment. The JSON report carries requestedId, resolved, links, warnings, summary.whatHappened, objectiveMode, window, inputs, outputs, latency, canonicalEvidenceBundle, dag, packetContext, timeline, tasks, candidates, jobs, agentRuns, anomalies, audit, recommendations, autoFixObjectiveId, interventions and assessment.
Warnings you may see: Persisted objective audit is stale relative to the latest objective update., Audit recommendation generation failed: <error> (or Audit recommendation generation failed. when no detail was recorded), Invalid canonical evidence bundle at <path>: <error>.
receipt factory audit
--limit defaults to 12, clamped 1–200. Text opens # Factory Receipt Audit with ## Summary, ## Improvement Signals, ## Top Anomalies, ## Auto-Fix Feedback, ## Memory Hygiene, ## Objectives and ## Warnings. A targeted failure reads Failed to audit objective <id>: <message>.
receipt factory insights
--limit defaults to 8, clamped 1–50. The JSON carries schema: "receipt.factory.insights.v1". Text opens # Factory Receipt Insights with ## Summary, ## Improvement Insights, ## Recurring Anomalies, ## Objectives, ## Agent Use and ## Warnings.
receipt factory doctor
Stream read commands
These four load.receipt/config.json and use its dataDir; --data-dir does not reach them.
JSON switching and output files
--output-file creates parent directories and changes what is printed. In JSON mode it writes the payload and prints {"ok": true, "outputFile": "<abs>", "format": "json", "bytes": <n>, "sha256": "<hex>"}. In text mode it writes the text and prints wrote <abs path>.
Resumption
receipt factory resume
factory resume requires <objective-id>. It reacts to the objective and then attaches like run, with the same exit codes. One difference matters if you are scripting: run --json stays silent while it waits, but resume --json keeps printing progress lines before the closing JSON snapshot, so read its output as a stream rather than as one JSON document.
Objective mutations
reacttakes an optional message;noterequires one and appends it without reacting.promoteis gated — see the promotion gate for the 409 and the six refusal messages.canceldefaults--reasonto the literal stringcanceled from CLI. It cancels the objective’s jobs, then emits the cancel and handoff receipts.cleanupcancels objective-scoped jobs with the reasonfactory objective cleanupand removes task worktrees and runtime workspaces.archivecancels jobs with the reasonfactory objective archived, emits an archive receipt if one is not already there, and rebalances slots.
Expected prev hash … and … advanced before applying a mutation conflicts. Each one except note also asserts the action against the profile’s allowed dispatch actions first; a compose that continues an existing objective asserts react.
Text mode prints one line per mutation, <action> <objectiveId>, with two exceptions: note prints noted <objectiveId>, and a compose that carried a note prints reacted <objectiveId>. The JSON form is:
note appears only when a note or prompt was attached. The objective actions are create, compose, note, react, promote, cancel, cleanup and archive.
Job controls
The runtime answers with:
- 404
job not found - 400
steer message required/follow-up message required - 409
job <jobId> is <status>; send the follow-up to its objective to continue in a new run - 409
job <jobId> became <status>; send the follow-up to its objective to continue in a new run
abort is exempt from the active-status check, so you can abort a job that has already finished. Commands are attributed to factory.cli.
Job mutations print <action> queued for <jobId> in text mode; the JSON is {ok, kind: "job", action, jobId, job, commandId}, with the job actions abort, steer and follow_up.
The agent-first surface
receipt factory agent … is the machine-readable half of the subtree. Every action returns one envelope, on both the success and the failure path:
command is factory.agent.<action>, except in the computer lane where it is factory.agent.computer.<subaction> or factory.agent.opensandbox.<subaction>. mode is write for start, create, steer, follow-up, react, resume and for computer exec, run, write, upload and download; it is read everywhere else.
On the error path ok is false, data is null, and error is filled in:
code takes one of two forms: FACTORY_SERVICE_<httpStatus> when the underlying error carried a status, and FACTORY_AGENT_COMMAND_FAILED otherwise. details is present only in the first case. The process exit code is 1 on the error path, so you can branch on the exit status and still read the envelope.
--output-file on an agent command writes the full envelope to disk and prints a second, small envelope whose data is {outputFile, format: "json", bytes, sha256}, whose single artifactRef is labelled Factory agent envelope, and whose nextCommands is ["cat <path>"].
receipt factory agent, agent help, agent --help and agent -h print the help envelope before the config is loaded, so they work in a repository with no .receipt/config.json. Every other agent action loads the config first. An unrecognised action returns Unknown factory agent action '<x>' inside an error envelope.
Agent actions
Read-command envelopes suggest what to run next. For an objective those are:
The computer lane
agent opensandbox is an alias. The subaction defaults to status. The target comes from --target, --objective or --objective-id, then the positional argument, then the board’s selected objective; with none: 404 No selected objective; pass an objective id.
Every subaction that needs a lease — everything except
status and inspect — reports its source as either existing-lease or acquired-lease, which is the distinction that matters:
An exec result is {exitCode, signal?, stdout, stderr}, where exitCode can be null.
The interactive board
Barereceipt in an interactive terminal — no arguments — opens the Factory board, as do receipt factory and receipt factory board. Bare receipt passes no flags through, so off an interactive terminal it prints the CLI usage rather than a board. receipt factory and receipt factory board do respond to the flags: with --json, or when the session is not an interactive terminal, they print a snapshot instead of opening the UI: JSON as {compose, board, selected?, live?}, or text under the section headers == Repo ==, == Needs Attention ==, == Active ==, == Queued ==, == Completed ==, == Archived ==, == Selected Objective == and == Live Tasks ==.
The board’s compose panel is not derived from your repository. Its profile summary is always
Using checked-in Factory profiles and skills only., its validation commands are always ["bun run build"], and its policy is always the built-in default.Hotkeys
The panels, in order, are Overview, Report, Tasks, Candidates, Evidence, Activity, Live, Debug, Receipts and Analysis.
Slash commands
/abort-job also accepts abortjob; /follow-up also accepts followup and follow_up.
Plain text with no objective selected creates a new objective; with one selected it reacts to that objective. Unknown commands answer Unknown command '/<name>'. Try /help., and every objective-scoped command refuses with its own line when nothing is selected, such as Select an objective before steering its active job.
Commands this page does not cover
receipt factory simulate and receipt factory experiment are engineering harnesses rather than product surface; the simulator is documented in Testing, simulation, and stack validation. receipt factory helper list reads the checked-in helper manifests, and receipt factory helper run executes one through the profile’s Python runner, so run needs python3 on PATH.
Note that the usage text is incomplete. The one-line subcommand list — receipt factory [init|run|create|…] — omits agent, board, doctor, simulate and helper; the longer Factory block printed underneath adds agent, doctor and simulate back, but board and helper appear nowhere. There is also no per-subcommand help for run, create, compose, watch, inspect, resume, the mutations, the job controls, board, helper or init — asking for receipt factory run --help prints the whole default usage instead.
Next step: run the simulator and the stack checks.