docs/web-ui.md (1315 lines) split into three sub-files: - docs/web-ui/shape.md — shared SPA skeleton, SSE multiplexing, Worker-death self-heal, terminal pane, listener bind, relative paths, atomic repaint, side panel - docs/web-ui/dashboard.md — SW4RM/Y3R/SYST3M/SCH3DUL3S/S3TT1NGS tabs, container row, topology tree, selection bar, approval card, dashboard endpoints + event channel - docs/web-ui/agent.md — header, terminal, composer, inbox, live view, slash commands, per-agent endpoints, stats page docs/web-ui.md replaced with a thin index linking all three. Section anchors in docs (gateway.md, gotchas.md), Rust doc comments (hive-ag3nt/src/web_ui.rs), and nix/templates/weston-vnc.nix updated to point at the correct sub-file. README and CLAUDE.md file-map updated with sub-file links. Inline // comments in frontend source left unchanged (they reference the index which redirects to the right sub-file).
236 lines
11 KiB
Markdown
236 lines
11 KiB
Markdown
# <img src="branding/hyperhive.svg" alt="" width="38" align="top"> hyperhive
|
|
|
|
> a swarm of claude-code agents, each in its own nspawn cage, gossiping
|
|
> over unix sockets. config changes flow as git commits, the operator
|
|
> approves them in a browser, every deploy is a tag. cyberpunk-themed
|
|
> dashboard included. 💜⚡
|
|
|
|
Claude code is great in one window, *exponentielle* across many — but
|
|
only if you can keep the agents from stepping on each other, give them
|
|
durable identity, and stop them from eating production. hyperhive is
|
|
the substrate.
|
|
|
|
- identity = unix socket
|
|
- communication = sqlite-backed broker (`send` / `recv` / `ask` /
|
|
`answer` / `remind`)
|
|
- config = git (manager proposes, operator approves, deploys land as
|
|
tagged commits)
|
|
- blast radius = container
|
|
|
|
```
|
|
host (NixOS, runs hive-c0re.service)
|
|
│
|
|
├── operator
|
|
│ ├── browser → :7000 hive-c0re dashboard
|
|
│ ├── browser → :8100-8999 per-agent web UIs (all agents, FNV-1a hash)
|
|
│ └── CLI → /run/hyperhive/host.sock admin protocol
|
|
│
|
|
├── hive-c0re (Rust daemon: lifecycle / broker / approvals /
|
|
│ auto-update / dashboard / sockets)
|
|
│
|
|
└── nixos-containers
|
|
├── hm1nd manager agent (privileged MCP surface)
|
|
└── h-<name> sub-agent (vanilla MCP surface + per-agent extras)
|
|
```
|
|
|
|
Depth lives in [`docs/`](docs/) — pick the one matching your task:
|
|
|
|
| reading path | doc |
|
|
| --- | --- |
|
|
| dashboard layout + endpoints | [`docs/web-ui.md`](docs/web-ui.md) ([shape](docs/web-ui/shape.md) · [dashboard](docs/web-ui/dashboard.md) · [agent](docs/web-ui/agent.md)) |
|
|
| claude turn loop + MCP tools | [`docs/turn-loop.md`](docs/turn-loop.md) |
|
|
| config-edit + approval state machine | [`docs/approvals.md`](docs/approvals.md) |
|
|
| what survives destroy / purge / restart | [`docs/persistence.md`](docs/persistence.md) |
|
|
| naming, wire protocol, commit style | [`docs/conventions.md`](docs/conventions.md) |
|
|
| nginx vhost map + sub-domain routing | [`docs/gateway.md`](docs/gateway.md) |
|
|
| NixOS / nspawn gotchas | [`docs/gotchas.md`](docs/gotchas.md) |
|
|
|
|
## Host config
|
|
|
|
Minimal `flake.nix` for a host that runs hive-c0re:
|
|
|
|
```nix
|
|
{
|
|
inputs = {
|
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
|
|
hyperhive.url = "git+https://forge.darkest.space/hyperhive/hyperhive";
|
|
};
|
|
|
|
outputs = { nixpkgs, hyperhive, ... }: {
|
|
nixosConfigurations.my-host = nixpkgs.lib.nixosSystem {
|
|
system = "x86_64-linux";
|
|
modules = [
|
|
hyperhive.nixosModules.default # hive-c0re + hive-forge + hive-gateway in one import
|
|
({ ... }: {
|
|
services.hyperhive.enable = true;
|
|
# services.hyperhive.c0re.operatorPronouns = "they/them"; # default: "she/her"
|
|
|
|
# ... rest of your host config
|
|
system.stateVersion = "25.11";
|
|
})
|
|
];
|
|
};
|
|
};
|
|
}
|
|
```
|
|
|
|
hive-c0re opens its admin socket + dashboard, auto-creates the
|
|
manager container, and auto-rebuilds any container whose hyperhive
|
|
rev goes stale. `claude-code` is unfree — hyperhive scopes the
|
|
whitelist to itself, nothing for the operator to set.
|
|
|
|
Optional: set `services.hyperhive.gateway.enable = false;` to bypass
|
|
the default nginx in front. By default (`gateway.enable = true`) every
|
|
request hits a small nginx in its own nixos-container that proxies
|
|
to hive-c0re's dashboard on the upstream port; `/matrix/` is served
|
|
directly from `services.hyperhive.matrix.gui.package` when the matrix
|
|
GUI is on. v0 is HTTP-only (TLS lives in a follow-up); pair with
|
|
`services.hyperhive.gateway.localHostsEntry = true;` for local dev so
|
|
`http://<services.hyperhive.domain>` resolves to the host without
|
|
setting up real DNS.
|
|
|
|
Optional: set `services.hyperhive.c0re.preBuildAgentTemplates = true;`
|
|
to pre-fetch the per-container system closures into your host's
|
|
/nix/store as part of `nixos-rebuild`. First-agent-spawn then
|
|
completes in seconds instead of minutes (no nixpkgs/claude-code
|
|
fetch on the critical path), at the cost of a few GB extra in your
|
|
system closure. Off by default (the toplevels are pinned to
|
|
`x86_64-linux`, so non-x86 hosts would otherwise force a cross-build).
|
|
Alternatively warm the store manually:
|
|
`nix build git+https://forge.darkest.space/hyperhive/hyperhive#agent-base-toplevel`.
|
|
|
|
Optional: set `services.hyperhive.domain = "example.com";` to define the
|
|
canonical hostname for hyperhive subsystems that need a stable public
|
|
name. No default — subsystems that require it (currently:
|
|
`services.hyperhive.matrix`) assert non-null at eval time with a clear
|
|
error message if it is missing.
|
|
|
|
Optional: set `services.hyperhive.hiveName = "pr1ma";` and / or
|
|
`services.hyperhive.swarmName = "constellat1on";` to give the hive and
|
|
the wider swarm human-readable display labels. Distinct from
|
|
`services.hyperhive.domain` (the DNS address): the names surface in
|
|
the dashboard chrome and the per-agent system prompt; the domain is
|
|
how things are addressed on the wire. Federated hives at different
|
|
domains can share a swarm name. Both default to null — chrome falls
|
|
back to the domain, the prompt simply doesn't mention them.
|
|
|
|
Optional: set `services.hyperhive.matrix.enable = true;` to spin up a
|
|
private [matrix-tuwunel](https://github.com/matrix-construct/tuwunel)
|
|
homeserver in a nixos-container. Requires either
|
|
`services.hyperhive.domain` or `services.hyperhive.matrix.serverName`
|
|
to be set (eval fails with a clear error if both are absent). The
|
|
`server_name` (embedded irrevocably in every user and room ID)
|
|
defaults to `<domain>` (bare hive domain); the hive-gateway serves
|
|
`.well-known/matrix/{client,server}` endpoints so clients auto-discover the
|
|
homeserver without a subdomain. **Existing homeservers** must set
|
|
`services.hyperhive.matrix.serverName = "matrix.<domain>";` explicitly to
|
|
preserve their existing user/room IDs (the `server_name` is embedded
|
|
into every ID). Override with
|
|
`services.hyperhive.matrix.serverName = "chat.example.com";` for a custom
|
|
server name. State
|
|
lives at `/var/lib/nixos-containers/hive-matrix/`. Federation is
|
|
enabled with an empty `trusted_servers` list; e2ee is deferred to
|
|
a follow-up.
|
|
|
|
The hive-gateway nginx container serves a
|
|
[fluffychat-web](https://fluffychat.im) matrix client at `/matrix/`
|
|
when `services.hyperhive.matrix.gui.enable` is on. This defaults to
|
|
`services.hyperhive.matrix.enable`, so enabling the homeserver enables
|
|
the web client by default; set `gui.enable = false` explicitly to keep
|
|
the homeserver without the GUI. The `◆ M4TR1X ◆ →` tab appears in
|
|
the dashboard chrome when enabled. The web client can
|
|
connect to any Matrix homeserver; enter the URL at first visit (e.g.
|
|
the local tuwunel instance if `services.hyperhive.matrix.enable = true`, or
|
|
any external homeserver).
|
|
|
|
## Agent configuration
|
|
|
|
Per-agent settings live in each agent's `agent.nix` and are synced to
|
|
the container as environment variables. Common options:
|
|
|
|
- **`hyperhive.model`** — Claude model for this agent (default: `"haiku"`).
|
|
Sets `HIVE_DEFAULT_MODEL` in the container; the harness applies it at
|
|
boot and it takes priority over any persisted runtime override. The
|
|
operator can still switch the model at runtime via the per-agent web UI,
|
|
but that choice is reset by any rebuild that changes this option.
|
|
- **`hyperhive.allowedRecipients`** — List of agent names this agent can
|
|
message (via `send`). If unset, all agents are allowed. Useful to
|
|
restrict an agent to talking only to the manager.
|
|
- **`hyperhive.forge.url`** — Base URL of the hyperhive-managed Forgejo
|
|
(default: `"http://localhost:3000"`). Used to configure the agent's
|
|
tea login at boot; no-op if `/state/forge-token` is missing.
|
|
- **`hyperhive.forge.keepSubscriptions`** — Boolean. If `true`, the agent's
|
|
forge repo subscriptions are never auto-cleaned during rebuild; useful
|
|
for agents that want to watch specific repos. Rendered as
|
|
`HIVE_FORGE_KEEP_SUBSCRIPTIONS`.
|
|
- **`hyperhive.forge.skipNotifyReasons`** — List of forge notification
|
|
`reason` values to suppress (e.g. `[ "subscribed" "participating" ]`).
|
|
Notifications matching these reasons are silently dropped; all others
|
|
including direct mentions and reviews are delivered. Empty list (default)
|
|
delivers all notifications. Rendered as `HIVE_FORGE_NOTIFY_SKIP_REASONS`
|
|
(comma-separated).
|
|
- **`hyperhive.frontend.dist`** — Override the default frontend package
|
|
(`pkgs.hyperhive-frontend`, built by `nix/frontend.nix`). Set to a custom
|
|
derivation to ship a fully custom per-agent SPA. The JSON contract
|
|
(`/api/state`, `/events/stream`, action endpoints) is the source of truth
|
|
for any replacement.
|
|
- **`hyperhive.frontend.extraFiles`** — Attrset of extra files/directories
|
|
to layer on top of the default agent dist. Each entry has a `source` (nix
|
|
path) and an optional `target` (URL prefix in the static tree, defaults to
|
|
the attribute name). Example: `{ bitburner.source = ./bitburner-dist; }`
|
|
serves that dist at `/bitburner/`. Pure additions only — overwriting an
|
|
existing default file is a hard eval-time error; use `frontend.dist` to
|
|
replace the whole dist. Paths with leading `/` or `..` segments are
|
|
rejected at eval time.
|
|
|
|
- **`hyperhive.matrix.enable`** — Boolean (default `true`). When true,
|
|
each agent container runs `hive-matrix-daemon` (a long-running
|
|
matrix-sdk process that holds the per-agent client + sync) and
|
|
auto-injects `hive-matrix-mcp` as a stdio MCP server so claude can
|
|
call the matrix tools (`mcp__matrix__send_message`, `send_dm`,
|
|
`send_reaction`, `send_reply`, `mark_read`, `list_rooms`,
|
|
`list_room_members`, `read_room`; `room` args accept both
|
|
`!id:server` and `#alias:server` forms). Silently no-ops when
|
|
`<state>/matrix-token` is absent (i.e., the host-level
|
|
`hyperhive.matrix` tuwunel container hasn't provisioned the account
|
|
yet). Set to `false` to opt a specific agent out of matrix.
|
|
- **`hyperhive.user.name`** — Unix username the agent runs as inside
|
|
the container (default: the agent's own label, injected by the
|
|
meta-flake). Agents no longer run as root. Stand-alone module eval
|
|
without the meta-flake falls back to `"agent"`.
|
|
- **`hyperhive.user.passwordlessSudo`** — Boolean (default `true`).
|
|
Grants the agent user `NOPASSWD: ALL` sudo so claude's `Bash` tool
|
|
can still escalate when needed — same surface as the old root-user
|
|
shape, just explicit. Set `false` for strictly unprivileged agents.
|
|
|
|
See `nix/templates/harness-base.nix` for the full list of options and
|
|
their descriptions.
|
|
|
|
## Operator CLI
|
|
|
|
`hivectl` is the operator-facing host CLI for ad-hoc administration that
|
|
doesn't go through the broker (built alongside `hive-c0re` when the host
|
|
module is enabled):
|
|
|
|
```sh
|
|
sudo hivectl forge create-user mara # provisions a forge user
|
|
sudo hivectl forge create-user mara --password 'hunter2' # … with a fixed password
|
|
sudo hivectl matrix create-user mara # provisions a matrix user
|
|
sudo hivectl matrix create-user mara --password-stdin # … reading one line from stdin
|
|
```
|
|
|
|
For agent names (i.e., a `Coordinator::agent_state_root(name)` exists),
|
|
`hivectl` persists the resulting token to the agent's state dir like the
|
|
boot sweep does. For non-agent names (e.g. the operator's own forge/matrix
|
|
account), it prints the token to stdout and writes nothing.
|
|
|
|
## Build / deploy
|
|
|
|
```sh
|
|
nix develop -c cargo check
|
|
nix flake check # rust + nix + toml fmt + clippy
|
|
|
|
# deploy from a host config that imports hyperhive.nixosModules.hive-c0re
|
|
nix flake update --update-input hyperhive
|
|
sudo nixos-rebuild switch --flake .#<host>
|
|
```
|