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
atlas ec4ba4c7fa feat(#2862): fd-carrying line framing for the priv socket
First half of the fd-passing work, and deliberately the half with the
real failure mode in it. No syscalls here — the caller does the
recvmsg and feeds this (bytes, fds); it hands back complete messages
paired with the descriptor each one owns.

Association is the whole point. A descriptor does not arrive neatly
paired with the request that wants it: recvmsg returns whatever bytes
happen to be available plus whatever ancillary data rode along, so a
descriptor can arrive with a chunk holding only part of its request's
line, with a chunk whose bytes finish the previous request, ahead of
any of its own bytes, or alongside several complete requests at once.

Pairing "the fd from this chunk" with "the request in this chunk" is
therefore wrong in the worst way: the types are identical either way,
so nothing catches it, and the failure is one request executing
against another's descriptor — in this process, writing one agent's
state into a different transfer's socket. So descriptors queue on
arrival and each message claims the oldest unclaimed one at the moment
it completes.

Two consequences worth stating: a line that fails to decode does NOT
consume a descriptor (closing it there would destroy something
belonging to a request nobody processed), and unclaimed descriptors
are drainable so the teardown path can close them instead of leaking
one per abandoned message in a long-lived helper.

Lives in hive-priv-sock, not hive-priv: clippy's dead-code error was
right that an unwired module doesn't belong in the binary, and chasing
that produced the better home anyway — both ends need this. The daemon
sends descriptors and the helper reassembles them, so framing is part
of the wire contract rather than one side's implementation detail.
2026-07-31 22:15:37 +02:00
.forgejo/workflows docs: stop claiming tracker-tag/comment-block lint are non-required 2026-07-23 00:10:59 +02:00
branding docs(#1182): remove component-diagram.svg; trim README; link to website + options 2026-06-03 19:06:06 +02:00
claude-plugins hive-forge: lint no-reviewer checks actual requested-reviewers, not a text mention 2026-07-27 19:07:36 +02:00
docs refactor(#2862): keep the option at services.hyperhive.snapshotStore 2026-07-31 19:03:24 +02:00
frontend fix: reinstate the style-tag doc-comment fix lost when the merge commit was dropped for a rebase 2026-07-31 21:56:50 +02:00
hive-agent stop telling agents to git against literal localhost:3000, point at $HIVE_FORGE_URL 2026-07-31 18:40:37 +02:00
hive-agent-mcp stop telling agents to git against literal localhost:3000, point at $HIVE_FORGE_URL 2026-07-31 18:40:37 +02:00
hive-agent-sock feat(#2635): wire harness-local questions mirror (inc2 pt2) 2026-07-26 02:07:33 +02:00
hive-bash-mcp hive-bash-mcp: flag bash-task completions with stderr instead of exit code 2026-07-31 15:48:50 +02:00
hive-c0re hive-c0re: wire up openapi spec + swagger ui (#2872) 2026-07-31 21:48:02 +02:00
hive-core-agent-sock docs(#2627): add READMEs for the remaining infra crates 2026-07-23 13:16:29 +02:00
hive-forge hive-forge: attach the resolved repo to every verb's error 2026-07-29 21:18:32 +02:00
hive-forge-notify feat(#2642): a github.com notification poller alongside the forge one 2026-07-31 17:23:18 +02:00
hive-host-sock refactor(#2808): the wire state enum is the scheduler's own 2026-07-27 21:50:24 +02:00
hive-jobq refactor(#2808): the wire state enum is the scheduler's own 2026-07-27 21:50:24 +02:00
hive-matrix-mcp refactor(sock): one socket client, retry as a policy value 2026-07-26 22:44:48 +02:00
hive-metric docs(#2627): add READMEs for the remaining infra crates 2026-07-23 13:16:29 +02:00
hive-priv hivectl: rename hivectl agents to hivectl agent <name> <verb> 2026-07-27 19:07:18 +02:00
hive-priv-sock feat(#2862): fd-carrying line framing for the priv socket 2026-07-31 22:15:37 +02:00
hive-screen-mcp docs(#2627): add README for hive-screen-mcp 2026-07-23 14:17:47 +02:00
hive-sh4re remove request_next_turn: same-turn continuation is always worse than an external wake 2026-07-27 22:15:36 +02:00
hive-sock-client refactor(sock): one socket client, retry as a policy value 2026-07-26 22:44:48 +02:00
hive-types docs(#2627): add READMEs for the remaining infra crates 2026-07-23 13:16:29 +02:00
hivectl refactor(#2808): the wire state enum is the scheduler's own 2026-07-27 21:50:24 +02:00
nix add /health/live and /health/ready hive-wide health endpoints 2026-07-31 21:01:23 +02:00
scripts docs: stop claiming tracker-tag/comment-block lint are non-required 2026-07-23 00:10:59 +02:00
.gitignore fix(review): drop libnull.rlib artifact + add Errors doc to ensure_config_pr_webhook 2026-07-11 12:19:52 +02:00
.mailmap chore(#2165): add damocles@pr1ma + lexis@pr1ma mailmap entries 2026-07-04 13:50:16 +02:00
.prettierignore fix(#1997): exclude docs/tools/forge.md from prettier (list-item continuations) 2026-07-02 23:33:11 +02:00
.prettierrc temp: add prettier configs 2026-07-02 23:33:11 +02:00
Cargo.lock hive-c0re: wire up openapi spec + swagger ui (#2872) 2026-07-31 21:48:02 +02:00
Cargo.toml hive-c0re: wire up openapi spec + swagger ui (#2872) 2026-07-31 21:48:02 +02:00
CLAUDE.md docs(#2862): document the snapshot store, drop the dedicated option 2026-07-31 19:03:24 +02:00
clippy.toml hivectl: wireguard mesh setup verbs (#1756) 2026-06-19 14:37:50 +02:00
flake.lock nix flake update 2026-07-13 13:58:53 +02:00
flake.nix feat(#2642): a github.com notification poller alongside the forge one 2026-07-31 17:23:18 +02:00
README.md docs: shorten Overriding nixpkgs section 2026-07-16 00:06:17 +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 → :80 (hive-gateway)    dashboard + per-agent UIs
│   │                                   /agent/<name>/ → per-agent unix socket
│   └── CLI     → /run/hyperhive/host.sock   admin protocol
│
├── hive-c0re  (Rust daemon: lifecycle / broker / approvals /
│               auto-update / dashboard / sockets)
│
├── optional containers
│   ├── hive-gateway   nginx — proxies :80 → c0re dashboard + per-agent sockets
│   ├── hive-forge     Forgejo — per-agent accounts, config mirror (agent-configs/)
│   └── hive-matrix    tuwunel — Matrix homeserver + per-agent accounts
│
└── agent containers
    ├── h-ruth     manager (privileged MCP surface, approval gating)
    └── h-<name>   sub-agent (claude + MCP tools + per-agent web UI + unix socket)

→ website · → options reference

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

Quick start

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";
    # Pin hyperhive to your own nixpkgs instead of the one it ships with
    # (see "Overriding nixpkgs" below) — recommended for most hosts:
    hyperhive.inputs.nixpkgs.follows = "nixpkgs";
  };

  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.

Overriding nixpkgs

hyperhive pins its own nixpkgs so it builds standalone in CI. Add hyperhive.inputs.nixpkgs.follows = "nixpkgs" (as in the quick-start above) to build it against your host's nixpkgs instead — one less nixpkgs evaluation, no version drift from the rest of your system. Standard flake follows pattern; works as long as your channel is reasonably close to the nixos-26.05 hyperhive develops against. Drop it again if a much older/newer channel hits breakage hyperhive's CI doesn't catch.

For the full list of host and agent NixOS options see the options reference.

Agent configuration

Per-agent config lives in each agent's agent.nix (proposed, operator-approved, deployed as git commits). Key options:

Multi-account Matrix support

hyperhive.matrixAccounts declares additional matrix accounts for an agent, beyond the hive-internal one. Each entry is keyed by account name and specifies:

  • tokenFile — path to the matrix bearer token (provisioned out-of-band)
  • sessionDir — path to the per-account matrix-sdk sqlite state (crypto keys + cache)
  • homeserver — optional homeserver URL (defaults to hyperhive.matrix.url)

Example:

hyperhive.matrixAccounts = {
  external-public = {
    tokenFile = "/agents/myagent/state/matrix-token-external";
    sessionDir = "/agents/myagent/state/matrix-sdk-state-external";
    homeserver = "https://matrix.org";
  };
};

The hive-internal account is always named main (synthesized from hyperhive.matrix.url + agent state). This option only declares extras; the main name is reserved and cannot be used here. Requires hyperhive.matrix.enable = true.

For more details see docs/matrix.md.

GitHub account

Every agent gets a managed GitHub identity — a gh CLI wrapper and git push over HTTPS — on by default (hyperhive.github.enable), inert until a PAT is provisioned. There is nothing per-agent to declare: paste an operator-supplied personal access token into the agent's dashboard credentials tab (or hivectl github set-token <agent> --token-stdin) and it works. The gh wrapper + git credential helper read the token live (git auths as x-access-token + the PAT; github.com only), so a rotated PAT takes effect with no rebuild.

Turn the integration off for the whole hive with the host option:

services.hyperhive.github.enable = false;

The PAT value is never in nix — only the enable flag. For more details see docs/github.md.

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.default
nix flake update --update-input hyperhive
sudo nixos-rebuild switch --flake .#<host>