otto run — instructions

An instruction is a procedure: one async function with full lab access — deploy, flash, collect — registered with @instruction() and dispatched as an otto run subcommand. Where suites produce verdicts across many test methods, an instruction has one body and one outcome.

What registration synthesizes

The decorator stores an entry in the INSTRUCTIONS registry (Registries and the pluggable CLI) and builds a Typer sub-app around the function, transforming its signature on the way:

  • Options expansion. If the function declares a parameter annotated with an options dataclass, the decorator expands the dataclass’s fields — including inherited ones, which is how repo-wide RepoOptions bases work (Options classes) — into individual CLI flags, and reconstructs the populated instance at call time. Suites use the same machinery for their Options class, so one options hierarchy serves both.

  • Context injection. A parameter annotated OttoContext is stripped from the CLI signature and injected from the active context at call time — the DI-friendly way for an instruction to reach hosts without global lookups (The command lifecycle).

What is unique about run

The full preamble applies (lab, output dir, reservation gate), and then the body is just the user’s coroutine on the invocation’s event loop. The instruction’s returned Result (if any) becomes the process exit code (Results and exit codes); artifacts belong in get_context().output_dir (otto run).

Because instructions live in the INSTRUCTIONS registry, tab completion of their names comes for free — these candidates are the demo repo’s registered instructions, resolved by the real completion machinery:

otto run <TAB><TAB> smoke $ otto run

otto run --help

otto run --help Usage: otto run [OPTIONS] COMMAND [ARGS]... Handle the eager ``--list-instructions`` flag; real work runs in the leaf preamble. Output-dir creation and the reservation gate moved to the shared leaf-invoke :func:`~otto.cli.invoke.command_preamble`, so a subcommand ``--help`` (which exits before invoke) can never create a spurious dir. ╭─ Options ────────────────────────────────────────────────────────────────────╮ │ --list-instructions List available instructions and exit. │ │ --help -h Show this message and exit. │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Commands ───────────────────────────────────────────────────────────────────╮ │ smoke Log a greeting — replace with your first real instruction. │ ╰──────────────────────────────────────────────────────────────────────────────╯