Extension points

Downstream repos extend otto from init modules — ordinary Python modules named in the init list of .otto/settings.toml, imported during bootstrap phase 2 (The command lifecycle). Registration is import-time and side-effect based: an init module calls register_* functions (or applies decorators), and from then on the new component behaves exactly like a built-in — same registries, same CLI listing and completion, same error messages (Registries and the pluggable CLI).

The seams

You want to add

Register with

Guide

an otto run subcommand

@instruction()

otto run

an otto test suite

Test-prefixed OttoSuite subclass (auto-registers)

otto test

a top-level otto command

otto.register_cli_command / @otto.cli_command

Extending the otto CLI

a CLI verb on a host class

@cli_exposed on the method

Host capabilities

a host class (new os_type base)

register_host_class

OS Profiles & Custom Host Classes

an OS profile (defaults bundle)

register_os_profile or [[os_profiles]] in settings

OS Profiles & Custom Host Classes

a connection (term) backend

register_term_backend

Extending otto with custom connection and transfer backends

a file-transfer backend

register_transfer_backend

Extending otto with custom connection and transfer backends

a shell dialect

register_command_frame

Extending otto for new embedded targets

an embedded binary loader

register_binary_loader

Extending otto for new embedded targets

an embedded filesystem type

register_filesystem

Extending otto for new embedded targets

a power controller

register_power_controller

Extending otto with custom connection and transfer backends

products on hosts

register_product_provider

Host capabilities

a host source (lab repository)

otto.storage.register_lab_repository()

Host Database

a reservation backend

register_reservation_backend

Lab Reservations

per-host monitor parsers

register_host_parsers

otto monitor

SNMP metric descriptors

register_snmp_metric

otto monitor

Options classes deserve a mention even though they aren’t a registry: a repo-wide @options class shared by instructions and suites is the standard way to give a whole project consistent CLI flags (Options classes).

What keeps third-party code honest

  • Symmetry. Built-ins use the same register_* calls, so the public seams are exercised by otto itself on every run.

  • Conformance helpers. For contract-shaped seams, otto.testing ships assert_*_conforms functions (e.g. assert_reservation_backend_conforms()) — one pytest test per backend catches every contract violation in one report. otto.examples holds small, copyable reference implementations that otto’s own suite keeps green.

  • Containment. A broken init module becomes one framed warning, not a broken CLI (The command lifecycle); a name collision is a loud error attributed to both registering modules (Registries and the pluggable CLI).

  • Schema visibility. Data-side extensions (profiles, preferences, custom settings tables) surface in otto schema export, so editors validate them (Data at the boundary).