# Many Swarm machines as one fleet (for AIs)

For AIs. A person can run Swarm on several machines (their PC, a VPS, a VM per client). Over Tailscale, one MCP server, `swarm-fleet`, reaches all of them: you see every machine, choose which one runs each job and monitor the whole fleet. Nothing is put on the public internet.

Status: ready, in daily use across several machines. Source: `packages/swarm-fleet` and `containers/headless/app/TAILNET.md` in https://github.com/swarm-agent/swarm. Report what fails.

You run every command. The person only creates accounts and keys in the Tailscale admin console when you tell them to, and never pastes a key into chat.

## 1. Tailscale policy (once, in the person's admin console)

- The tailnet needs **MagicDNS** and **HTTPS certificates** (admin console, DNS page).
- Access controls: Swarm's policy is `containers/headless/app/tailnet-policy.hujson` in the repository. The person pastes it into their access controls, keeping sections they already have. It replaces the default "everyone reaches everything" rule.
- The policy grants devices `read` or `write` on machines tagged `tag:swarm` through the `swarmagent.dev/cap/swarm` capability. `read`: status, sessions, usage, models, projects, workers. `write`: also start work and stop runs. Never granted this way: approving tool calls, managing workers, limits or models. `tag:swarm-protected` machines are read-only to AI devices.

## 2. Each Swarm machine

- New machine: install with Tailscale at once: `curl -fsSL https://swarmagent.dev/install | sudo bash -s -- --tailnet` (or with `TS_AUTHKEY` in root's environment and `--tag tag:swarm`, so no login link is needed).
- Existing machine: `sudo bash /var/lib/swarm-headless/install.sh tailnet on --tag tag:swarm` (it prints a login link for the person unless `TS_AUTHKEY` is set), then `install.sh tailnet-identity on`.
- `install.sh status` shows the machine's tailnet MCP: `https://NAME.TAILNET.ts.net:8444/mcp`. Swarm's log says `tailnet identity on` when devices are admitted by the policy.

## 3. Connect to every machine at once

On a device in the tailnet, with a checkout of the repository:

    claude mcp add swarm -- bash /path/to/swarm/packages/swarm-fleet/fleet.sh

`swarm-fleet` finds machines tagged `tag:swarm` (`FLEET_TAGS`), lists their tools with a `machine` argument and forwards each call to that machine's gateway (port 8444). Machines admitted only by the policy need no key. A machine outside discovery, or one you must manage (models, limits), goes in `SWARM_FLEET` as `[{"name","url","token"}]` with a full AI key from that machine.

One machine only: `claude mcp add --transport http swarm https://NAME.TAILNET.ts.net:8444/mcp` (Codex: `codex mcp add swarm --url https://NAME.TAILNET.ts.net:8444/mcp`).

## 4. Monitor the fleet

- `swarm_fleet_status`: every machine in one view: reachable, access level, running sessions, today's usage against its limits, and its own `swarm_status` (`ok`, `attention`, `degraded` with reasons).
- Per machine: `swarm_status` and `swarm_activity` with `machine`.
- Alerts from every machine: each one's signal feed can be forwarded to the person's endpoint with a signal sink: https://swarmagent.dev/ai/alerts.md.
- A dashboard that only watches: a read-only monitor key per machine (`signals:read`), also in alerts.md.

## 5. One model table

- `swarm_fleet_models`: the fleet table (one provider, model and thinking level per role: coder, finder, designer, compact, router), overrides, and per machine what each role actually runs: `in_sync`, `override`, `drift` (with `wanted`), `unset` or `unknown`.
- `swarm_fleet_set_models` `{models: {coder: {provider, model, thinking?}}}` merges into the table and applies it to every machine; `{machine, models}` sets an override for one; `{machine, clear_override: true}` drops it; `apply: false` only records. Setting models is a manage operation: a machine admitted only by the policy is shown but cannot be changed without a full key in `SWARM_FLEET`.
- The table is stored at `~/.config/swarm-fleet/fleet.json` (0600, no secrets). Change models only when the person asks.

## 6. Claude Code on the web (preview)

Not yet exercised by the Swarm team: say so to the person, and report what fails.

A cloud session joins the tailnet as a throwaway device:

- Environment variables: `TS_AUTHKEY` and `MCP_TIMEOUT=120000`. The person creates the key in the admin console (Settings, Keys): reusable, ephemeral, pre-approved, tag `tag:claude`, with an expiry. Anyone who can use the environment can read it, so keep `tag:claude` grants at `read` unless `write` is needed.
- Setup script: the contents of `packages/swarm-fleet/claude-web-setup.sh`.
- Network access must allow `pkgs.tailscale.com`, `*.tailscale.com` and `raw.githubusercontent.com`.
- A new session then has the Swarm tools: "list my Swarm machines".

## 7. All results in one bucket (optional)

Each machine can export its signal log and finished jobs to one bucket: set `SWARM_OUTBOX_URL` (`gs://BUCKET/PREFIX`, `s3://BUCKET/PREFIX` or `file:///DIR`) with an HMAC key in `SWARM_OUTBOX_ACCESS_KEY_ID` / `SWARM_OUTBOX_SECRET_ACCESS_KEY` in the daemon's environment (`install.sh daemon-env set`). Layout: `machines/<machine>/log/<seq>.json`, `machines/<machine>/results/<run>.json` (status, outcome, report, cost, commits and a Git bundle) and `machines/<machine>/blobs/sha256/<hash>` (bundles and media). Objects are written once and never changed.

## Turning things off

- One AI device: remove it in the admin console (ephemeral ones vanish on their own).
- All AI devices: revoke the auth key or delete the `tag:claude` grants.
- One machine: `install.sh tailnet-identity off`, or remove its tag. AI keys keep working either way.
