# First-run setup What's left after the first `nixos-rebuild switch` of the [README's all-local quick start](../../README.md#quick-start-an-all-local-swarm) — from a freshly built host to your first agent. Step 0, the NixOS flake, module and required options, is [`nixos.md`](nixos.md). Everything after that is one command, run as **root on the host**: ```bash swarmctl setup ``` It walks the ten steps interactively, in order. It checks where you stand first, so a rerun continues where it stopped. It shows `Step n of N`, prompts for what each step needs, shows a running action as one live line, and prints the secrets you must record under a ⚠️ warning until you type `yes` to say you stored them. A step this host can't do, because it doesn't run that service, names the deploy option it needs and the host to run `swarmctl setup` on. A session that starts at the SSO account, with the store already set up, looks like this: ```console # swarmctl setup swarmctl setup: 10 steps, 5 left to do ✔ 1 secret store initialised ✔ 2 secret store unsealed ✔ 3 granter bootstrapped ✔ 4 granting units active ✔ 5 store unsealed after the granting units ○ 6 SSO account in the admins group ○ 7 first swarm UI and forge login ○ 8 forge site admin ○ 9 ruth created and up ○ 10 another agent (optional) Step 6 of 10: SSO account in the admins group (5 left, this one included) no enabled user in the "admins" group; the placeholder is disabled Your SSO account is made in the `admins` group, which the swarm UI gates on. Username: mara Display name [mara]: Mara Email address (the forge needs one): mara@example.com ✔ added mara ⚠️ Its generated password follows. It is shown once and stored nowhere. password: … Type `yes` once you have stored the password: yes ``` Steps the tool can't do for you print their command and wait: the unseal under the `shamir` seal, the restart after the granter, and the browser login. Run `swarmctl setup status` at any point to see how far you have got. It changes nothing, and it works from a script: it exits 0 when every step it can see has finished. ```console # swarmctl setup status 🏗️ setup: 6/8 steps done ███████░░░ ❓ 2 unknown ✅ 1 secret store initialised ✅ 2 secret store unsealed ✅ 3 granter bootstrapped the granting units log in through it ✅ 4 granting units active 2 units ✅ 5 store unsealed after the granting units 👉 6 SSO account in the admins group no enabled user in the "admins" group; the placeholder is disabled ↳ setup.md § 2: `swarmctl user add --email
--group admins` ❓ 7 first swarm UI and forge login unknown (not observable: a browser login leaves nothing to read) ❓ 8 forge site admin unknown (not observable: the controller has no read route for it; `forge make-admin` is safe to re-run) ⬜ 9 ruth created and up ruth is declared paused ✅ 10 another agent [optional] 1 besides ruth next: step 6, setup.md § 2: `swarmctl user add --email
--group admins` ``` > **Not all-local?** Each step says which host it runs on. A split swarm > also has credentials you can't generate where they're read — each > host's mTLS identity at the secret store. Read [`2-handbook/swarm/credentials.md`](../2-handbook/swarm/credentials.md) first; it > says which files you place, and where. ## The steps by hand The sections below are the same steps, one command each. Use them to know what a step does, to script one, or to redo one. Do them in order; each one assumes the ones before it. ### 1 · Secret store _On the host running `swarm-bao`._ Everything else fetches its credentials from the store, so it comes first. ```bash swarmctl bao init ``` It prints the unseal (or, under the default `pkcs11` seal, recovery) keys and the root token **once**, and stores none of them: not in a file, and the root token is never in a process's argument list (so not in `ps`). Record them off this host before you do anything else. It refuses an initialised store, and works from any host that can reach the store and has `bao` on `PATH`; the wrapper installed on the store host already knows the store's address and CA. Then bootstrap the **granter**, the one principal that writes every `swarm-*` policy and role from then on. This is the only step that needs the root token. Run it as root on the host running `swarm-bao`: ```bash swarmctl bao grant-bootstrap # prompts for the root token, input hidden ``` It writes the `bao-bootstrap` policy, places a 24h grant token for `swarm-bao-granter-role` and restarts that unit. The token comes from the hidden prompt, or from stdin when stdin isn't a terminal; never from an argument or environment variable. If the granter exists already, it says so and does nothing. To do both steps in one go, without re-typing the root token, run `swarmctl bao init --and-grant` instead (it needs the `pkcs11` seal, which unseals itself). If the host running `swarm-bao` has no `swarmctl` (the controller runs elsewhere), the granting units print the equivalent `bao` commands when the store refuses them. Check `systemctl status swarm-bao-granter-role` logs `Uploaded policy: bao-granter`, then restart the granting units that failed while they waited. The granter unit deletes the token itself after a successful run: ```bash systemctl reset-failed 'swarm-bao-*-policy.service' swarm-bao-agent-pki.service systemctl restart 'swarm-bao-*-policy.service' swarm-bao-agent-pki.service systemctl status swarm-bao-controller-policy # Uploaded policy, Data written to: auth/cert/certs/swarm-controller ``` ⏱️ A first attempt right after a rebuild may fail with `local node not active` while the store comes up; the units retry every 30s for a day. With the default `pkcs11` seal the store unseals itself from here on. With `deploy.bao.seal = "shamir"`, run `bao operator unseal` after every restart. What the granter is, why it's root-equivalent, and the store's TLS: [`4-implementation/swarm/bao.md`](../4-implementation/swarm/bao.md). ### 2 · Your SSO account _On the host running authelia._ Until this runs, `auth.` serves a login page that refuses everyone: its only subject is a placeholder marked `disabled`. ```bash swarmctl user add mara --display-name Mara --email mara@example.com --group admins ``` It prints a generated password once — record it. Keep both flags: - **`--group admins`** — the swarm UI and other operator surfaces gate on it. Without it you log in fine and are then refused. - **`--email`** — the forge won't create an account without one. Fix either afterwards with `swarmctl user update mara --add-group admins --email …`. Details: [`2-handbook/swarm/sso.md`](../2-handbook/swarm/sso.md). ### 3 · Swarm UI login Open `https:///` and sign in with the account from step 2. The name resolves on the box itself through `/etc/hosts`; from anywhere else it needs a real DNS record. → [`2-handbook/swarm/ui.md`](../2-handbook/swarm/ui.md) Signing in to the forge once through SSO creates your forge account under the same username. Then, _on the swarm-controller's host_: ```bash swarmctl forge make-admin mara ``` If the forge already has a local account with your username, the first SSO login asks for its forge password once, to link the two. Agents learn your pronouns from the **Pronouns** field of your forge profile settings. Leave it empty and agents refer to you by name only. ### 4 · Clippy, then ruth hive-c0re creates no agent at startup. On the swarm UI's start page, the paperclip (clippy, the setup assistant) offers to set up ruth, the manager agent. Select it: it opens the create form with `ruth` filled in and the `manage_root_agent` permission checked. That permission mounts the other agents into her container so she can recover them. The form declares her, creates her config repo and deploys her to the hive you pick. The swarm declares a new agent `paused`, so without a further step ruth runs but drives no turns. Open `/agents` in the swarm UI and set her `up` from her card. On a hive that already has a ruth container from an earlier release, create her once the same way, so that her config repo and store identity exist. The container keeps starting with the hive meanwhile. ### 5 · Ask ruth for further help From here on, ask ruth. Open her card on `/agents` in the swarm UI and use the message box under her terminal. She is the manager agent: her MCP surface is the privileged one that configures agents, and she can recover the others. Changes to an agent's config arrive as PRs you merge. → [`2-handbook/agents/agent-roster.md`](../2-handbook/agents/agent-roster.md) To create an agent yourself instead, use the swarm UI, or: ```bash swarmctl agent create --hive firsthive ``` The name is yours to choose; it has no meaning to the swarm. The controller provisions the agent's identity, forge user and config repo (`agent-configs/`, from the default template), then has the hive build and start the container. The hive builds from a copy of hyperhive on the swarm's own forge: the controller mirrors it there as `hyperhive/hyperhive` on a fresh swarm, so the first agent needs no extra step (see [`nixos.md`](nixos.md#the-hyperhive-mirror)). It returns once the scheduler queues the job — watch the swarm UI's job view for progress. Later config changes are PRs on `agent-configs/`; you merge them on the forge, and the merge deploys them. → [`2-handbook/agents/config-changes.md`](../2-handbook/agents/config-changes.md#config-changes) ## After setup: use the swarm UI Day-to-day operation happens in the swarm UI at `https:///`: agents, hives, jobs and messages. Swarm-level operations take over from the per-hive dashboard and `hivectl`. → [`2-handbook/swarm/ui.md`](../2-handbook/swarm/ui.md)