swarm-metrics reads the swarm's VictoriaMetrics from inside an agent
container: query, query-range, series, labels and label-values, each one
GET against the store's Prometheus read API through the gateway, printing
the store's JSON. It authenticates the way swarm-logs does, with the
agent's own queue secret read from bao under the agent's leaf, sent as
a swarm-agent bearer.
On the metrics store's host the read API's auth map gains an agent arm
ahead of the Grafana one. It routes to swarm-metrics-agent-auth, a
swarm-logs-auth instance logged in under the existing swarm-metrics-auth
leaf, whose bao grant now includes swarm/agents/+/queue read. The check is
rate-limited per address like the log store's
(deploy.victoriametrics.agentAuth{Rate,Burst,VerdictTtl}).
nix/agent-modules/metrics.nix installs the wrapped binary when the hive
forwards HIVE_AGENT_METRICS_URL (from swarm.victoriametrics.domain) and a
store address, the same gate as swarm-logs. Adds the base:swarm-metrics
skill and the CLI reference with its freshness check.
Fixes #5395
11 KiB
hyperhive — claude entry point
Hey claude. This is your starting page. The detailed docs live in
docs/ and are written for humans + you both — read them
when you need depth on a subsystem. This file is the index.
- High-level project intro: README.md.
- Open work + backlog: the forge issue tracker at
$HIVE_FORGE_URL/hyperhive/hyperhive/issues. Read the host out of the env var — inside an agent containerlocalhostis the agent, not the forge, so a hardcoded loopback address fails to connect. - Operator/agent trust-boundary design:
docs/trust-boundary/boundary.md (
area/opsissues for the deployment/gateway/privsep work — the separator is a slash, and--label area:opsnow fails withdid you mean "area/ops"?). - Agent trust model (trust boundary, prompt-injection threat model, capability = accepted risk), credential isolation + sandbox threat model: docs/trust-boundary/security.md.
- Odd-looking nspawn / container plumbing usually has a story: docs/process/gotchas.md.
Build & check
Always through the devshell — a bare cargo fails (failed to find tool "cc", cannot find -lsqlite3). Details:
docs/process/conventions.md.
nix develop -c cargo clippy --all-targets -- -D warnings
nix develop -c cargo test
nix fmt # treefmt is the CI gate, NOT bare cargo fmt
Changed a hivectl / swarmctl verb or flag? Regenerate its doc — only
CI's nix flake check catches the drift:
nix develop -c cargo run --bin hivectl -- markdown-docs > docs/tools/hivectl-cli.md
(same for swarmctl → docs/tools/swarmctl-cli.md). CI red but local
green → build the suspect check (e.g. nix build .#checks.x86_64-linux.hivectl-docs) before blaming the builder.
Repo map
One line per crate / top-level dir. Each module's authoritative,
always-current description lives in its own //! doc-comment —
grep/read the module when you need detail. This index is kept
deliberately lean: it auto-loads into every turn's context, and a
hand-maintained per-file tree drifts out of sync with the code.
Rust workspace (Cargo.toml members)
Per-hive (host + in-container):
hive-c0re/— host daemon (runs as the unprivilegedhive-coreuser), daemon-only — the operator CLI ishivectl. Owns the sqlite broker, reminder queue, meta flake, lifecycle (nixos-containershellouts), gateway wiring, per-container stats and the axum operator dashboard. Agent forge/matrix accounts areswarm-controller's. Largest crate.hivectl/— operator CLI; talks tohive-c0reover the host admin socket, does NOT link it. Verb reference (CI-enforced):docs/tools/hivectl-cli.md.hive-priv/— minimal root helper, socket-activated at/run/hive/priv.sock; the few root ops (bind-mount edits, nsenter)hive-c0redelegates. Seedocs/trust-boundary/boundary.md.hive-agent/— the in-container serve loop: turn-loop policy (turn.rs) overhive-runtime, per-agent web UI, event + turn-stats sinks, system-prompt renderer, claude launch config (mcp_config.rs). Withhive-agent-mcpit's what "hive-ag3nt" refers to — there is no such directory.hive-agent-mcp/— the embedded MCP server (hive-mcp-httpunit).hive-runtime/— theRuntimeinterface an agent's turns run on: aclaudebackend (overhive-claude) and anacpbackend whose stream is translated into claude'sstream-jsonshape. Links no hyperhive binary crate, so the subagent daemon uses it too.hive-bash-mcp/,hive-matrix-mcp/,hive-subagent-mcp/— per-agent MCP daemons serving streamable-http directly (no stdio bridge): background bash tasks, matrix-sdk tools, nested subagent sessions (optionally goal-driven over several turns; daemon state is in-memory, the claude session survives a restart).hive-screen-mcp/— stdio MCP bridge for GUI agents: screenshot, keyboard, mouse. All userspace.hive-forge/—hive-forgeForgejo CLI; one module per verb.hive-forge-notify/— notification pollers → todos on the in-agent socket. Two binaries:hive-forge-notify,hive-github-notify.hive-jobq/— the job-DAG scheduler library. Runtime-only — nothing writes the graph to disk, so node ids are stable within a run, not across restarts.hive-c0re'sjob_queue/is being removed in its favour — new scheduler-shaped code goes here.hive-jobq-wire/— presentation of ahive-jobqgraph to viewers (WireNode/WireResource); kept out ofhive-jobqon purpose.hive-jobq-metrics/— OTEL export of a graph's state rollup on a timer.hive-log/— the one log-sink chooser: journald or stdout, never both (under a unit, stdout already is the journal). Do not grow it into a utility crate.hive-metric/— one-shot CLI pushing a labeled metric over OTLP.
Wire types + socket plumbing:
hive-types/— leaf newtypes, chiefly the validatedIdent.hive-sh4re/— shared payload types (Message,HelperEvent, …).hive-host-sock/(hivectl ↔ c0re),hive-priv-sock/(c0re ↔ priv),hive-core-agent-sock/(harness ↔ c0re,/run/hive/mcp.sock) — per-socket wire types, split out so each client links only its protocol.hive-agent-sock/— the in-agent socket the harness serves to in-container producers (todos, reminders); also holds theextra_mcpspec. ⚠️ This socket never leaves the container —hive-c0reis not in the path, unlikehive-core-agent-sock.hive-sock-client/— the shared JSON-line unix-socket client; retry is a policy value (Retry::None/Retry::RideOutRestart). Also holds the bounded request-line reader (read_request_line) the socket servers use.
Swarm-level:
swarm-controller/— owns what is true across hives; opt-in, one per swarm. Serves HTTP over a unix socket nginx proxies to — ⚠️ the socket's directory is its access control; the crate README has the constraint and a unit test pins the path.swarmctl/— swarm operator CLI; runs as root and acts directly (README says why). Does not linkswarm-controller— its wire shapes are a local mirror. ⚠️ Edits authelia'susers.ymlin place, shared withswarm-authelia-bridge; that crate's README says what both writers must uphold. Verb reference (CI-enforced):docs/tools/swarmctl-cli.md.swarm-authelia-bridge/(+swarm-authelia-bridge-sock/wire types) — the other writer of authelia's users DB; runs insideswarm-authelia.swarm-secret-client/— OpenBao client overvaultrs. ⚠️ Reads theBAO_env spellings explicitly —vaultrs'sVAULT_*defaults are set by no unit here, and falling through to them yields a client with no identity and a TLS failure that names no cause.swarm-queue-client/— the one authenticated connect to the swarm NATS queue.swarm-nats-auth/— NATS auth-callout responder; without it the queue is fail-closed and admits nobody.swarm-agent-verify/— checks aswarm-agent.<agent>.<secret>token against the store; shared byswarm-nats-authandswarm-logs-auth.swarm-logs-auth/— nginxauth_requestresponder for agent access to the log store, and to the metrics store asswarm-metrics-agent-auth.swarm-metrics-auth/— nginxauth_requestresponder for Grafana's bearer on the metrics store's query API.swarm-logs/— agent CLI: a LogsQL query in, log lines out.swarm-metrics/— agent CLI: a MetricsQL query in, the store's JSON out.swarm-matrix-client/— appservice calls against the swarm homeserver, shared byswarm-controllerandswarm-matrix-ctl.swarm-matrix-ctl/— the one binary run insidecontainers.hive-matrix; new in-container jobs are verbs here, not crates.swarm-builder/— builds agent config PR heads for commit status. Design:docs/swarm/builder.md.swarm-ci-metrics/— polls the forge's Actions runs and pushes each finished run's duration and queue wait to the metrics store. Design:docs/swarm/ci-metrics.md.swarm-claude-login/— runsclaude auth loginfor one agent and stores the credentials atswarm/agents/<agent>/claude-credentials. Design:docs/swarm/claude-login.md.swarm-review-classifier/— oneclaude --printper PR classification, no tools, no forge credential. Design:docs/swarm/review-classifier.md.
External dependencies with no directory here
hive-claude— app-agnostic driver for headlessclaude --print(stream-json,Telemetry, the self-compactingInfiniteSession). ⚠️ Its own repo, not a workspace member — there is nohive-claude/directory andgrephere will not find it.
Other top-level dirs
frontend/— npm workspaces built hermetically bynix/packages/frontend.nix:shared,dashboard(operator SPA),agent(per-container UI),swarm-ui(Preact; packaged separately bynix/packages/swarm-ui.nix, not inpackages.default's closure).nix/—host-modules/(the host stack),agent-modules/(per-agent harness features),container-modules/(guest side of service containers),templates/agent.nix(the container entry point),packages/,docs/(options doc),module-eval/(NixOS module-eval tests),builder/(check-flake),script-tests/, plussources.nix/rust.nix/checks.nix/devshell.nix/treefmt.nixbehind the thinflake.nix.docs/— subsystem reference docs (see Reading paths below).branding/,scripts/— static assets + helper scripts.
Reading paths
docs/README.md is the single index, grouped by
topic. Don't add a second copy of it here — a parallel list used to live
in this file and drifted.
Conventions & process
- Never add
#[allow(clippy::…)]— fix the lint instead (extract a helper, add backticks, etc.). Worked examples:docs/process/conventions.md. - Pre-push lint hook (catches tracker-tag and comment-block failures
before CI does — install once per clone):
ln -sf ../../scripts/pre-push .git/hooks/pre-push - Comment/PR-description length: size it to how non-obvious the
thing is, not to how much investigation it took to find it — a
mechanical fix gets a one-line comment, a genuinely non-obvious
invariant or decision earns real prose. Don't restate a module's
//!doc in a comment further down the same file. - Operator-facing doc with real implementation detail mixed in: wrap
the implementation part in a
<details><summary>…</summary>block (blank line after<summary>so the markdown inside renders) rather than a sibling page — seedocs/integrations/github.md's "Implementation" section. It only collapses in a rendered browser, and the<summary>line isn't markdown-processed, so keep it plain prose with no backticks.