On this page

Host connections

Every Stado host operation reaches its target over one of the routes that host's registry declaration names. The declaration is ordered, the product tries the routes in that order, and the receipt says which one carried the command. No connection provider is built into the product: tailscale, lan, nebula and primary are names an operator declares, and a host that loses one of them keeps working over the next.

Declaration

The routes live on the registry target in canonical registry.json:

  • targets[].ssh is the preferred destination and is always the path named primary.
  • The target's alternate-route array holds the rest, read top to bottom. Each entry carries name (a lowercase identifier other than primary) and destination ([user@]host[:port]). At most sixteen are accepted, and a duplicate name or destination is refused by registry validation.
  • stado registry host path list <host> --json is the read contract: one connections array with name, destination, order and preferred.

A host that declares one destination behaves exactly as before: one route, tried once. A host that declares two — say primary on its Tailscale address and lan on build-mac.lan.example — keeps working when the Tailscale path goes down.

The networks the product can describe are themselves declared, in stado-rs/data/fleet/connections.json, compiled into the binary and read through targets::declared_connection_providers. That document is the one place the names live: the listing publishes it, Stado Desktop shows what the listing publishes, and the connection tests draw from it instead of writing a network name of their own. It is not a closed set — a fleet-specific name is accepted as a route like any other — so what the declaration buys is that every surface offering a choice offers the same one.

Choosing and changing the provider

stado registry host path list <host> [--json]
stado registry host path set <host> <path> --ssh <[user@]host[:port]> [--priority <n>] [--json]
stado registry host path remove <host> <path> [--json]

list prints the preferred path and the ordered alternates with their positions, marks each one declared or fleet-specific against the declared vocabulary, and ends with the networks this product describes. Under --json that vocabulary is known_providers, an array of name and summary beside the connections array. set adds or replaces one path: --priority places an alternate (counting from 1); omitting it keeps an existing position or appends. Passing --priority for primary is refused with the primary path is always preferred and does not take --priority, and removing it is refused with the primary path cannot be removed; replace it with registry host path set. Every write goes through the canonical registry's compare-and-swap and validates the whole document first, so a refused declaration changes nothing.

Moving a host from one network onto another follows the identity rule: two routes may not name one host, so a destination is held by exactly one path at a time. Declare the new network beside the one in use, prove the host answers on it, then release that name and hand the identity to the preferred entry, and finally declare the address the host came off under its own network name so it stays as an alternate:

stado registry host path set <host> wireguard --ssh operator@host-wg --priority 1
stado host link <host>
stado registry host path remove <host> wireguard
stado registry host path set <host> primary --ssh operator@host-wg
stado registry host path set <host> tailscale --ssh operator@host-ts --priority 1

Asking for a second route at the address the preferred entry already holds is refused with host identity '<host>' is already declared by registry.targets[N].ssh, and the document is left byte-identical.

How a connection is chosen

stado-rs/src/deploy/host_channel/ owns the selection. A target that is this machine is answered locally without any ssh at all. A target with one declared route uses it. A target with several probes them in declared order and takes the first that answers, so a dead preferred route costs one probe rather than the operation. A target with no declared route is refused with target "<name>" has no registry-managed SSH connection path.

The route that carried the work is reported, not inferred: host command receipts carry used_connection with the path's own name, or local for the machine itself. A receipt that published only the declared routes could not distinguish a healthy preferred path from a dead one whose alternate rescued the read.

Accounts made through the channel

stado host user create <username> (--target <host>… | --all) creates one local account on each selected kind=local registry host that has an SSH destination, asking for the initial password twice on the terminal and carrying it on the channel's stdin, never in an argv. --full-name sets the display name and --shell the login shell; either one omitted is left to the host's account tool (sysadminctl on macOS, useradd on Linux). --admin adds the account to the administrators, --require-password-change makes the first login change the password, and --dry-run lists the hosts without connecting. stado host user delete <username> --target <host> --confirm <username> [--keep-home] removes one.

Each host is reported as created, exists, plan or failed, and with --json as one document listing every host's status, os, ssh_target and detail; any failed host makes the run exit non-zero. A failure's detail is the account tool's own words, whole: its stderr, else its stdout, else the exit status. A display name or shell is refused only when it carries NUL or a newline, which the remote command line cannot carry; how long either may be is the account tool's limit, refused in its own words.

Where it is visible

  • stado registry host path list <host> --json — the declaration, and known_providers for the networks the product describes.
  • stado host link <host> — the probe of every declared route, and the silences recorded against them.
  • stado host exec and the other host commands — used_connection in the receipt.
  • Stado Desktop, Hosts inspector: the routes sheet lists the preferred route and its alternates with their probe results, and its editor writes exactly the registry host path set and remove calls above, showing the command line before it runs.

Source: this website