Results and exit codes¶
Every host verb — and, through the CLI, every command built on one — speaks
one vocabulary for “what happened”: the otto.result family. There is
no separate exit-code logic anywhere in the CLI to drift out of sync; codes
are derived from results.
The Result family¶

Result— status + optional payload (value) + human diagnostic (msg). Truthiness followsis_ok(Success or Skipped), never the payload —if result:always asks “did it work?”.CommandResult— one shell command: adds thecommandstring and the shellretcode(-1means the command never ran).Results— the aggregaterun()returns: aResultthat is also aSequence[CommandResult]. Its status is the first non-ok entry’s status;onlyasserts exactly one command ran and returns it;first_failurefinds the culprit in a batch. Transfer verbs aggregate per-file results the same way.
The shared vocabulary is Status: Success, Failed,
Error, Unstable, Skipped.
Exit codes¶
Result.exit_code is 0 when ok, else the status value.
CommandResult.exit_code follows the ssh convention users already know:
Situation |
Exit code |
|---|---|
Command succeeded |
|
Command ran and failed |
the shell’s own |
Command never ran (connection/timeout) |
|
Failed without a retcode |
the |
A @cli_exposed host verb returning any Result gets these semantics on the
CLI for free; returning a plain value exits 0. See
The host subsystem for how verbs become CLI commands.