On this page

Channels, local services and routes of your own

Reading a host's channels without the control plane, a service the host runs beside its service directory placement, and a route of your own while the resolver holds no listener.

Inspect channels without contacting the control plane

stado resolver channels [--bind HOST:PORT] [--consumer NAME] [--json] reads only this API host's published waiting-channel file. It uses the same publication path as the resolver, including STADO_RESOLVER_STATE_FILE. It does not read the registry, probe a listener, contact the authority or change a route. Both filters must match when supplied together.

JSON retains source, the selected filters, channels and health_observed: false. Each channel carries its service, consumer, adapter bind, upstream host/endpoint, phase and start time. No matching wait means only that this snapshot has none; completed or refused connections disappear from it, and it does not prove the resolver or provider healthy.

Missing HOME/path authority, a missing or unreadable file and malformed JSON are distinct command refusals with the actual operation, path and OS/parser cause. JSON failures include the parser's category: Eof for a truncated document, Syntax for invalid JSON syntax, or Data for a document that does not match the waiting-channel schema. The original parser message retains its location and specific cause. No missing publication is replaced with a successful empty list. Use this read when reporting a failed client connection would otherwise wait on the full resolver status registry and authority probes:

stado service directory connect "$SERVICE" --consumer "$CONSUMER" --no-verify --json
stado resolver channels --bind "$ADAPTER_BIND" --consumer "$CONSUMER" --json

ADAPTER_BIND is the host:port from the directory's returned URL, not a guessed service port. The first command is discovery; only the second is local-only. Stado Desktop exposes the second under Hosts → Routes → Available operations… → Read local resolver channel publication. It runs on the selected Stado API host and retains the same output and refusal.

node tests/resolver/channels.mjs uses the real CLI and an already-published live wait. Supply STADO_BIN, STADO_TEST_SOURCE_REVISION, STADO_TEST_CHANNEL_BIND and STADO_TEST_CHANNEL_CONSUMER. It checks both selectors against that publication, then exercises genuinely missing and directory-valued paths, truncated JSON, invalid JSON syntax and a wrong document shape in its own ignored build area. It checks the observed filesystem error or parser category separately for each refusal and never replaces the live resolver's publication. .build/resolver-channels retains commands, exits, source/binary/test digests, live observations and the actual refusal causes.

A service this host runs beside its placement

Every service is placed on one active host, and every other host reaches it through its own resolver adapter. When that host is out of reach, every caller here loses the service even if this host can run it itself, and the fleet registry cannot be changed from here, since its authority is the host out of reach. A host states instead, in a file of its own, which services it runs for its own callers, each at the loopback URL with port it answers on here:

stado service directory beside brama --url "$BRAMA_LOOPBACK_URL"   # declare
stado service directory beside --json                               # list
stado service directory beside brama --withdraw                     # take back

The statement is kept in ~/.stado/beside.json as {<service>: {url, declared_at}}. stado service directory connect <service> on this host then answers that address, as {"placement": "beside", "placed_on": "<this host>", …} with --json, or <url> (<service> runs beside its placement on <this host>, …) without; a refusal says <service> runs beside its placement on <host> and did not answer at <url>: <cause>. Without a declaration the answer is "placement": "placed" exactly as before. Another host's view (--target) and the fleet registry are unchanged: the statement is this host's own, and nothing answers it silently in place of the placement.

Declaring only names an instance; it does not start one. The instance runs under its product's own installation on this host, with what that product needs reachable from here — a Brama run beside its placement reads its credentials from a Skarbiec this host can reach, and one whose Skarbiec is only reachable through the stopped route is still refused there, by its own sentence.

Refused, each naming its cause: a URL that is not loopback with a port (--url "<url>" must name a loopback address with its port), --url together with --withdraw, a service named with neither, --url or --withdraw without a service, withdrawing a service this host does not declare (this host declares no <service> beside its placement), and a beside.json that cannot be read or parsed, named by its path. Stado Desktop runs the same list, declare and withdraw operations from its routes. The real journey is tests/service_directory/beside.rs (service-directory-beside). The journey also removes the admitted caller's adapter, checks the structured doctor refusal, restores the declaration and checks the recovered route. Each invocation retains a unique JSON receipt under .build/service-directory-beside/, including the embedded source revision, binary digest, arguments, exit status, stdout and stderr; later invocations do not overwrite earlier evidence. The release manifest runs this journey as a required test on both declared platforms. Registration is not a passing result; qualification requires the real command receipts from the candidate revision.

A route of your own while this host's resolver holds no listener

The host resolver is the route to every service placed elsewhere; when it holds no listener — it stopped, or this host declares no adapter for the pair — a caller that must reach such a service has its own route in the product:

stado resolver relay "$SERVICE" --consumer "$CONSUMER" --bind "$LOOPBACK_ADDRESS:$(stado host local port)" --json

The directory is read the way every registry read is (from the authority over SSH), the service is resolved for the consumer exactly as the resolver resolves it, the loopback address you name ($LOOPBACK_ADDRESS) is bound, and the first line printed is the announcement: {"service", "placed_on", "generation", "url", "relayed"} with --json, or <url> (<service> on <host>, relayed over this process's SSH channel until it ends) without. Every connection accepted at that URL is carried over the process's own SSH session to the service's endpoint on its host, the same channel the resolver would open. The relay lives for as long as you hold its standard input: close it, or end the process, and the listener is gone; a relay nobody owns does not outlive its owner. A service placed on this host is answered with its own loopback URL and "relayed": false, and the process ends, so a caller that always asks here gets one answer shape on every host.

Refusals name their cause before any address is printed: the service or consumer the directory does not record (service_resolution's own sentence), a placement whose registry record carries no SSH connection path, a host the fleet channel could not reach (<service> is placed on <host>, which the fleet channel could not reach: …, exit as infrastructure down), an address that is not loopback, or one this host could not bind. A connection the host refuses after the relay is up is answered on that connection with stado resolver relay: not relayed to <host>:<port>: <cause> and said on stderr.

This is the route a review gate or a judge on a workstation takes to Brama when the workstation's resolver is down and Brama answers on its host; it is not a second resolver, and it does not replace the adapters the host declares.

Source: this website