> Source: https://nexusatlas.dev/docs/1.0.0/cli — Nexus Atlas developer documentation (Reference). Converted from the HTML page; the page is canonical. This is the 1.0.0 release line; the current line is 3.0.0 (https://nexusatlas.dev/docs/cli).

# CLI reference

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  v1.0.0+4d54d40
  wire 3 · 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. The thirty-second answer to "is it running and is it healthy".

Example

```
$ atlasd status

  Nexus Atlas  v1.0.0+4d54d40

  nexus0  10.0.100.1/24  lowest_delivery_time  2/2 links alive  1 peer established
```

### `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](https://nexusatlas.dev/docs/1.0.0/api).

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](https://nexusatlas.dev/docs/1.0.0/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](https://nexusatlas.dev/docs/1.0.0/concepts/telemetry#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.

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](https://nexusatlas.dev/docs/1.0.0/config) 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](https://nexusatlas.dev/docs/1.0.0/concepts/identity)). 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](https://nexusatlas.dev/guides/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](https://nexusatlas.dev/guides/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 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.

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. Warnings: 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](https://nexusatlas.dev/docs/1.0.0/concepts/identity#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](https://nexusatlas.dev/guides/admission-modes#invite).

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](https://nexusatlas.dev/guides/admission-modes#cert).

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](https://nexusatlas.dev/guides/admission-modes#pending) and [forwarding](https://nexusatlas.dev/guides/admission-modes#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](https://nexusatlas.dev/docs/1.0.0/cli#cmd-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](https://nexusatlas.dev/guides/area-zeroize#select).

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](https://nexusatlas.dev/docs/1.0.0/cli#cmd-fleet-sign). Outside its fence for `--grace-secs`, the node isolates itself (reversible) or zeroizes. See [Give a node a geofence](https://nexusatlas.dev/guides/area-zeroize#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](https://nexusatlas.dev/docs/1.0.0/cli#cmd-fleet-push). A revoked node can still be named by name or UUID. See [Wipe a node remotely](https://nexusatlas.dev/guides/area-zeroize#zeroize).

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](https://nexusatlas.dev/guides/push-release).

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](https://nexusatlas.dev/guides/rotate-fleet-keys).

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](https://nexusatlas.dev/docs/1.0.0/api#machine-credentials).

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](https://nexusatlas.dev/docs/1.0.0/concepts/qos#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](https://nexusatlas.dev/releases/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 `v1.0.0+4d54d40` 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 1.0.0+4d54d40 · wire 3 · 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 1.0.0+4d54d40

$ nexus-atlas-relay --version
nexus-atlas-relay 1.0.0+4d54d40 · wire 3, 2 · 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
```
