- Rust 68.7%
- Nix 15.7%
- JavaScript 8.4%
- CSS 3.7%
- TypeScript 1.9%
- Other 1.6%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Fixes #2822. `swarm.js` had two independent per-agent "is this in flight" sources: `transientsState` (operator/worker-initiated ops the backend chose to flag) and `inFlightOpsByAgent()`, a separate derivation straight from `rebuildQueueState` covering everything else. Since #3010/#3016, `running_transients()` is a status-only test — any `Running` job-queue node naming a non-empty agent lights a transient pill, not just a curated subset — so the second source's Running-state handling is now provably redundant: a Running node with an agent always already has a transient by the time `queuedOpsByAgent()` (renamed from `inFlightOpsByAgent`) would be consulted. ## What changed - `transientsState`: `Map<name, {kind, since_unix}>` (one pill per agent) -> `Map<name, Map<kind, since_unix>>` (several pills per agent). `applyTransientSet`/`applyTransientCleared` now add/remove by `(name, kind)` rather than overwrite/delete by name alone, using `TransientCleared`'s `transient_kind` field (landed in #3016) to know which pill cleared. `syncTransientsFromSnapshot` groups the now-flat `TransientView` list by name instead of assuming one row per agent. - `inFlightOpsByAgent()` -> `queuedOpsByAgent()`: trimmed to the `Pending` (queued, not yet started) case only. The `Running` branch and its "running beats queued" priority logic are gone entirely — dead weight now that transients cover every running case unconditionally. - Render loop: an agent's transients win outright whenever any exist (rendered as **one badge per pill**, not collapsed into one label — mara: "show all running nodes that name the agent"); the queued fallback only applies when a agent has zero transients. `opRunning` simplifies to "does this agent have at least one transient". - `docs/web-ui/dashboard.md`'s Container-row section rewritten to match — it described a "transient, then in-flight-queue, in priority order" model that's no longer accurate now that the second source only ever fires for the one case the first can't represent. ## Verification `npm run build` clean for both packages (dashboard + agent). Standalone re-derivation of the transient-map + queued-fallback logic (`/tmp/verify-swarm-transients.mjs`, not part of this diff) run against constructed event sequences: single-pill lifecycle, two simultaneous pills on one agent with independent clear-by-kind, clearing an unknown kind is a safe no-op, a flat snapshot with duplicate agent names groups correctly, the queued fallback only fires when no transient exists and steps aside the instant one arrives, and a Running-state rebuild-queue entry produces no queued badge (confirming the Pending-only trim is correct, not just assumed). All 17 checks passed. Verified directly against the merged backend rather than trusting summaries: `job_queue/mod.rs::running_transients()` filters `State::Running` only (not Pending — an earlier note of mine claiming otherwise was imprecise paraphrasing), and `NodeView.agent` / `running_transients()`'s agent both resolve through the same `payload.agent()`, so a Running node's presence in `rebuild_queue` and its presence as a transient are guaranteed consistent, not just usually so. #2985 (DagView/NodeView deletion) unblocks once this merges — atlas is waiting on a ping. |
||
| .forgejo/workflows | ||
| branding | ||
| claude-plugins | ||
| docs | ||
| frontend | ||
| hive-agent | ||
| hive-agent-mcp | ||
| hive-agent-sock | ||
| hive-bash-mcp | ||
| hive-c0re | ||
| hive-core-agent-sock | ||
| hive-forge | ||
| hive-forge-notify | ||
| hive-host-sock | ||
| hive-jobq | ||
| hive-jobq-wire | ||
| hive-matrix-mcp | ||
| hive-metric | ||
| hive-priv | ||
| hive-priv-sock | ||
| hive-screen-mcp | ||
| hive-sh4re | ||
| hive-sock-client | ||
| hive-types | ||
| hivectl | ||
| nix | ||
| scripts | ||
| swagger-ui-theme | ||
| .gitignore | ||
| .mailmap | ||
| .prettierignore | ||
| .prettierrc | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CLAUDE.md | ||
| clippy.toml | ||
| flake.lock | ||
| flake.nix | ||
| README.md | ||
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 · → docs · → options reference
Depth lives in docs/ (rendered at
hyperhive.darkest.space/docs/) —
start at docs/README.md and pick the page matching
your task rather than reading front to back.
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.
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>