CLI reference

Outputs verified against the daemon sourceView as Markdown

One binary carries everything: atlasd is the daemon, the control CLI, the web server and the tooling. (Packaging installs a nexus-atlasd compatibility symlink beside it for older unit files.) Commands default to config /etc/atlas/config.toml and interface nexus0 where those apply.

Daily drivers

atlasd keygen

Generate a Curve25519 keypair, base64-encoded — the node identity. The private key goes into this node's [interface], the public key into every peer's [[peer]] block for it.

Example — the key lines are TOML-ready, paste them straight into configs
$ atlasd keygen

✓ Keypair generated (Curve25519)

  Private Key (keep secret)
  private_key = "4AiNx2P9vKq8mW3jR7hT5cL0dF6gY1bZ4nS8uE2oKEY="

  Public Key (share with peers)
  public_key  = "9XpQm4Wv7Jk2Rt8Ny5Bc1Hf3Zd6Ls0Ga9Ue7Iw2bQc="

  » Add these to your /etc/atlas/config.toml
  » Share only the public key with remote peers
atlasd run -c <config>

The daemon itself. Under systemd, startup completes only when the TUN exists and every link is serviced (Type=notify) — "started" means the data path is up, not that the process exec'd.

Example — the log milestones that mean the tunnel is up
$ sudo atlasd run -c /etc/atlas/config.toml

  Nexus Atlas  v3.0.0+7c341a4
  wire 5 · relay 2 · seal 2 · pairing 3 · adapter 1 · report 2 · api 1

…  handshake init from peer 1 processed, sending response
…  handshake complete with peer 1
…  all peer handshakes established
Under systemd, prefer the unit — start blocks until the data path is live
$ sudo systemctl start nexus-atlasd   # returns when TUN + links are serviced
atlasd status

Freshness-checked digest of every daemon instance on the host: interface, address, strategy, links alive, peers established, and a bearers block with one line per member whose advert lists its bearer kinds — what it rides on, a dead kind marked (down), and the kind at the far end of this node's direct path. The thirty-second answer to "is it running and is it healthy".

Example
$ atlasd status

  Nexus Atlas  v3.0.0+7c341a4

  nexus0  10.0.100.1/24  lowest_delivery_time  2/2 links alive  1 peer established
    bearers
      node-a (this node): Ethernet + Wi-Fi
      node-b: Ethernet + Cellular (down) · direct over Ethernet
atlasd stats -i nexus0 -f pretty|json|json-pretty

One-shot snapshot dump. The JSON forms are stable integration surfaces — the same document served at /api/stats.

Example — one link, machine-readable
$ atlasd stats -i nexus0 -f json | jq '.links[0]'
{
  "id": 0,
  "name": "wired",
  "bind_device": "eth0",
  "alive": true,
  "rtt_ms": 0.42,
  "jitter_ms": 0.05,
  "loss_pct": 0.0,
  "capacity_mbps": 100.0,
  "quality_score": 0.98,
  "tx_bytes": 104857,
  "rx_bytes": 99231
}
atlasd monitor -i nexus0 -r 500

Live terminal dashboard, refresh in milliseconds. Keys: q quit, g sparklines, p pause. The fastest way to watch a failover happen.

atlasd web -i nexus0 -l 0.0.0.0:9800

The REST API and browser dashboard. Static UI assets are served from disk (/opt/atlas/web); without them the port is API-only.

Example — serve, then read the same snapshot the CLI sees
$ atlasd web -i nexus0 -l 0.0.0.0:9800 &

$ curl -s localhost:9800/api/stats | jq .strategy
"lowest_delivery_time"

$ curl -fsS localhost:9800/api/health >/dev/null && echo healthy
healthy
atlasd journal [-c category] [-s severity] [--since 30m] [--code link.down] [--follow] [--json]

Read the persistent event journal; --follow tails it live, --json makes it a pipeline source. Default limit 50 entries, newest first.

Example — human view, then the same entry as a pipeline source
$ atlasd journal -c link -s warn --since 24h
2026-08-13 14:32:01  WARN   link.down                 link wired on nexus0 went down  reason=probe_timeout missed_probes=5
2026-08-13 14:31:42  WARN   link.quota_warn           link lte0 at 80% of monthly budget  used_pct=80

$ atlasd journal --json -n 1
{"v":1,"seq":891,"ts":1786297001,"category":"link","severity":"warn","code":"link.down","msg":"link wired on nexus0 went down","fields":{"reason":"probe_timeout","missed_probes":5}}

Configuration tooling

atlasd config check [-c path] [--json]

The daemon's exact load pipeline without starting the engine. Exit 0 = loadable (warnings allowed), exit 1 = the daemon would refuse to start. --json emits {ok, findings:[{fatal, path, message}]} for CI gates. In a record fleet, a config with an interconnect seam is also checked against the node's own record in the list it holds: every route, map or export outside the record's interconnect section is refused, naming the record and its lists (the running daemon enforces the record either way).

Example — the three verdicts, and the exit code CI cares about
$ atlasd config check -c node-a.toml
✓ node-a.toml is valid

$ atlasd config check -c tuned.toml
✓ tuned.toml is loadable (2 warnings)

$ atlasd config check -c broken.toml
✗ broken.toml has fatal errors — the daemon would refuse to start
$ echo $?
1
atlasd config schema

Print the config JSON Schema (draft-07), generated from the daemon's own structs. Point a #:schema header at it and a TOML-aware editor autocompletes and validates as you type; the configuration reference is generated from the same document.

Example
$ atlasd config schema | head -6
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Nexus Atlas config",
  "type": "object",
  "required": ["interface", "link"],
  "properties": {

$ atlasd config schema > config.schema.json   # then: #:schema ./config.schema.json
atlasd config node-token

Print the time-windowed mesh read token for the X-Atlas-Node-Token header — bare token to stdout, scope and validity to stderr, so it pipes cleanly into scripts. In a record fleet it mints the node-bound form instead (n1.…, signed with this node's signing_key), which reads as far as the record's dashboard flag allows.

Example — annotations go to stderr; only the token reaches stdout
$ atlasd config node-token
  Scope  GET /api/config, GET /api/stats — no writes, no session
  Valid  another 4m 12s (5-minute windows — mint again after that)

9y1uTq83KfWv2mDplRcxJ7hNbA5eZsG0

  » Read a locked-down mesh member over the tunnel:
    $ curl -H "X-Atlas-Node-Token: $(atlasd config node-token)" \
           http://10.0.100.2:9800/api/stats
atlasd config keygen-author [--out path]

Generate the Ed25519 author keypair that signs fleet configuration epochs (written mode 0600).

atlasd config sign-epoch --policy <file> --epoch <n> [--confirm-secs 90] [--target-roles a,b]

Sign a policy TOML into a distributable config epoch offline, with optional role/node targeting (selectors intersect) and the commit-confirm window baked in.

atlasd config wizard

Offline provisioning-bundle authoring shell. Binds loopback only by default — it deliberately has no auth of its own.

Node identity & fleet list

For a record fleet ([auth] provider = "fleet", see Identity and authorisation). The fleet subcommands author the list on the operator host and default to /etc/atlas/fleet-list.toml; every edit refuses to write a list that would not validate. fleet revoke, fleet push and peer evict remove nodes; fleet invite, fleet cert and fleet pending admit them (see admission modes). fleet add-node --sink and fleet set-caps --sink make a record a read-only member — it may subscribe and receive, never send data, relay or author; it gets no classes unless --classes names some, which fleet check then warns about — the record a feed gateway host runs with. fleet set-update-class, fleet rollout, fleet rotate and fleet set-lifeline drive pushes and rotations.

atlasd keygen --identity

A whole node identity: the record UUID, an X25519 transport keypair and an Ed25519 signing keypair, printed as the node's [interface] lines, with the fleet add-node command for the operator on stderr.

Example — the private lines stay on the node; the public halves go into the record
$ atlasd keygen --identity

  node identity generated (keep the private lines secret, file mode 0600)

  # [interface] — this node
  node_id = "af2e580d-5365-4b5f-acfa-9a9da1f69e73"
  private_key = "…"
  signing_key = "…"

  # public halves — for the fleet list
  public_key  = "aC+J3tbTGW+7vBHMWMDbeCnjdsFxCxNS4W5gCmxAHWk="
  signing_public_key = "2b2Z8FwiOSi2wJgh17Zp8cPK5Kg6q0/Am7usCaiSDTY="

  On the operator host:
    atlasd fleet add-node --name <name> --node-id af2e580d-5365-4b5f-acfa-9a9da1f69e73 \
      --transport-key aC+J3tbTGW+7vBHMWMDbeCnjdsFxCxNS4W5gCmxAHWk= \
      --signing-key 2b2Z8FwiOSi2wJgh17Zp8cPK5Kg6q0/Am7usCaiSDTY= \
      --allowed-ip <tunnel-ip>/32
atlasd fleet init --fleet <id> [--file path] [--force]

Start the authoring copy of a new fleet's list. The fleet id scopes each node's high-water mark.

atlasd fleet add-node --name n --node-id uuid --transport-key k --allowed-ip cidr [--signing-key k] [--role r] [--relay] [--classes a,b] [--config-author] [--dashboard none|own|fleet] [--sink]

Add a record, least privilege unless the flags say otherwise. --transport-key, --signing-key, --allowed-ip and --role repeat. --sink makes a read-only member: it may subscribe and receive, never send data, relay or author, and gets no classes unless --classes names some (which fleet check then warns about).

Example — a weather sensor with default flags except the dashboard
$ atlasd fleet add-node --name sensor --node-id de8bae79-560d-43fb-b269-0e12b9c478a8 \
    --transport-key lZJk7MeEDtZbjfDhy7L56+C9tncbO4P+7lUjpnUt7k0= \
    --allowed-ip 10.0.9.3/32 --role sensor --dashboard none
record `sensor` added to /etc/atlas/fleet-list.toml (unsigned — run `atlasd fleet sign`)
atlasd fleet set-caps <name|uuid> [--relay bool] [--classes a,b] [--config-author bool] [--dashboard none|own|fleet] [--sink bool]

Change a record's flags. The edit clears the signature until the next fleet sign; a change that would leave the list invalid writes nothing and exits 1. --sink true clears the classes unless --classes is given; --sink false restores the least set when none are left.

Example
$ atlasd fleet set-caps sensor --classes Telemetry,Position
`sensor`: relay=false classes=[Telemetry,Position] config_author=false dashboard=none (unsigned — run `atlasd fleet sign`)
atlasd fleet set-interconnect <name|uuid> [--may-import a,b] [--may-export c] [--clear] [--file path]

Set what a record may import and export as an Atlas Interconnect seam host, in its [node.ext.interconnect] section. --may-import lists the routes and mapped local addresses the node may announce from another network, --may-export this network's hosts it may expose; each is comma-separated, "" means none, and a list left out keeps its value. --clear removes the section: the node may import and export nothing. Write 0.0.0.0/0 for anything. The edit clears the signature until the next fleet sign; an empty list is warned about, and the first list whose records carry extensions gets a note, because nodes on release 3.0.0 or older cannot verify it and keep the list they hold.

Example — grant, sign, push
$ atlasd fleet set-interconnect op-a --may-import 10.0.9.0/25,10.0.101.130/32 --may-export 10.0.101.0/24
`op-a`: may_import [10.0.9.0/25, 10.0.101.130/32] · may_export [10.0.101.0/24] (unsigned — run `atlasd fleet sign`)
  note: records now carry extensions — a node on release 3.0.0 or older cannot verify this list and keeps the one
  it holds; publish it once the fleet runs a build with record extensions
$ atlasd fleet sign
$ atlasd fleet push
atlasd fleet sign [--file path] [--key /etc/atlas/config-author.key] [--seq n]

Bump the sequence number (or set it) and sign with a config-author key, the same key config keygen-author makes for epochs.

Example — the author's key id, the record count and the list's hash
$ atlasd fleet sign
fleet `field-1` seq 2 signed by 3c24f045 (4 records, ffc955e8)
atlasd fleet show [--file path | -c config] [--json] [--revoked]

Summarise a list file, or with -c the list a node config runs with (its bootstrap copy or a newer cached one). --json prints the GET /api/fleet shape; --revoked lists only the revocations. A record with an interconnect section shows an interconnect line (may_import [10.0.9.0/25] · may_export [10.0.101.0/24]), and extension keys this build does not know are listed as kept and signed as they are.

Example — abbreviated to two records
$ atlasd fleet show --file fleet-list.toml
fleet `field-1` · seq 2 · 4 records · signed ffc955e8

  drone (e191..81b6) af2e580d-5365-4b5f-acfa-9a9da1f69e73
    allowed_ips  10.0.9.2/32
    roles        uav
    capabilities relay=true classes=[Control,Voice,Position,Telemetry,Video,Bulk] config_author=false dashboard=own
    transport    6142ed49 valid
    transport    5123339a valid
    signing      e5c003f3 valid

  sensor (94b6..9806) de8bae79-560d-43fb-b269-0e12b9c478a8
    allowed_ips  10.0.9.3/32
    roles        sensor
    capabilities relay=false classes=[Telemetry,Position,Bulk] config_author=false dashboard=none
    transport    115b28e5 valid
    signing      8a10e10a valid
atlasd fleet verify [--file path]

Verify the signature against the trust anchors in config-authors.toml; exit 1 on failure.

Example
$ atlasd fleet verify
fleet `field-1` seq 1: signature OK (anchor `operator`)
atlasd fleet check [--file path] [--json]

Validate the records and report the signature state. Errors exit 1: duplicate ids, names or keys, empty allowed_ips or classes, unknown class names, more than two keys of a kind valid at once, config_author without a signing key, more than 32 record extensions or a key over 32 characters, an interconnect section that does not parse. Warnings: an empty interconnect may_import or may_export ("this node may not act as a seam host"), overlapping allowed_ips, a record without a signing key, config_author on a record without the operator role, and a sink record that also names classes, config_author, relay or dashboard = "fleet" (each ignored at enforcement).

Example — human and JSON forms
$ atlasd fleet check
fleet `field-1` seq 0: 4 records, 0 error(s), 0 warning(s), signature unsigned

$ atlasd fleet check --json
{"errors":[],"ok":true,"signature":"unsigned","warnings":[]}
atlasd fleet revoke <name|uuid|node id|key>… [--reason text] [--push config] [--push-relays] [--no-rotate] [--file path] [--key path]

Remove records, or single keys given in base64, for good (see Revocation): list them as revoked, rotate the mesh secret to the remaining records, bump the sequence number and sign. --push hands the list to the daemon of that node config, which floods it; --push-relays sends the revoked transport keys to the relay registry with the staff token from $ATLAS_CONTROL_PLANE_TOKEN or --token-file. --no-rotate keeps the mesh secret, which leaves the removed node able to read gossip until the next rotation.

Example — remove one node and push it fleet-wide
$ atlasd fleet revoke drone03 --reason "lost on sortie 12" --push /etc/atlas/config.toml --push-relays
  removed `drone03` (5a1c..9e02) — id and keys revoked
  mesh secret rotated (rot-1791801600-mesh_secret), sealed to 5 remaining record(s)
fleet `field-1` seq 8 signed by 3c24f045 (5 records, 9b0e7d21)
fleet `field-1` seq 8 handed to the atlas0 daemon — it floods it over its sessions
relay registry: 2 revoked key(s) for fleet `field-1` seq 8 (revoked_clients_seq 8)
atlasd fleet push [--file path] [-c config] [--relays] [--control-plane url] [--token-file path]

Hand a signed list to the daemon running -c, which verifies it like a list from a peer, adopts it and floods it; and with --relays, send its revoked transport keys to the relay registry. An unsigned list is refused.

atlasd fleet show --revoked

What the list has revoked, oldest first. A removed node is listed with its id and each key it held.

Example — a key retired after a leak, then a removed node
$ atlasd fleet show --revoked
revoked (4):
  transport 7d0e44a1 of gs  since 1791720000  (key copied to a laptop)
  node   drone03 5a1c..9e02  since 1791801600  (lost on sortie 12)
  transport 2b9f61c0 of drone03  since 1791801600  (lost on sortie 12)
  signing   e07a3d55 of drone03  since 1791801600  (lost on sortie 12)
atlasd fleet invite --name n (--allowed-ip cidr | --pool cidr) [--classes …] [--relay] [--dashboard none|own|fleet] [--role r] [--ttl 15m] [--uses 1] [--region r] [-c config] [--json]

Ask the running daemon to mint an invitation and print its v=2 pairing code on stdout (the summary goes to stderr). Unnamed flags are least privilege; a multi-use invitation with --pool gives each node the next free /32 and numbers the names. --list shows every invitation with its state and the nodes it admitted; --withdraw <id> voids one. Needs a record fleet. See Pairing code.

Example
$ atlasd fleet invite --name drone07 --allowed-ip 10.1.0.17/32 --ttl 15m
invitation 7c41e09a2f5d4b8e9a3c11d07f62b5e4 for `drone07` — 1 use(s), expires in 15m
  classes Telemetry,Position,Bulk · relay no · address 10.1.0.17/32
  the code carries 1 anchor(s), 0 author(s), the address 10.1.0.17/32 and this node's address 10.1.0.1/24 — all under the token's MAC (202 characters)
atlas:pair?v=3&k=<this node's key>&n=drone07&a=<anchors>&i=10.1.0.17/32&h=10.1.0.1/24&t=<token>
atlasd fleet cert (--node name|uuid [--file list] | --name n --node-id uuid --transport-key pub [--signing-key pub] --allowed-ip cidr --fleet id) [--classes …] [--relay] [--dashboard …] [--psk-id id] [--expires 365d] [--key authority.key] --out F.cert

Sign a record as a fleet certificate with the authority key (default /etc/atlas/config-author.key). Any node that trusts that key admits the certificate's holder with its flags and no list entry. Warns when the key is not an anchor on this host. See Fleet certificate.

Example
$ atlasd fleet cert --node drone-c --file /etc/atlas/fleet-list.toml --expires 365d --out drone-c.cert
certificate for `drone-c` (5e0b..c4a1) in fleet `tenant-1` signed by 3c24f045 → drone-c.cert (812 bytes, expires 1823341500)
on the node: [auth] cert_file = "drone-c.cert"
atlasd fleet pending list [--json] | approve <id> (--allowed-ip cidr | --pool cidr) [--name n] [--classes …] [--relay] [--dashboard …] [--role r] | deny <id> [--block 1h] [--reason text] | unblock <id> [-c config]

The approval queue of the running daemon ([auth] pending = true). approve mints the knocking key's record — signed into the next list when this node can sign, else kept here and forwarded to an author — and the node's next retry gets a session; deny blocks the key for --block or [auth] block_secs. list also shows records this node minted on their way to an author (queued `n` (via) — status (author `a`)) and, on an author with [auth] accept_forwarded = false, records other nodes forwarded (forwarded <id> … — awaiting approval), which approve <id> signs exactly as minted and deny <id> refuses. See The approval queue and forwarding.

Example
$ atlasd fleet pending list
5d2e81a0  from 198.51.100.23:51820   "phone-07"         4× first 9s ago last 1s ago
$ atlasd fleet pending approve 5d2e81a0 --allowed-ip 10.1.0.70/32 --classes Position,Telemetry
approved as `phone-07` (9b1f..07c2), 10.1.0.70/32 — in fleet list seq 3
atlasd fleet pull -c config [--file path] [--with-queued]

Copy the verified list a node runs with into the authoring file — after that node signed newer lists itself, from invitations, approvals or a dashboard removal — so the next edit builds on it. --with-queued also adds the records the node minted and still holds — a record an author refused, or one waiting for an author it cannot reach; they are unsigned until you run fleet sign and push. fleet revoke --cert F revokes a certified record that has no list entry.

atlasd fleet select-area --polygon area.geojson [-c config] [--json] [--revoke [--yes] [--reason text] [--no-rotate] [--file path] [--key path]]

Resolve a GeoJSON polygon (Polygon, Feature or FeatureCollection, [lon, lat]) against the last known positions of the daemon running -c, and print the records inside with the age of each fix, the count outside and the records with no position. --revoke then removes exactly the listed records — never the node of -c — from the authoring file as fleet revoke does, signs, and hands the list to that daemon; it asks first unless --yes. The reason defaults to removed by area. See Remove nodes by area.

Example
$ atlasd fleet select-area --polygon sofia.geojson -c /etc/atlas/config.toml
fleet `field-1` seq 7 · 3 inside · 2 outside · 1 without a position
  inside  n3               4c1e..a902  (42.69770, 23.32190)  fix 1 s ago
  inside  n4               91b0..33fe  (42.70120, 23.33810)  fix 1 s ago
  inside  n5               07da..c4e1  (42.68840, 23.31570)  fix 4 min ago (advert aged out)
  no fix  n2               e5a3..1b7c
atlasd fleet set-geofence <name|uuid> (--polygon f.geojson [--grace-secs 600] [--action isolate|zeroize] | --clear) [--file path]

Set or remove a record's [node.geofence] in the authoring file. The list is left unsigned until fleet sign. Outside its fence for --grace-secs, the node isolates itself (reversible) or zeroizes. See Give a node a geofence.

Example
$ atlasd fleet set-geofence n1 --polygon burgas.geojson --grace-secs 300 --action isolate
`n1`: fence of 4 points, isolate after 300 s outside (unsigned — run `atlasd fleet sign`)
atlasd fleet zeroize <name|uuid|node id> [--not-before unix | --delay-secs N] [--no-revoke] [--no-rotate] [--reason text] [--cancel] [--push config] [--file path] [--key path]

Sign a remote zeroize command for one node into the authoring file and sign the list. By default the same list also revokes the node, with a mesh-secret rotation; --no-revoke keeps its record. --not-before or --delay-secs holds the command; --cancel drops the node's pending command; --push hands the list to that node config's daemon, otherwise push it with fleet push. A revoked node can still be named by name or UUID. See Wipe a node remotely.

Example
$ atlasd fleet zeroize n2 --delay-secs 600 --push /etc/atlas/config.toml
  zeroize `n2` (e5a3..1b7c) not before 1791802200 (in 600 s)
  revoked `n2` (e5a3..1b7c) in the same list — id and keys, it can never rejoin
  mesh secret rotated (rot-1791801600-mesh_secret), sealed to 2 remaining record(s)
fleet `field-1` seq 9 signed by 3c24f045 (2 records, 1 command(s), 4f7a2c10)

$ atlasd fleet zeroize n4 --no-revoke
  zeroize `n4` (9b02..77de)
  not revoked (--no-revoke): `n4` stays a record
fleet `field-1` seq 10 signed by 3c24f045 (2 records, 2 command(s), 8c31e0f5)

$ atlasd fleet zeroize n4 --cancel
  dropped 1 command(s) for `n4`
atlasd peer evict <name|uuid|node id|key id|key|peer id> [--reason text] [-c config]

Ask the running daemon to tear one peer's sessions down now. It is a reset: a peer that still has a record reconnects; revocation is what keeps it out. Exits 1 when no peer matches or the daemon does not answer within 5 s.

Example
$ atlasd peer evict relay --reason "stale endpoint"
evicted peer 3 (c41f..07ad)
atlasd identity show [-c path] [--json]

This node's identity as the daemon would resolve it at start: node id and UUID, record name, flags, each key with its validity and whether this node holds it, and the fleet list's sequence number.

Example — a node in the middle of a rotation holds both transport keys
$ atlasd identity show
interface      atlas0
mode           record fleet
node id        e191..81b6 (af2e580d-5365-4b5f-acfa-9a9da1f69e73)
record         drone
capabilities   relay=true classes=[Control,Voice,Position,Telemetry,Video,Bulk] config_author=false dashboard=own
transport      6142ed49 valid · held here
transport      5123339a valid · held here
signing        e5c003f3 valid · held here
fleet list     `field-1` seq 2
atlasd fleet set-update-class <name|uuid|node id> required|best-effort|left-behind [--pinned] [--file path]

Set a record's update class for fleet pushes in the authoring list — unsigned until atlasd fleet sign, then pushed. required gates a release and aborts it when silent or failed; best-effort is tracked, never awaited; left-behind is outside targeting and both gates, and takes the newest epoch after [config_mgmt] left_behind_grace_secs unless --pinned. See Push a release the fleet cannot half-take.

Example
$ atlasd fleet set-update-class relay-van required
`relay-van`: update class required (unsigned — run `atlasd fleet sign`, then push)
$ atlasd fleet set-update-class test-bench left-behind --pinned
`test-bench`: update class left_behind, pinned (unsigned — run `atlasd fleet sign`, then push)
$ atlasd fleet sign
fleet `field-1` seq 12 signed by 3c24f045 (6 records, 5be2a1c0)
atlasd fleet rollout status [-c config] [--json] · release [--force] · abort [--reason text]

The staged rollout this node drives. status prints both gates — the canary gate and the release gate with its required, confirmed, silent and failed counts, the deadline and an abort cause when there is one — and every node's class and state. release signs phase 2 (--force past an unmet canary gate); abort signs the pre-rollout policy forward, to the canary set or, once released, to everyone. The web API's /api/config/rollout/* does the same.

Example — a release watch that ended in an automatic abort
$ atlasd fleet rollout status -c /etc/atlas/config.toml
rollout r-1791900000-9f3a1c2e · phase aborted · canary epoch 13
  canary gate: 1 of 1 canaries applied and confirmed
  aborted by: relay-van (4f02..c8d1) silent (release phase)
  release gate (epoch 14): required node relay-van (4f02..c8d1) did not confirm by the deadline for the released epoch 14 — the rollout aborts
    gs1            9b1e..40aa   required     applied            epoch 14   confirmed
    relay-van      4f02..c8d1   required     unknown            no epoch   SILENT
    drone-a        d1a0..7c21   best_effort  applied            epoch 14   confirmed
    test-bench     e77a..1b06   left_behind* left_behind        epoch N-1  held
    (* pinned: never takes a new epoch)
atlasd fleet rotate plan --kind mesh-secret|node-transport|node-signing[,…] [--subject node] [--next-key b64] [--next-signing-key b64] [--publish-in secs] [--activate-after secs] [-c config] [--push config] · status [-c config] [--json] · activate <id> · retire <id> [-c config] [--force] [--reason text] [--at unix] · cancel <id>

Rotations on the three-step schedule. plan signs a schedule into the list: the mesh secret is minted and sealed to every record, a node key names the subject and its next public key (--next-key for a transport key, --next-signing-key for a signing key); publish is now unless deferred with --publish-in, activate follows after [rotation] default_publish_to_activate_secs unless --activate-after sets it. activate, retire and cancel take --push too, and every step defaults to --file /etc/atlas/fleet-list.toml and the author key. status prints every rotation, each node's reported state, the retire gate and the nodes still on old material. activate brings activation forward to now. retire signs the retire step and is refused until every required node, and a node rotation's subject, reports active in the gossiped view of -c (--force is recorded on the node whose view was overridden). cancel withdraws a rotation that has not activated. See Rotate keys and the mesh secret without stranding anyone.

Example
$ atlasd fleet rotate plan --kind mesh-secret --push /etc/atlas/config.toml
  rot-1791900000-mesh_secret: new mesh secret sealed to 6 of 6 record(s); published 1791900000, activates 1791903600
fleet `field-1` seq 14 signed by 3c24f045 (5be2a1c0)
fleet `field-1` seq 14 handed to the atlas0 daemon — it floods it over its sessions

$ atlasd fleet rotate retire rot-1791900000-mesh_secret -c /etc/atlas/config.toml
error: retire waits for 1: relay-van — wait for them, or pass --force
atlasd fleet set-lifeline <name|uuid|node id> [--off] [--file path]

Flag a record as a lifeline node (a bootstrap peer) in the authoring list, unsigned until atlasd fleet sign: after each retire it keeps accepting the retired key or secret for [rotation] lifeline_secs, so a straggler still finds a node that speaks its material. --off clears the flag.

Dashboard accounts & tokens

atlasd web adduser|passwd|deluser|list-users

Dashboard account management — argon2id at rest, sessions as signed cookies. Create accounts before exposing :9800 beyond localhost.

atlasd web remove-passkey

The break-glass path when a hardware security key is lost — removes a passkey from an account so password sign-in works again.

atlasd web token add ci --scope read|write [--expires 30d]

Mint an API token for automation; the secret is printed exactly once. token list and token revoke manage the set; scopes are documented in the API reference.

Example — the secret appears exactly once, on stdout
$ atlasd web token add ci --scope read --expires 30d
atlas_kQ3nX8vLw2Jm7RfT5cYp0dHb4gZs9uEaIo6WqBNVkPr

$ atlasd web token list
  ci  atlas_kQ3n  read  created_at=1786295400 by=admin expires=1788887400 last_used=never

Complete footage

For classes with retain = true (see complete footage by backfill). Both commands read -c for the interface and the [qos.retain] paths. A clear goes to the running daemon, which executes it itself, or straight to disk when none runs.

atlasd retain status [--json] | clear [--class C] [--dest ip] | export --class C --dest ip [--stream hex] [--out f]

The sender's journal: retained classes, size against max_bytes, whether it is sealed at rest, backfill served, one line per stream. clear empties it at the end of a flight; export writes the sender's copy of a stream in the capture export format, for comparison with the receiver's.

Example — on the vehicle
$ atlasd retain status
retained classes: Video
journal: 226.3 MiB of 2048.0 MiB in 4 segment(s) under /var/lib/atlas/atlas0.retain (sealed at rest)
journaled 187500 · dropped 0 · requests 41 · backfill queued 12972 sent 12972
  Video     → 10.0.0.1        stream 3d4c  187500 packets  seq 0..187499  226.3 MiB
atlasd capture status [--json] | export <peer> <class> [--stream hex] [--out f] | clear [--class C] [--peer ip]

The receiver's archive: completeness per origin, class and stream, with missing and unrecoverable counts. export writes a stream in sequence order with its gaps annotated (.atlcap, the input of tools/atlas-capture); without --stream, every stream of that origin and class. The dashboard's Export button calls POST /api/capture/export with {"peer", "class", "stream"}, up to 256 MiB.

Example — on the ground station, after the backfill
$ atlasd capture status
captures: 226.3 MiB of 2048.0 MiB under /var/lib/atlas/atlas0.capture
requests sent 41 · answers 41 · backfill received 12972 · duplicates 0
  10.0.0.2        Video     stream 3d4c  100.00 %  187500 of 187500  missing 0  unrecoverable 0

$ atlasd capture export 10.0.0.2 Video --out sortie.atlcap
stream 3d4c: 187500 packets, 0 missing, 0 unrecoverable → sortie.atlcap

Diagnostics & support

atlasd --version | -V

One line on stdout, for scripts and bug reports: the release, + the git short hash of the build it was made from, then every contract number this binary speaks (Versioning says what each one covers). A build made outside a git checkout reads +unknown; packaging may set the hash through ATLAS_BUILD. atlasd --help and the atlasd run banner show the same release as v3.0.0+7c341a4 with the contract row under it, and atlasd status shows the release. The wire number is the one that decides whether two nodes form one fleet.

Example — the daemon
$ atlasd --version
atlasd 3.0.0+7c341a4 · wire 5 · relay 2 · seal 2 · pairing 3 · adapter 1 · report 2 · api 1
The configuration tool and the relay server print their own lines — a relay carries the current wire and the one before it
$ atlas-config --version
atlas-config 3.0.0+7c341a4

$ nexus-atlas-relay --version
nexus-atlas-relay 3.0.0+7c341a4 · wire 5, 4 · relay 2
atlasd support-bundle -i nexus0 [-o file.zip] [--no-crashes]

One redacted zip: config (secrets stripped by allowlist), stats, health, journal tail, scheduler log, netcheck, QoS state, versions, crash spool. It prints every redaction it performed — private keys cannot leave by accident.

atlasd crash list|show|export|purge [<id>]

The local crash spool — capture is on by default, and reports stay on the node until an operator acts. IDs match by unique prefix; export writes a signed zip for manual handling.

atlasd crash send <id> [--anonymous|--attributed]

Explicit, per-report upload to the console. Anonymous mode strips identity and forces redaction; background auto-send exists but is off by default.

atlasd enroll <code>

Enroll this node into a hosted console account, with proof-of-possession of the node key. The only way a node ever becomes console-connected.

Patterns worth stealing

# CI gate: fail the pipeline when a config would not load
atlasd config check -c deploy/node-a.toml --json | jq -e '.ok'

# Yesterday's link flaps, machine-readable
atlasd journal -c link -s warn --since 24h --json

# Watch a failover as it happens
atlasd monitor -i nexus0 -r 250

# Print the schema your editor should validate against
atlasd config schema > config.schema.json
Esc
↑ ↓ navigateEnter — openEsc — close