Skip to main content

Lifecycle

Every session opens and closes with these verbs: stand the daemon up, mount a topology, register a workflow, check it is healthy, tear it back down.

orca version                            # sanity check (no daemon needed)
orca start # spawn the daemon, no system loaded
orca topology mount <spec> # build a SystemRuntime from a topology factory
orca workflow load <spec> # register a workflow on the mounted runtime
orca status # daemon + runtime health
orca unload # drop the runtime, keep the daemon
orca shutdown # unload (if needed) and exit the daemon

There is no single orca load verb. Bringing a system up takes two steps. topology mount builds the instrument and config foundation, described on Topology. workflow load then registers a workflow on it. On the local daemon both take a module:factory spec (module:build_topology, module:build_workflow). Against a Orca AI deployment they take a source-file path and a --message, covered on Code deployment.

orca version

Print the installed framework version. No side effects, no daemon required.

$ orca version
orca 1.0.0

--json form:

{"version": "1.0.0"}

The version is read from the installed cheshire-orca distribution. If that lookup fails, it prints unknown rather than erroring.

orca start

Spawn the daemon as a detached subprocess. Polls /health until ready, then prints the PID and port.

$ orca start
daemon started (pid=43821, port=51724). No system loaded -- run `orca topology mount <spec>` next.
FlagEffect
--port <n>Bind port. Default 0, which picks a free ephemeral port.

What happens:

  1. Refuse with exit 30 if a live daemon is already recorded in the PID file.
  2. Pick the requested port, or a free one when --port is 0.
  3. Spawn python -m orca.daemon --port <port> detached (CREATE_NO_WINDOW plus a new process group on Windows, start_new_session on POSIX).
  4. Capture the child's output to ~/.orca/daemon_startup.err until the daemon's own logging takes over.
  5. Poll GET /health for up to 10 seconds.
  6. Read back the PID file the daemon wrote for itself.

If the health probe times out, the CLI exits 50 and prints the tail of daemon_startup.err, so an import error or a crashed dependency is visible without re-running the daemon in the foreground.

Pitfalls:

  • start does not load a system. The daemon is up but idle. Run orca topology mount <spec> next.
  • Stale PID files: if the daemon was killed without shutdown, the recorded PID points at a dead process. start treats that as no daemon and re-spawns. status reports no daemon running and exits 10.
  • The daemon writes its own PID file. If /health answers but no PID file appears, start exits 1 and points you at ~/.orca/daemon.log.

orca topology mount <spec>

Builds the runtime foundation. On the local daemon, <spec> is a module:build_topology factory. The daemon imports the module, calls the factory, builds a SystemRuntime with no workflows on it, and starts it.

$ orca topology mount examples.hamilton_smc.topology:build_topology
mounted topology 'examples.hamilton_smc.topology:build_topology' (sim=False); runtime is RUNNING
FlagEffect
--simLocal only. Turns on the daemon's sim coroutine diagnostics for the mounted runtime and marks the mount as sim in /health.
--message / -mCloud only. Commit message for the submitted topology.py. Required on cloud.

--sim does not choose a run mode. Run mode is per submission: see --run-mode on Run a workflow and the sim hierarchy.

The spec must be importable from the daemon's working directory. If you launched orca start from /lab, then examples.hamilton_smc.topology resolves against /lab.

Mounting while a topology is already mounted exits 30 and tells you to orca unload first. A bad spec string exits 2; a module or factory that cannot be found exits 20.

Against an Orca AI deployment, <spec> is a path to a topology.py source file and --message is required; the submission triggers a full rebuild. See Code deployment.

orca workflow load <spec>

Registers a workflow on the mounted runtime. Validates and registers; does not run it. On the local daemon, <spec> is a module:build_workflow factory; against Orca AI it is a workflow source file plus --name and --message.

$ orca workflow load examples.hamilton_smc.workflow:build_workflow
loaded workflow 'smc_assay'
FlagEffect
--nameCloud only. Must match @orca.workflow(name=...). Required on cloud.
--message / -mCloud only. Commit message for the submitted source. Required on cloud.

Loading a workflow whose name is already registered replaces it. The prior template's bundled methods and thread templates are dropped first, then the new template is added. Nothing else in the runtime is touched, and no execution is stopped.

Replacing a template does not rewrite work already in flight, so a running execution keeps the definitions it started with. To change a single method or action inside a running labware thread, use execution thread insert-method instead.

Loading with no topology mounted exits 30. A name collision inside the workflow's own bundle exits 30 as well.

orca status

One-shot health view. What it prints depends on the resolved backend.

On the local daemon it reports the daemon process plus the loaded system:

$ orca status
daemon:
pid: 43821
port: 51724
uptime: 754s
system_loaded: True
spec: examples.hamilton_smc.topology:build_topology
runtime_state: RUNNING
sim: False

The --json form returns pid, port, started_at, uptime_seconds, health_reachable, system_loaded, spec, runtime_state and sim. When health_reachable is false, the last four are null: the PID is recorded but /health did not answer, so the CLI genuinely does not know.

On the cloud backend it renders the runtime-lifecycle snapshot instead, plus one list of everything stopping the run:

$ orca status --backend cloud
cloud runtime
built: True

what is stopping the run
kind severity what is wrong what to do
DEVICE_FAULT error shaker_01: 'shake' did not come back clean. orca device clear-fault shaker_01

The nine blocker kinds are RUNTIME_NOT_BUILT, DEVICE_FAULT, THREAD_ERROR_PAUSE, EXECUTION_PAUSED, WAITING_ON_A_PARKED_HOLDER, MANUAL_PLACE, MANUAL_REMOVE, MANUAL_STEP and DEVICE_EXTERNAL_CONTROL. They print worst first. Severity is error (something is broken) or warning (a person has to do the thing). Each row's last column is that blocker's recommended remedy, written as the command line to run.

Three outcomes are distinct, and the wording separates them:

  • Rows listed: that is what is in the way.
  • nothing is in the way: the list was read and it is empty.
  • the list could not be read; this is not an all-clear: the list is unknown. Do not read it as clear.

A device that may still be moving prints ! in the severity column instead of its severity, because any verdict on it would be premature.

Exit codes: 0 whenever the backend answered, whether or not a system is loaded. Exit 10 when no daemon is running on the local backend. There is no distinct exit code for "daemon up, nothing loaded"; read system_loaded in the output.

The blocker list is a cloud-backend surface. The local daemon's runtime status reports only whether the runtime is built, so orca status on the local backend prints the daemon block and nothing else.

orca runtime status is the narrower read: it works against both backends and prints whether the runtime is built plus, on cloud, the last build failure and its recovery hint.

orca unload

Tears down the loaded SystemRuntime. The daemon keeps running, ready for another topology mount.

$ orca unload
topology unloaded; daemon still running

Unload aborts every non-terminal execution. It cancels each execution task, stops the tick loops, and marks the executions aborted. There is no refusal, no prompt and no --force gate on this verb, so check orca execution list before running it.

To drain gracefully instead: execution close each accepting execution, wait for the threads to reach a terminal state, then unload.

Unloading with nothing mounted exits 30.

orca shutdown

Full stop. Unloads the system if one is loaded, then exits the daemon.

$ orca shutdown
daemon stopped (pid=43821)

With no daemon running it prints no daemon running and exits 0.

If the daemon does not acknowledge POST /shutdown within 5 seconds, the CLI warns, sends SIGTERM to the recorded PID, waits, and removes the PID file if the daemon did not clean up after itself.

To leave the daemon up but drop the system, use unload instead.

See also