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.5%
  • Nix 15.6%
  • JavaScript 7.1%
  • CSS 3.8%
  • TypeScript 3.5%
  • Other 1.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
iris 9ed58ab96d clippy: fix lints that crane's cargoClippy properly enforces (#538)
The naersk → crane swap in the parent commit flips clippy from
silently passing to actually failing on `-D warnings` (naersk's
`mode = "clippy"` mangled the `--` separator so the deny never took
effect). This commit clears the surfaced lints so the workspace
builds clean under the new enforcement — every fix is mechanical and
preserves behaviour. Tests still pass (160 across the workspace).

Auto-fixes via `cargo clippy --fix`:
- `doc_markdown` (19 sites): bare identifiers in doc comments
  wrapped in backticks
- `format_in_format_args`, `explicit_into_iter_loop`,
  `redundant_closure_for_method_calls`, `useless_conversion`, and
  a few more — mechanical rewrites of the kind cargo can apply
  safely.

Hand-fixed:
- `match_same_arms` (forge_notify::is_atx_heading): two arms returning
  `true` collapsed into a single `matches!` pattern.
- `cast_sign_loss` + `format_push_string` (mcp.rs status formatter):
  guarded `i64 → u64` through `u64::try_from(…).unwrap_or(0)` (status
  timestamps are always positive in practice; clamp the skew edge to
  0) and swapped `out.push_str(&format!(…))` for `write!` into the
  buffer with an infallible-writer `let _ =`.
- `doc_lazy_continuation` in turn.rs + manager_server.rs + sh4re/lib.rs:
  doc paragraphs that the markdown parser was treating as list-item
  continuations got either a separating blank line or a `/`-for-`+`
  word swap so the parser stops seeing a list.
- `unused_async` (manager_server::handle_request_schedule_prompt):
  function has no `.await`; dropped the `async` and its `.await` call
  site.
- `needless_pass_by_value` (scheduled_prompts::submit): take
  `&NewSchedule` instead of moving the struct in; updated two prod
  callers and eight test sites to pass references.
- `type_complexity` (approvals::mark_cancelled): hoisted the
  7-tuple SELECT row shape into a `type CancelLookupRow = (…);` alias.

Allow-with-reason for intentional patterns:
- `option_option` (6 sites across dashboard / scheduled_prompts /
  manager_server): `Option<Option<T>>` carries three-state PATCH
  semantics (missing key = leave alone, `Some(None)` = clear,
  `Some(Some(v))` = set). Collapsing to `Option<T>` loses the
  "clear" state.
- `dead_code` (rebuild_queue::QueueKind::Destroy /
  QueueSource::CrashRecover; topology::parent_of / default_seed):
  wire-shape variants + API surfaces kept for the upcoming features
  (#361 follow-ups, future `Destroy` queue routing, crash-recovery
  path). Allowed at the variant / function level with the rationale
  in `reason = "…"`.
- `too_many_lines` on three specific call-sites: a 117-line
  exhaustive-variant test (dashboard_events::kind_tag_matches_…),
  the meta-flake string template renderer
  (meta::render_flake_with_lookup), and the notification poll loop
  (forge_notify::poll_once) — splitting any of them would just hide
  the contiguous shape they exist to keep visible.

`nix flake check` formatting target is still broken on main itself
(pre-existing nixfmt drift across ~28 files unrelated to this PR);
left alone here so the scope stays "crane port + lints the port
exposed" and the operator's review doesn't have to triage drive-by
nixfmt churn.
2026-05-29 01:45:48 +02:00
branding forge: auto-set agent-configs org avatar on core start (#424) 2026-05-26 00:10:52 +02:00
docs docs: forge_notify.rs file map + wait_for_login mtime resumption (follow-up to #544 #545) 2026-05-29 00:34:11 +02:00
frontend tabs: logs flyout fills the side-panel height (closes #541) 2026-05-28 18:54:02 +02:00
hive-ag3nt clippy: fix lints that crane's cargoClippy properly enforces (#538) 2026-05-29 01:45:48 +02:00
hive-c0re clippy: fix lints that crane's cargoClippy properly enforces (#538) 2026-05-29 01:45:48 +02:00
hive-forge hive-forge: collapse autogenerated diffs to a single one-line summary (#222) 2026-05-29 01:16:51 +02:00
hive-sh4re clippy: fix lints that crane's cargoClippy properly enforces (#538) 2026-05-29 01:45:48 +02:00
nix hive-matrix: always use matrix.<domain> subdomain (mara on #552) 2026-05-29 01:31:40 +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 nix: add hive-matrix module + hyperhive.domain option (#548 part 1) 2026-05-29 01:25:29 +02:00
flake.lock flake: replace naersk with crane (#538) 2026-05-29 01:45:48 +02:00
flake.nix flake: replace naersk with crane (#538) 2026-05-29 01:45:48 +02:00
README.md docs: update README flake example to nixos-26.05 2026-05-27 22:12:32 +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-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 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.

Optional: set services.hive-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.

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>