Watch
0
0
Fork
You've already forked hyperhive
0

docs(swarm): facts + structure pass

swarm/README.md opens with the swarm and its control plane; hive identity
and the directory follow as the substrate. Upgrade notes move into a
<details> block, the per-agent queue publishing detail into another, and
the one-paragraph pointer sections collapse into a link list.

Fact fixes, checked against origin/main:
- an empty swarm.hives fails eval (swarm.nix:341-354); it does not mean
  "not in a swarm"
- swarm.domain is required with a hive (hive-network.nix:156,188), hiveName
  with a hive, store or homeserver (hyperhive.nix:161-166)
- the matrix container trusts the hive's trust-bundle.pem at runtime under
  self-signed certs (hive-matrix.nix:1046-1052, lib/hive-ca-trust.nix:76-85)
- singleHostSwarm also defaults the controller, localHostsEntry, the nats
  callout keys and the bao bootstrap token path (local-defaults.nix:72-129)
- swarm-controller serves far more than /health: roster, wanted state, job
  graph, agent creation and credential mints (main.rs:2874-2899)
- swarmctl user add needs --email for the forge account and refuses an
  existing user (setup.md:67-71, swarmctl/src/main.rs:425-430); document
  agent mint-identity and mint-forge-token
- agent creation also mints store identity, forge token and matrix
  account, and declares the agent paused (main.rs:1822-1920, 247-248)

Refs #3902
This commit is contained in:
atlas 2026-10-01 23:25:24 +02:00 • committed by mara
commit 270430a4b4
5 changed files with 408 additions and 402 deletions

View file

@ -31,18 +31,9 @@ that.
## One file, two writers
`users.yml` — authelia's own users database — is read and written
directly. There is no second store.
There used to be: a private `users.json` here, canonical, with `users.yml`
rendered from it, while `swarm-authelia-bridge` kept its own pair against
the _same_ physical file. Two canonical stores for one file is a seam, and
it bit — a writer whose own JSON was missing could not tell "nothing here
yet" from "someone else's users", and refused to write.
The argument for the split was that it let this crate work without a YAML
parser. It didn't: the JSON was read back on every run, so the round-trip
was already being paid — the two files differed only in _format_.
`swarmctl` reads and writes `users.yml` — authelia's own users database —
directly, with no second store. `swarm-authelia-bridge` writes agent
subjects into the same file.
⚠️ The file is round-tripped, so **comments and hand-formatting do not
survive a write**. Values do, and so do keys this binary does not model.
@ -62,18 +53,30 @@ an error.
| `SWARMCTL_AUTHELIA_USERS_FILE` | host-side path of the users database |
| `SWARMCTL_AUTHELIA_MACHINE` | container name, for `systemctl -M` |
| `SWARMCTL_AUTHELIA_UNIT` | authelia's unit inside that container |
| `SWARM_CONTROLLER_SOCKET` | the controller's unix socket, for `agent create` |
| `SWARM_CONTROLLER_SOCKET` | the controller's unix socket, for `agent` and `forge` verbs |
Every verb and flag: [`docs/tools/swarmctl-cli.md`](../docs/tools/swarmctl-cli.md).
The sections below cover why each verb behaves as it does.
## `user add`
```console
# swarmctl user add mara --display-name "Mara" --group admins
# swarmctl user add mara --display-name "Mara" --email mara@example.com --group admins
```
Keep both flags:
- **`--group admins`** — the swarm UI and other operator surfaces gate on it.
- **`--email`** — the forge won't create an account without one.
`user add` refuses a username that already exists; fix an existing account
with `swarmctl user update mara --add-group admins --email …`.
The password is **generated by authelia** (`crypto hash generate argon2
--random`) and printed once. It is never passed on a command line:
`/proc/<pid>/cmdline` is world-readable, so a password in argv is readable
by any local process for the lifetime of the call.
by any local process for the lifetime of the call. `user reset-password`
generates a new one the same way.
## `agent create`
@ -89,13 +92,17 @@ module sets from the daemon's own `socketPath`). It prints the queued
job's node id **and stops there**.
It deliberately does not wait. The endpoint queues a DAG — SSO identity,
forge user, forge repo, repo membership, config-repo seed, then a deploy
forge user, forge repo, repo membership, config-repo seed, store identity,
forge token, matrix account, a `paused` wanted state, then a deploy
message — and the last of those _publishes_: the hive's `hive-c0re` picks
it up and converges on its own clock, out of the controller's sight. So
even a fully settled graph would not mean the agent is up, and there is
nothing this CLI could wait for that would let it say so honestly. Watch
the swarm UI's job view for the rest.
The new agent starts `paused`: it doesn't drive turns until you set it `up`
in the swarm UI.
No approval gate, for the same reason nothing else here has one: running
this binary already means being root on the controller's host.
@ -110,6 +117,30 @@ crate does not link it, and there is no wire-type crate between them.
Two fields out, two in, both ends validating — a drift shows up as a
400 naming the field.
## `agent mint-identity`
```console
# swarmctl agent mint-identity ruth
```
`POST /api/agents/{name}/identity` on the swarm-controller. Re-runs the
store-identity mint for one agent that already exists — the backfill for an
agent the swarm never created, such as the manager agent `hive-c0re` makes at
startup. It re-mints the agent's store certificate, which the agent picks up
the next time its container boots, and leaves an existing queue secret alone.
Queues and returns, like `agent create`.
## `agent mint-forge-token`
```console
# swarmctl agent mint-forge-token ruth
```
`POST /api/agents/{name}/forge-token` on the swarm-controller. Checks one
agent's forge token and mints it if it's missing or stale. The controller
already does this for every agent with a store identity at start and every
five minutes; this verb skips the wait. Queues and returns.
## `forge make-admin`
```console