a swarm o 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. 💜
  • Rust 68.7%
  • Nix 15.7%
  • JavaScript 8.4%
  • CSS 3.7%
  • TypeScript 1.9%
  • Other 1.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-06-01 16:49:41 +02:00
.forgejo/workflows fixup: ci.yml — run on PR only, not every branch push 2026-05-31 23:44:12 +02:00
branding forge: auto-set agent-configs org avatar on core start (#424) 2026-05-26 00:10:52 +02:00
docs docs: add ci.md to CLAUDE.md + clarify runner details 2026-06-01 15:52:01 +02:00
frontend chore: scrub #NNN issue references from code comments and nix descriptions 2026-06-01 13:30:52 +02:00
hive-ag3nt fix(#924): set web socket mode to 0o666 so gateway nginx can connect 2026-06-01 15:54:23 +02:00
hive-c0re fix(#947): include manager in agent-sockets.json 2026-06-01 16:49:41 +02:00
hive-forge hive-forge: drop boilerplate # Errors from pure-GET verbs (mara on #827, option A) 2026-05-31 16:22:05 +02:00
hive-matrix-mcp docs: catch up post-#658/#604/#660 + add operator hivectl section (#124) 2026-05-31 10:13:33 +02:00
hive-sh4re feat(#665): harness-internal async bash task runner (option B) 2026-06-01 13:28:31 +02:00
nix fix(#947): set HIVE_WEB_SOCKET for manager unconditionally 2026-06-01 16:49:41 +02:00
scripts forge-login: don't die on RO ~/.config/git/config 2026-05-17 01:22:31 +02:00
.gitignore gitignore .claude/settings.local.json 2026-05-15 14:44:58 +02:00
Cargo.lock Cargo.lock: bump 24 patch-level deps (#680) 2026-05-31 02:44:22 +02:00
Cargo.toml matrix: hive-matrix-mcp crate (daemon+stdio bridge) + harness wiring (#548 phase 3) 2026-05-29 20:51:01 +02:00
CLAUDE.md docs: add stats_vacuum + bash_tasks_vacuum entries to CLAUDE.md file map 2026-06-01 16:11:08 +02:00
flake.lock nix: hyperhive owns nixpkgs pin via follows; bump to nixos-26.05 (#526) 2026-05-30 12:02:48 +02:00
flake.nix feat: add hive-ci module — Forgejo Actions runner for CI 2026-05-31 23:44:12 +02:00
README.md docs(#727): split docs/web-ui.md into shape / dashboard / agent 2026-05-31 21:37:04 +02:00
TODO.md docs: move backlog to forge issue tracker, extract boundary doc 2026-05-20 12:19:16 +02:00

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/ — pick the one matching your task:

reading path doc
dashboard layout + endpoints docs/web-ui.md (shape · dashboard · agent)
claude turn loop + MCP tools docs/turn-loop.md
config-edit + approval state machine docs/approvals.md
what survives destroy / purge / restart docs/persistence.md
naming, wire protocol, commit style docs/conventions.md
nginx vhost map + sub-domain routing docs/gateway.md
NixOS / nspawn gotchas docs/gotchas.md

Host config

Minimal flake.nix for a host that runs hive-c0re:

{
  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 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 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):

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

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>