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
iris dd92ef07fa dashboard: inline edit form on schedule rows (closes #474)
Per damocles's PATCH /api/schedules/{id} backend (#475), each
non-cancelled schedule row gets a `✎ edit` button that toggles
an inline form pre-filled with current values. Editable:

- body (textarea)
- description (blank to clear)
- next-fire (datetime-local)
- interval (shared composer from #466 — all-zero flips to one-shot)

Targets stay immutable per the design call with damocles:
per-target last-result history is keyed on them; cancel + new
schedule is the documented retarget workaround. The form
surfaces the active target list as a read-only note explaining
this.

Submit semantics — the form computes a PATCH diff against the
original schedule and only includes keys for fields that
actually changed. Blank description → `null` (clear), all-zero
interval on a recurring schedule → `null` (flip to one-shot).
No-op submit (no fields changed) just closes the edit form.

Refactored the interval composer (#466) into a shared
`buildIntervalComposer({ label, namePrefix, initialSeconds })`
helper so the new-schedule and edit-schedule forms use the same
chip/d/h/m/s/preview widget. New-schedule form behavior
unchanged; edit-form input names are prefixed `edit_interval_`
to avoid FormData collisions when both happen to mount.

State survives state-poll re-renders via `editingSchedules`
(Set of ids being edited) + `scheduleEditCarry` (per-id
mid-edit values) — same pattern the new-schedule form uses
with `readScheduleFormCarry`.
2026-05-26 15:58:28 +02:00
branding forge: auto-set agent-configs org avatar on core start (#424) 2026-05-26 00:10:52 +02:00
docs dashboard: inline edit form on schedule rows (closes #474) 2026-05-26 15:58:28 +02:00
frontend dashboard: inline edit form on schedule rows (closes #474) 2026-05-26 15:58:28 +02:00
hive-ag3nt scheduled prompts: fire-now operator + manager surfaces (closes #467) 2026-05-26 15:55:35 +02:00
hive-c0re scheduled prompts: fire-now operator + manager surfaces (closes #467) 2026-05-26 15:55:35 +02:00
hive-forge hive-forge: make --json a global flag (closes #421) 2026-05-26 15:55:59 +02:00
hive-sh4re scheduled prompts: fire-now operator + manager surfaces (closes #467) 2026-05-26 15:55:35 +02:00
nix hive-forge: rewrite bash CLI helper as a rust binary (closes #280) 2026-05-25 02:16:53 +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 hive-forge: rewrite bash CLI helper as a rust binary (closes #280) 2026-05-25 02:16:53 +02:00
Cargo.toml hive-forge: rewrite bash CLI helper as a rust binary (closes #280) 2026-05-25 02:16:53 +02:00
CLAUDE.md docs: fix scheduled_prompts.rs entry — auth logic is in manager_server.rs not scheduled_prompts.rs 2026-05-26 11:46:51 +02:00
flake.lock flake: update nixpkgs + nixpkgs-unstable 2026-05-17 22:52:08 +02:00
flake.nix forge: auto-set agent-configs org avatar on core start (#424) 2026-05-26 00:10:52 +02:00
README.md docs: add hyperhive.frontend.* options to README (follow-up to #350) 2026-05-23 15:03:51 +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 → :8000 / :8100-8999  per-agent web UIs
│   └── 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
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
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-25.11";
    hyperhive.url = "git+https://git.berlin.ccc.de/vinzenz/hyperhive";
  };

  outputs = { nixpkgs, hyperhive, ... }: {
    nixosConfigurations.my-host = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        hyperhive.nixosModules.default  # hive-c0re + hive-forge in one import
        ({ ... }: {
          services.hive-c0re.enable = true;
          # services.hive-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.

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.

See nix/templates/harness-base.nix for the full list of options and their descriptions.

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>