Appearance
Relays
A paired client can reach more than one gateway, through more than one relay — the CLI models this as an n×n matrix: a set of gateways, a set of relays, and the edges between them (which relay can reach which gateway). Bootstrap seeds one gateway and its system relay; you grow the matrix from there — pairing more relays with relays pair, pairing more gateways by running bootstrap again, or letting a gateway hand you its whole relay set with gateways resync. Whichever edge carries your traffic, the end-to-end encryption is unaffected: a relay only ever sees sealed bytes.
The CLI itself never picks between edges for you beyond simple defaults — connect/ssh always resolve to exactly one (gateway, relay) pair (see Connect & SSH). routes --json exists so an extension app can apply its own priority/condition logic and drive connect explicitly.
The relay axis
sh
burrowee relays listReads config.json directly (no daemon needed) and prints a fixed-width table:
ID NAME KIND ORIGIN FINGERPRINT LAN
* edge.example.com seoul system wss://edge.example.com sha256:1a2b3c4d5e6f7a8b YThe * marks your default relay; FINGERPRINT is the relay's LAN TLS certificate fingerprint truncated to 16 characters (— when the relay publishes none); LAN is Y when the relay has published LAN origins, - otherwise. Relay ids are their origin (scheme://host:port), stable across re-pairing.
The NAME column shows the relay's display name. A relay learns its console-assigned name from the pairing blob, and gateways resync refreshes it as the operator renames it on their end. You can also pin a local name that only this client sees — it wins over the console name and is never synced back:
sh
burrowee relays rename <id|host|name> <new-name> # set a local name
burrowee relays rename <id|host|name> # clear it (fall back to the console name)A locally-named relay is marked with a trailing * in the table, with a footnote explaining it. gateways rename does the same for the gateway axis.
sh
burrowee relays use <id|host> # set the default relay
burrowee relays rm <id|host> # remove a relay and its edgesuse persists default_relay in config.json, then tells the running daemon to switch live; if the daemon is down, the preference is still saved and picked up on next start. rm deletes the relay and every edge that referenced it — a gateway that only had that one relay loses its default.
sh
burrowee relays gateway [<relay>] # list a relay's gateways (omit → default relay)
burrowee relays gateway [<relay>] default <gw> # set a relay's default gatewayrelays gateway is the reverse lookup: which gateways this relay reaches, with * on the relay's default gateway. Setting a default lets you dial with just --relay and no --gw when the relay is edged to more than one gateway.
sh
burrowee relays pair <blob> <pin>Adds a console-minted relay to your matrix — see Bootstrap → Adding more relays later.
The gateway axis
sh
burrowee gateways listPrints ID, NAME, relay count, and default relay, with * on your default gateway.
sh
burrowee gateways use <id> # set the default gateway
burrowee gateways rm <id> # remove a gateway and its edgessh
burrowee gateways relays [<gw>] # list a gateway's relays (omit → default gateway)
burrowee gateways relays [<gw>] default <relay> # set a gateway's default relaygateways relays is the forward lookup: which relays this gateway is reachable through, * on the gateway's default relay. The relay argument to default accepts an id, host, or wss:// origin, and must already be an edge of that gateway.
sh
burrowee gateways bridges [<gw>]Lists the gateway's bridges — chained-edge routes that reach the gateway through an intermediate edge rather than a directly-paired relay — as entry origin, end, and the entry's CLI path. Pass the entry origin as --relay (with an explicit --gw) on connect/ssh to dial through one.
sh
burrowee gateways resync [<gw-id-or-name>]Full-mirrors a gateway's current relay and bridge set from the live gateway into your matrix — relays the gateway has added since you last synced get added, ones it dropped get pruned. Omit the argument to resync every configured gateway; a failure on one gateway doesn't stop the others. Useful after an operator adds or removes an edge relay on their end, without needing a fresh pairing blob.
The matrix export — routes
sh
burrowee routes [--json] [--config <path>]Prints the whole gateway×relay matrix. The default (human) form is a compact adjacency listing — each gateway, then its relays indented underneath, with */→ marking the defaults:
* gateway 1a2b3c4d5e6f7a8b
→ edge.example.com
relay2.example.net--json emits the same matrix as a stable, machine-readable contract — this is the export an extension app reads to apply its own routing policy and then call connect --gw <id> --relay <id> explicitly. There's no priority/failover ordering command in the CLI itself; that logic lives in whatever's reading routes --json.
Diagnostics
sh
burrowee relays probe [--json]Asks the running daemon to actively probe every configured relay — a cold and a warm pass per pair, with per-pass dial/query/total latency, the carrier's connection state, target and session counts. Output is grouped by gateway, then by relay, with each relay header carrying the relay's own reported version (and the gateway header carrying the gateway's). Within each gateway the relays are ranked fastest-first by warm-pass query latency, so the quickest edge sits on top; a relay whose warm pass failed sinks to the bottom of its group. Needs a running daemon.
sh
burrowee relays ping [<relay>|all] [<gw>] [--transport <mode>]An end-to-end application-layer ping — unlike probe, this doesn't need the daemon; it dials the relay itself. Name a single relay (optionally disambiguated with <gw> when it's edged to more than one gateway) for a continuous, ICMP-ping-style stream of RTT samples until you Ctrl-C, followed by a min/avg/max/jitter/loss summary. Pass all (or omit the relay entirely) to sample every configured edge instead — 30 pings each, run concurrently — and print one summary table grouped by gateway. --transport auto|ws|quic (default auto) forces the same transport constraint connect/ssh would use, so you can check whether a ws-only network path pings differently than QUIC.
All relays/gateways subcommands accept --socket <path> and --config <path> if you've moved the daemon socket or the config file.
LAN origins and the pinned certificate
An edge relay running on your own network can publish LAN origins — direct local addresses like wss://192.168.1.20:9443 — alongside its internet-facing URL. When a relay entry carries LAN origins, the CLI dials LAN-first: each origin gets a short (~2 s) attempt before falling back to the stored URL. At home that means your traffic never leaves the network; elsewhere the LAN attempts fail fast and the normal path takes over.
A LAN address can't be verified by a public certificate authority — there's no hostname to vouch for. So each LAN-capable relay entry also carries the relay's certificate fingerprint (a SHA-256 hash of its LAN TLS certificate, stored as lan_cert_fp in config.json, and shown truncated in relays list). When dialing a LAN origin, the CLI accepts the connection only if the certificate it is shown hashes to exactly that fingerprint — in plain words: the config remembers which certificate this relay is supposed to present, and refuses imposters. No fingerprint, no LAN dial; those entries just use the regular URL.
LAN-only relays
Some edge relays are LAN-only ("lan_only": true in the relay entry): they have no internet-facing listener at all, and their stored ws URL serves purely as a stable identity — it is never dialed. The CLI reaches a LAN-only relay exclusively through its LAN origins, which means it simply isn't usable when you're away from that network. That's the point: a LAN-only relay keeps your traffic strictly local.
LAN origins, fingerprints, and the lan_only flag all arrive in pairing and relay-add blobs, or via gateways resync; the CLI doesn't receive live pushes otherwise. If a relay's published endpoints change, run burrowee relays pair with a freshly minted blob (it updates the existing entry in place), burrowee gateways resync, or re-bootstrap.