Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/docs/2-handbook/swarm/ui.md
iris 4adbc939f2 docs: the swarm UI page shrinks to an overview
The page-by-page and control-by-control description of the swarm UI moves to
4-implementation/web-ui/swarm-ui.md, with the quick-links wiring. The handbook
page keeps the route table, how to reach the UI, who may and what the browser
keeps. Links to the moved sections point at the new page.
2026-11-11 09:03:05 +01:00

10 KiB

Swarm UI

The swarm's own web surface and the operator's day-to-day view: served by the gateway on the swarm apex (services.hyperhive.swarm.domain), readable only by operators. The per-hive dashboard, on each hive's own domain, covers host-level detail for one hive.

What it shows

The swarm UI is a set of pages. Each one is a card list or a table you open in place, and every one reads from swarm-controller:

route what
/ the start page: the swarm's name over a digital-rain backdrop with the slug (hyperhive / we are the wired, its shaded gradients pulsing in a wave unless reduced motion is on) at the foot, plus a paperclip offering to set up an agent while no ruth exists, or her hive declares her destroyed (it opens the create form with ruth filled in); the swarm name in the header links here
/agents every agent as a card that opens in place (status, terminal, subagents, and settings with permissions, internet, allowed domains and accounts); create agents (with their permissions, optionally from an archetype), link forge, matrix and GitHub accounts
/swarm what belongs to the whole swarm: a folded hives card with the hive directory and each hive's last reported status, a folded egress card with the swarm-wide allowed and denied domains, and a folded, beta notification router card (with a warning banner) holding the router's flows: a switch for each built-in, every flow drawn as a graph, and an editor for custom flows. /notifications redirects here
/agents/<name>/terminal one agent's live terminal
/agents/<name>/subagents/<subagent>/terminal one of that agent's subagents' live terminal
/reports three folded cards, each read only once opened: the alerts the swarm's Grafana holds now, the firing ones, with a button for the pending, no-data and error ones and a link to Grafana's own alert list; read through the controller with a Viewer service-account token, and a cross-repo issues list, and a cross-repo pull requests list
/jobs the controller's job graph, where agent creation and credential mints show progress, and under it the swarm builder's recent builds (agent config PRs, and agents built from internal/meta before a deploy), with what nix printed when one failed, and the review classifier's recent runs, a try-out on a real PR, and its settings
/messages the swarm-wide message feed: every message between agents, and to them from the operator, reminders and compaction, with a history window and a filter on sender or recipient; a folded broadcast card above the feed sends one message to more than one agent at once, and a folded schedules card holds the scheduled prompts: add, edit, pause, resume and remove

An agent created here or with swarmctl agent create starts paused; set it up from its card. A card shows login needed when the agent's claude has no session, with a log in button that runs the claude login from a dialog (see claude-login.md). The wanted badge changes an agent's declared state, destroy included.

Each page, its controls and what they send are in the swarm UI reference.

Enabling

services.hyperhive.deploy.swarm-controller.enable = true;   # the UI comes with it

The UI has no switch of its own (setting deploy.swarm-ui.enable or swarm.ui.enable has no effect, and warns at evaluation), and doesn't follow allSwarmServices: the UI is a view onto the controller's state and reaches it over that daemon's socket, so the host that runs the controller is the host that can serve the UI. A hive that merely uses a swarm has nothing to serve.

The UI build is deploy.swarm-controller.ui.package (defaulted from this flake's swarm-ui package). The older deploy.swarm-ui.package still works and warns at evaluation.

The UI answers on services.hyperhive.swarm.domain and nothing else. It shares that name with the swarm-controller it fronts — one service to a reader and to a certificate — so there is no separate option to pin.

The apex must differ from services.hyperhive.domain. The gateway's default server already answers for the hive domain, and two vhosts claiming one server_name don't error — nginx picks one — so this is an assertion rather than a runtime surprise.

🔑 You must be in the admins group

This is the step that separates "protected" from "locked out." The vhost's auth_request asks authelia "is there a session"; the rule that makes it mean "is this an operator" is an access_control entry requiring group:admins, followed by a deny for everyone else. An account without that group authenticates fine and still gets bounced.

swarmctl user add <you> --email <you>@example.com --group admins
swarmctl user update <you> --add-group admins   # an account that already exists

--email isn't needed for the UI, but the forge won't create your account without one → setup.md § 2.

Why a group and not "any session": agents are authelia subjects too, so authenticated includes every agent in the swarm. The group is the only thing standing between "an operator's page" and "anyone with a session."

When your login ends

When the session ends while a page is open, the page's next /api/ request (a poll, a form, or a stream that dies) gets a plain 401 with a WWW-Authenticate header from the gateway, and the page reloads. The reload lands on the login and, after you log in, back on the same address. A page request still gets the login redirect, and swarmctl --swarm still treats the 401 as a sign to log in again. The page skips a second reload within ten seconds, so a page that keeps answering 401 can't loop.

What the browser keeps

The vhost tells the browser what to cache. The bundle under /static/ has content hashes in its names, so the browser keeps it for a year. The entry document, /sw.js, the manifest, the icons and the theme's colors.css have fixed names, so the browser revalidates them on every load, and a deploy reaches an open browser at its next load. A file that doesn't exist answers 404, including a /static/ file from an older build, rather than the entry document.

The service worker fetches its shell past the HTTP cache and refreshes the cached entry document on each page load that reaches the network. When its install fails, the previous worker keeps running and the browser console shows why.

The pages carry a content security policy: scripts and connections only from this origin, images from this origin, data: and https, and no framing from another origin.

What it costs to be reachable

hyperhive publishes the apex to the hive's resolver like every other swarm service, so agent containers can resolve it. That's deliberate and it's not a hole: reachability isn't the access control here. An agent that resolves the name and connects still has no operator session, and the subrequest denies it.

The header has one 🔗 button, on every page, that opens links to the swarm's other services: the forge, authelia, Grafana, the metrics and log stores, the Matrix client and the secret store's web UI. The list is services.hyperhive.deploy.swarm-controller.links, which defaults to one entry per swarm service. An empty list hides the button. The Bao entry admits members of authelia's admins group only; see credentials.md. Where each URL comes from, and the two places to wire a new swarm service name, are in the reference.

Cross-references