On this page

Target

What is a registry target, and why is it not the same thing as a hostname? A target is one routable box the fleet has written down; a hostname is one of the several names that box may answer to.

What it is

A target is one entry in the targets[] array of the canonical registry — "one routable box", in the words of stado-rs/src/targets/target.rs. The registry is the single source of truth for every box the queue can route to: workstations, GCP zonal dispatchers, vast.ai pools. A target carries, among other fields:

Field Meaning
name The fleet's word for the box. Lowercase [a-z0-9._-], validated by the registry-v2 contract.
kind local, gcp, or vast.
hostnames[] Every name the machine itself answers to.
ssh The channel destination ([user@]host[:port]), stored verbatim.
role, host_heuristic Stable placement class and the declarative selector that resolves to exactly one local target.
services[] The units Stado must keep running there — see service.
managed_versions The version each stado-managed binary is required to be at; optional, and a target that omits it is reported undeclared, not agreeing.

Unknown per-target keys round-trip through the target's extra map, so a writer built from an older checkout cannot delete a field a newer one added (targets.rs, ComputeTarget).

Who declares it

An operator, through stado registry host add HOST --ssh DEST --release-platform PLATFORM or by editing the document and running stado registry push. Declaration reads nothing from the machine — it is an assertion, and stado registry doctor is what later diffs the assertion against reality (cli).

The same operator changes what add declared with stado registry host edit HOST [--ssh DEST] [--kind KIND] [--release-platform PLATFORM] [--json], and retires a machine with stado registry host remove HOST [--json]. Both write under the generation they read, so a registry that moved in between is refused with exit 75. A field add does not write is changed with stado registry set --path targets.<host>.<field> --value VALUE.

Refusals, word for word:

  • name at least one of --ssh, --kind or --release-platform to change (exit 2): edit was given nothing to change.
  • --ssh must not be empty (exit 2).
  • registry target "<host>" not found: no target answers to that name; stado registry pull --path targets lists the names that do.
  • <host> is still named at <paths> in <registry>; move or remove those entries first (stado registry set --path <path> --value <other host>), then remove <host>: remove found a service, database or other entry still pointing at the host, and lists every such path.

edit that changes nothing writes nothing and says so: <host>: already declares those values in <registry>; nothing written.

Who observes it

Everything that routes or repairs. The scheduler admits jobs only against targets whose declared capabilities match (architecture). stado host inventory <target> reconciles the declaration against the live host. Beacon readers resolve a target to its host_health/<slug>.json object. The coordinator's rogue-daemon kill switch exits when a successfully read registry omits this machine's entry (targets.rs).

Where it lives in the store

registry.json, in the backend STADO_CONFIG selects — one document for the whole fleet (architecture, canonical object layout).

A target is not a hostname

The fleet knows the box by name; the machine knows itself by whatever hostname returns, and the two are routinely different spellings of one machine. The beacon writer (stado host beacon collect, which the host process runs on its health period) publishes under the machine's own short hostname, lowercased — so the target and its beacon file are spelled differently on a machine named twice, and every reader must try the name and every hostname the registry declares for it.

The matching rule is beacon_slugs in stado-rs/src/monitor/host_health/load.rs: for each identity — the declared hostnames[], the target name, the identity the caller asked for, and the hostname inside the ssh destination — take both the first dot-label and the full normalized form (trimmed, lowercased, trailing dot stripped), skip empty or /-containing candidates, and deduplicate preserving order. The beacon script applies the same idea from the other side: it matches the local hostname against the target name and declared hostnames "with the local suffix dropped", so some-mac.local and some-mac are one identity.

The practical rule: when a machine's self-reported hostname differs from its target name, put every spelling in hostnames[]. A spelling the registry does not declare is a beacon nobody can find.

Commands that act on it

stado registry host add HOST --ssh DEST --release-platform PLATFORM
stado registry host show HOST [--path FIELD]
stado registry host edit HOST [--ssh DEST] [--kind KIND] [--release-platform PLATFORM] [--json]
stado registry host remove HOST [--json]
stado registry self [--local] [--name-only | --json]
stado registry pull
stado registry doctor
stado host inventory <target>
stado host health <target>

Full flags in the cli reference.

Which target is this machine

stado registry self reads the canonical registry, from the registry authority when the store is another host's object API. stado registry self --local answers from this machine's own record instead and never asks another host: the store itself when it is a local directory, otherwise the last-known-good copy ~/.stado/cache/registry-last-good.json that this host's resolver rewrites on every refresh. A local stado product install decides whether a receipt's host is this machine with stado registry self --local --json, so an installation here finishes while the host that keeps the registry does not answer.

--json prints {"name", "kind", "hostname", "source"}; a machine the record does not carry is answered with "name": null. Without --json that machine is refused as host <hostname> is not in <record>. A machine that keeps no record is refused:

this machine keeps no usable local registry record: <home>/.stado/cache/registry-last-good.json and its .meta.json sidecar are not both there and readable; this host's resolver writes them on every refresh, and `stado registry self` without --local writes them once the registry authority answers

tests/install/local_identity.rs runs the real stado in an isolated home against a real OpenSSH server standing for the authority, which answers one read and is then stopped with SIGSTOP, so it accepts connections and never answers; it checks that no --local read announced a connection to it.

Observing GUI automation

stado workload run gui-automation --target <target> with a status plan reads the selected Mac's installed driver, login session, managed runtime and serving CuaDriver socket. It calls check_permissions with prompt: false; this status command does not request macOS consent or open System Settings.

accessibility-record describes the stored TCC entries. accessibility describes what the serving driver actually reports: granted, denied, or unobserved. An unreadable reply or missing socket also produces accessibility-error with the failed operation and its cause. A stored grant does not prove the running driver can use it.

gui-ready: yes requires the declared login session, the running managed driver, its socket, and an observed Accessibility grant. A driver reporting denied therefore produces gui-ready: no, even when the stored entries say granted. Do not treat that state as permission to run GUI actions or bypass macOS consent.

Not to be confused with

  • A hostname. One target may carry several; matching uses the stem rule above, never string equality on the raw name.
  • An SSH destination. ssh is one field of the target, stored verbatim; the target name is what every command takes.
  • A service. A target is a box; a service is a unit declared on a box.
  • A beacon. The target is the declaration; the beacon is what the box itself reports.

Source: this website