hyperhive — host options
services.hyperhive.enable
Whether to enable hyperhive — the agent swarm coordinator.
Type: boolean
Default:
false
Example:
true
Declared by:
services.hyperhive.c0re.enable
Enable hive-c0re coordinator daemon (auto-enabled by services.hyperhive.enable).
Type: boolean
Default:
config.services.hyperhive.enable
Declared by:
services.hyperhive.c0re.package
hyperhive workspace package. Provides /bin/hive-c0re
(coordinator daemon) and /bin/hivectl (operator-facing host
CLI for ad-hoc administration + the host admin socket). Wired to
this flake’s packages.<system>.default by
nixosModules.default (via lib.mkDefault, so setting it here
wins).
Type: package
Default:
hyperhive.packages.${system}.default
Declared by:
services.hyperhive.c0re.adminUsers
Login users granted sudoless hivectl. Each is added to the
hive-admin group, which group-owns the host admin socket
(/run/hyperhive/host.sock, mode 0660) — so listed users drive
hivectl (and thus the whole hive) without sudo.
This is a real privilege grant: the admin socket is full hive
control — spawn / kill / destroy / deploy — see docs/trust-boundary/boundary.md.
Keep the list to trusted operators. Empty (the default) keeps the
socket root-only, as before.
Type: list of string
Default:
[ ]
Example:
[
"alice"
]
Declared by:
services.hyperhive.c0re.agentBaseToplevel
Pre-built agent-base container system closure, pulled into the
host system closure when preBuildAgentTemplates is on. Wired
by nixosModules.default; only evaluated when that option is
enabled.
Type: package
Default:
hyperhive.packages.x86_64-linux.agent-base-toplevel
Declared by:
services.hyperhive.c0re.agentCpuQuota
systemd CPUQuota= applied to every agent container via a
container@h-<name>.service.d/ drop-in written on each
spawn/rebuild. Expressed as a percentage of one CPU core —
"200%" allows each agent to use up to 2 cores. Bump this if
agents are hitting CPU limits during builds or heavy tool use.
For a hive-wide cap across all containers, set
systemd.slices.machine.serviceConfig.CPUQuota in your NixOS
config (all nspawn containers live in machine.slice).
Type: string
Default:
"200%"
Example:
"400%"
Declared by:
services.hyperhive.c0re.agentCpuWeight
systemd CPUWeight= applied to every agent container via the
same drop-in as agentCpuQuota. This is the cgroup v2
cpu.weight relative share, not a cap: a low-weight
container still gets the whole machine when nothing else wants
it, and the weight only decides who yields under contention.
That makes it the complement of agentCpuQuota, which throttles
even on an idle host.
The kernel default is 100. The hyperhive default of 80 means
agent containers yield slightly to everything that is not on
this drop-in path — host services and the infrastructure
containers (hive-ci, hive-forge, hive-gateway,
hive-matrix), which stay at 100. Note this is a hive-wide
value, so it does not rank agents against each other: they all
share one weight.
Set to null to leave CPUWeight= out of the drop-in entirely —
the container then inherits the kernel default and the generated
unit file is identical to one from before this option existed.
Type: null or integer between 1 and 10000 (both inclusive)
Default:
80
Example:
null
Declared by:
services.hyperhive.c0re.agentIoWeight
systemd IOWeight= applied to every agent container via the
same drop-in as agentCpuQuota — the block-IO counterpart of
agentCpuWeight, with the same relative-share, contention-only
semantics.
Caveat: IOWeight= maps to the cgroup v2 io.weight knob, which
is only honoured when the io.cost (blk-iocost) controller is
enabled for the backing device, or when the device uses the BFQ
scheduler. On a host running none/mq-deadline/kyber without
iocost QoS configured, systemd writes the value and the kernel
ignores it — harmless, but it will measure as a no-op. Check with
cat /sys/fs/cgroup/io.cost.qos on the host, and set this to
null to omit the setting rather than write one nothing reads.
Type: null or integer between 1 and 10000 (both inclusive)
Default:
80
Example:
null
Declared by:
services.hyperhive.c0re.agentMemoryMax
systemd MemoryMax= applied to every agent container via the
same drop-in as agentCpuQuota.
Type: string
Default:
"4G"
Example:
"8G"
Declared by:
services.hyperhive.c0re.assets
Bundled static runtime assets (see nix/packages/assets.nix): the
project’s branding family + the claude system-prompt template +
claude-settings JSON. Output has share/hyperhive/{branding,prompts}/;
passed to hive-c0re’s systemd unit via HIVE_ASSETS_DIR
(hive_sh4re::assets::* resolve paths underneath). Override to
ship customised branding or prompts without rebuilding the
rust derivation.
Type: package
Default:
hyperhive.packages.${system}.assets
Declared by:
services.hyperhive.c0re.buildSlots
Number of nix-heavy job-queue nodes (container prebuilds, profile swaps, first-spawn creates, meta lock bumps) hive-c0re runs concurrently. The default of 1 serializes all heavy nix work; raise it on hosts with the cores/RAM to build several agent toplevels at once. Per-agent correctness is independent of this count — each agent’s container-affecting operations are serialized by its lifecycle lease regardless.
Type: positive integer, meaning >0
Default:
1
Example:
2
Declared by:
services.hyperhive.c0re.claudeCodePackage
The claude-code build every agent runs, or null (the
default) to leave each agent on the claude-code from its own
nixpkgs — i.e. whatever nixpkgsFlake resolves to.
This is the one binary the whole hive is built around, and it
moves fast enough that a release channel routinely trails
unstable by weeks on it. An agent cannot fix that for itself:
agents evaluate against the single nixpkgs hive-c0re injects,
so an agent.nix has no other tree to reach for. Set this from
a second nixpkgs in the host flake and every agent follows,
without moving the nixpkgs the rest of the container is built
from.
What travels into the container is the store path, not the
derivation: agents share the host’s /nix/store, so the binary
and its full closure are already reachable there — nothing
needs rebuilding or copying. hive-c0re writes the path into
each agent’s generated flake as a plain string literal (a bare
path fed to lib.types.package would run builtins.storePath,
which is illegal under pure evaluation) and the agent module
puts its bin/ on the harness’s PATH.
The flip side of a plain string is that nothing in the agent’s
own closure refers to it, so the container cannot keep it
alive. The host does that instead: this package is
interpolated into /etc/hyperhive/serve.json, which puts it in
the host’s system closure — so it is gc-rooted by the running
generation for exactly as long as that generation is the one
the agents were rendered from. The cost is that
nix-collect-garbage cannot reclaim an old claude-code until
every agent has been rebuilt past it and the old generations
are gone.
Type: null or package
Default:
null
Example:
inputs.nixpkgs-unstable.legacyPackages.x86_64-linux.claude-code
Declared by:
services.hyperhive.c0re.contextWindowTokens
Per-model context-window sizes in tokens. Each key is a
model-family short name matched case-insensitively as a
substring of the active model name at runtime (e.g. "sonnet"
matches "claude-sonnet-4-5"). The defaults cover the known
Anthropic families; add entries for new models or override
existing ones here to change the window for all agents at once.
Passed to hive-c0re serve as JSON and injected into every
container’s harness service environment as
HIVE_CONTEXT_WINDOW_TOKENS_<KEY_UPPER>. Changes propagate
on the next ↻ R3BU1LD — no per-agent approval needed.
Type: attribute set of signed integer
Default:
{
haiku = 200000;
opus = 1000000;
sonnet = 1000000;
}
Example:
{
haiku = 150000;
sonnet = 900000;
}
Declared by:
services.hyperhive.c0re.dashboardPort
TCP port the hive-c0re dashboard listens on.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
7000
Declared by:
services.hyperhive.c0re.frontend
Bundled frontend dist (see nix/packages/frontend.nix). Output
has dashboard/ and agent/ subdirectories — hive-c0re serves
dashboard/ via tower_http::ServeDir from the path passed
in HIVE_STATIC_DIR. Override to ship a custom dashboard SPA;
the JSON contract (/api/state, the SSE streams, the action
endpoints) is the source of truth for any replacement.
Type: package
Default:
hyperhive.packages.${system}.frontend
Declared by:
services.hyperhive.c0re.hyperhiveDocs
URL of the narrow docs/ source (no fragment). Inlined into the
generated meta flake.nix at inputs.hyperhive-docs.url and
threaded to each agent as hyperhive.docs.source, from which the
harness resolves $HIVE_DOCS_DIR. Its own store path — separate
from hyperhiveFlake — so a doc edit only re-locks this input
instead of rebuilding every agent container.
Type: string
Default: the docs/ tree’s own store path
Declared by:
services.hyperhive.c0re.hyperhiveFlake
URL of the hyperhive flake (no fragment). Inlined into each
per-agent flake.nix at inputs.hyperhive.url. The per-agent
flake then pulls hyperhive.nixosConfigurations.agent-base to
build the container. Wired by nixosModules.default to this
flake’s own filtered source — only override if you want agents
tracking a different ref.
Type: string
Default: the hyperhive flake’s own filtered source store path
Declared by:
services.hyperhive.c0re.managerToplevel
Pre-built manager (ruth) container system closure — see
agentBaseToplevel.
Type: package
Default:
hyperhive.packages.x86_64-linux.ruth-toplevel
Declared by:
services.hyperhive.c0re.modelPrices
Per-model USD prices (per million tokens) used for the
hive-wide cost estimate on the dashboard’s ST4TS tab. Each key
is a model-family short name matched case-insensitively as a
substring of the active model id at runtime (e.g. "sonnet"
matches "claude-sonnet-4-5"); the longest matching key wins, so
a specific entry beats a generic family name. Any model not
covered by this table falls back to hive-c0re’s built-in
estimate.
The defaults track Anthropic list pricing at the time of
writing — override them here to keep the estimate current
without a code change. Passed to hive-c0re serve as JSON via
--model-prices; read only by hive-c0re itself (not injected
into containers). Changes apply on the next host rebuild.
Type: attribute set of (submodule)
Default:
{
haiku = {
cache_read = 0.1;
cache_write = 2.0;
input = 1.0;
output = 5.0;
};
opus = {
cache_read = 0.5;
cache_write = 10.0;
input = 5.0;
output = 25.0;
};
sonnet = {
cache_read = 0.3;
cache_write = 6.0;
input = 3.0;
output = 15.0;
};
}
Example:
{
sonnet = {
cache_read = 0.3;
cache_write = 6.0;
input = 3.0;
output = 15.0;
};
}
Declared by:
services.hyperhive.c0re.modelPrices.<name>.cache_read
USD per million cache-read tokens.
Type: nonnegative integer or floating point number, meaning >=0
Declared by:
services.hyperhive.c0re.modelPrices.<name>.cache_write
USD per million cache-creation (write) tokens.
Type: nonnegative integer or floating point number, meaning >=0
Declared by:
services.hyperhive.c0re.modelPrices.<name>.input
USD per million input tokens.
Type: nonnegative integer or floating point number, meaning >=0
Declared by:
services.hyperhive.c0re.modelPrices.<name>.output
USD per million output tokens.
Type: nonnegative integer or floating point number, meaning >=0
Declared by:
services.hyperhive.c0re.nixpkgsFlake
Store-path URL for the nixpkgs input in the generated meta
flake. The meta flake declares this as a top-level input and
wires inputs.hyperhive.inputs.nixpkgs.follows = "nixpkgs" so
every agent container evaluates with this exact nixpkgs.
Defaults to "path:${pkgs.path}" — the store path of the
nixpkgs the host NixOS module was evaluated with. When the
operator sets inputs.hyperhive.inputs.nixpkgs.follows = "nixpkgs" in their host flake, pkgs.path resolves to the
host’s own nixpkgs, so agents transparently track the same
channel as the host.
Override to pin agents to a specific nixpkgs version regardless of the host’s channel.
Type: string
Default:
"path:${pkgs.path}"
Declared by:
services.hyperhive.c0re.operatorPronouns
Operator pronouns, free text. Threaded into every agent
container as the HIVE_OPERATOR_PRONOUNS env var; the
harness substitutes it into the agent / manager system
prompt at boot so claude refers to the operator naturally
in third person (“ask her”, “tell them”, etc.). Changes
propagate to running agents on the next ↻ R3BU1LD —
forwards as a meta flake env-var bump, no per-agent
approval needed.
Type: string
Default:
"she/her"
Example:
"they/them"
Declared by:
services.hyperhive.c0re.orgAvatarPng
PNG uploaded once as the agent-configs Forgejo org’s avatar
(forge::users::ensure_config_org_avatar, one-shot,
marker-guarded — delete forge/agent-configs-avatar-set under
the state dir to force a re-upload after changing this).
Defaults (null) to the bundled agent-configs.png from
assets. Set this to override just the org avatar without
replacing the whole assets package.
Type: null or absolute path
Default:
null
Declared by:
services.hyperhive.c0re.preBuildAgentTemplates
Pre-fetch the per-container system closures (agent-base + manager toplevels) into the host’s /nix/store as part of this host’s NixOS build, instead of letting the first agent spawn do all the work.
Enabling this adds roughly the full nixpkgs runtime closure +
claude-code + the harness binary to your system closure size
(low single-digit GB), but the first nixos-container start
for any agent then completes in seconds instead of minutes
because nothing’s left to fetch.
Off by default because the toplevels are pinned to
x86_64-linux (nixos-containers run native arch). Enabling
on an aarch64 host would force nix to build the x86 closure
via cross or a remote builder, which is rarely what you want.
Flip to true on an x86_64 host when you care more about
first-spawn latency than host store size — or just
nix build .#agent-base-toplevel once manually to warm the
store.
Type: boolean
Default:
false
Example:
true
Declared by:
services.hyperhive.c0re.xdgIcons
XDG icon set + .desktop entries for hyperhive processes (see
nix/packages/hive-xdg-icons.nix), installed into the host
system packages so desktop environments can match hyperhive
processes to their icon.
Type: package
Default:
hyperhive.packages.${system}.xdg-icons
Declared by:
services.hyperhive.domain
Canonical host domain for hyperhive subsystems that need a
stable name (currently: services.hyperhive.swarm.matrix.serverName
derives from this, defaulting to
matrix.${services.hyperhive.domain} when serverName is
null). Required when services.hyperhive.enable — eval fails
with a helpful message if it’s unset (it’s baked into matrix on
first boot and drives the gateway/forge/agent URLs, with no safe
default; changing it later is destructive). Exposed to agents as
HYPERHIVE_HIVE_DOMAIN; consumed by
hive-agent::identity::hive_domain() for <name>@<domain>
qualified labels.
Deprecated as a place to write. It is read from this hive’s
own entry in services.hyperhive.swarm.hives, whose domain
defaults to <hiveName>.<swarm.domain> — so a conventional hive
states nothing at all, and a non-conventional one states its
address in the directory every other hive reads. Setting it here
still wins and still works, with a warning: the directory is
shared, this option is not, so a value written only here is
invisible to the rest of the swarm.
Type: null or string
Default:
services.hyperhive.swarm.hives.${hiveName}.domain, or null when there is no entry for this hive
Example:
"darkest.space"
Declared by:
services.hyperhive.gateway.auth.enable
Whether to enable HTTP basic auth on the gateway using an htpasswd file. When
enabled, every request to the gateway’s main vhost requires a
valid username and password. nginx’s built-in auth_basic
module validates credentials against
/var/lib/hive-gateway/conf/gateway.htpasswd. Off by default.
Manage users with hivectl gateway create-user, delete-user,
and list-users — see hivectl gateway --help for usage.
The htpasswd file is created automatically when auth is enabled;
add at least one user before enabling to avoid locking everyone out.
.
Type: boolean
Default:
false
Example:
true
Declared by:
services.hyperhive.gateway.auth.realm
HTTP Basic auth realm value sent in the WWW-Authenticate
header when credentials are absent or rejected. Must not
contain " or $ (nginx string metacharacters).
Type: string matching the pattern [^"$]*
Default:
"hyperhive"
Example:
"my-hive"
Declared by:
services.hyperhive.gateway.hsts.enable
Add Strict-Transport-Security to all gateway vhosts.
Disabled by default: HSTS pins HTTPS in the browser’s HSTS preload list; enabling it on a deployment that later loses TLS will lock browsers out until the max-age expires. Only enable this when you are certain TLS is permanent.
The gateway always terminates TLS (self-signed floor), so HSTS is always served over https when enabled — but mind the warning above: HSTS pins https in the browser, so only enable it when TLS is permanent for this deployment.
Type: boolean
Default:
false
Declared by:
services.hyperhive.gateway.hsts.includeSubDomains
Whether to include includeSubDomains in the HSTS header.
Only disable this if the gateway host has sub-domains that
intentionally serve plain HTTP.
Type: boolean
Default:
true
Declared by:
services.hyperhive.gateway.hsts.maxAge
Value for the max-age directive in seconds.
Default: 31536000 (1 year), which is the value required for
HSTS preload list submission. Use a shorter value (e.g. 86400)
while testing so browsers forget the pin quickly.
Type: positive integer, meaning >0
Default:
31536000
Example:
86400
Declared by:
services.hyperhive.gateway.httpsPort
TCP port for the TLS-terminated vhosts. Default 443. The gateway
always terminates TLS (self-signed is the implicit floor when no
tls.certDir / ACME is configured), so this port is always active
alongside the plain-http port.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
443
Example:
8443
Declared by:
services.hyperhive.gateway.localHostsEntry
Add an /etc/hosts entry mapping services.hyperhive.domain
to 127.0.0.1 on the host. Useful for local deployments +
tests where there’s no real DNS for services.hyperhive.domain
but the operator (or browser-based tests) want to hit
http://${services.hyperhive.domain} to exercise the
gateway shape. Off by default — operators running with real
DNS shouldn’t have a stale /etc/hosts entry sticking
around. Requires services.hyperhive.domain to be set.
services.hyperhive.deploy.singleHostSwarm turns this on as
part of saying “this box is the whole deployment”: that mode
means there is no real DNS for these names and the operator is
browsing them from the host itself. Set it here explicitly to
override in either direction.
Type: boolean
Default:
false
Example:
true
Declared by:
services.hyperhive.gateway.openFirewall
Open port in the host firewall. Off by default (secure-by-default).
Flip to true to expose the gateway to
the operator’s browser / external clients — required for any
out-of-host reach, since the agents themselves talk to
hive-c0re via the per-agent unix sockets and don’t need the
nginx vhost. Leave off when running behind another reverse
proxy (e.g. caddy / traefik on the host) that handles TLS
termination + forwards to port.
Note: this used to default to true. Add
services.hyperhive.gateway.openFirewall = true; to your host
config if external reach stopped working after a recent upgrade.
Type: boolean
Default:
false
Example:
true
Declared by:
services.hyperhive.gateway.port
TCP port the gateway listens on. Default 80 (canonical web port). nginx runs on the host as root, so it can bind <1024; if 80 is already taken on the host (existing nginx, traefik, etc.) override to an unused port like 8080 or move the conflicting service.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
80
Example:
8080
Declared by:
services.hyperhive.gateway.swaggerUiTheme
Full Swagger UI static dist, hyperhive-themed (see
nix/packages/swagger-ui-theme.nix, built on
nix/packages/swagger-ui-dist.nix). The gateway serves this
whole tree directly at /api/docs/ — hive-c0re hosts none of
it, only the dynamic /api/openapi.json route (proxied
through, unaffected by this option). Override to ship a
custom theme (or the plain vendored dist) without a gateway
rebuild.
Type: package
Default:
hyperhive.packages.${system}.swagger-ui-theme
Declared by:
services.hyperhive.gateway.tls.acme.enable
Let the gateway’s nginx obtain and renew TLS certificates
automatically via ACME (Let’s Encrypt). When enabled, each
vhost calls out to Let’s Encrypt using the HTTP-01
challenge on port (default 80) and stores certs in the
gateway’s persistent state dir on the host.
Requirements:
services.hyperhive.domainmust be set and publicly DNS-resolvable to this host.services.hyperhive.gateway.openFirewall = trueso Let’s Encrypt can reach/.well-known/acme-challenge/.tls.acme.emailmust be set (ACME account contact).
Mutual exclusion: tls.certDir set together with
tls.acme.enable = true fails at eval — pick one TLS source.
Typical setup:
services.hyperhive.gateway = {
openFirewall = true;
tls.acme = {
enable = true;
email = "admin@example.com";
};
};
Type: boolean
Default:
false
Example:
true
Declared by:
services.hyperhive.gateway.tls.acme.email
Email address for the ACME account registration with
Let’s Encrypt. Required when tls.acme.enable = true.
Let’s Encrypt sends expiry warnings to this address.
Type: null or string
Default:
null
Example:
"admin@example.com"
Declared by:
services.hyperhive.gateway.tls.certDir
Path to a host directory containing a TLS certificate and
private key for nginx. When set, nginx listens on httpsPort
and uses this cert, overriding the self-signed default — the
auto-generated hive-CA-signed leaf is skipped entirely.
nginx reads <certDir>/<tls.certName> and
<certDir>/<tls.keyName> directly — it runs on the host, so
the directory needs no bind mount and no copy.
Default filenames (cert.pem / key.pem) match the output
layout of nixpkgs’s security.acme module.
Typical ACME setup:
security.acme.certs."example.com" = { ... };
services.hyperhive.gateway.tls.certDir =
config.security.acme.certs."example.com".directory;
Mutual exclusion with tls.acme.enable — set one or the other,
not both.
Type: null or absolute path
Default:
null
Example:
"/var/lib/acme/example.com"
Declared by:
services.hyperhive.gateway.tls.certName
Filename of the TLS certificate within tls.certDir. Defaults
to cert.pem which matches nixpkgs’s security.acme output.
Type: string
Default:
"cert.pem"
Declared by:
services.hyperhive.gateway.tls.keyName
Filename of the TLS private key within tls.certDir. Defaults
to key.pem which matches nixpkgs’s security.acme output.
Type: string
Default:
"key.pem"
Declared by:
services.hyperhive.gateway.upstreamHost
Host the gateway proxies non-static requests to. Defaults to
127.0.0.1 because nginx runs on the host itself, so loopback
resolves directly to hive-c0re.
Type: string
Default:
"127.0.0.1"
Declared by:
services.hyperhive.gateway.upstreamPort
TCP port the gateway proxies non-static requests to. Defaults
to 7000 (hive-c0re’s out-of-the-box dashboard port). Operators
who change services.hyperhive.c0re.dashboardPort should set
upstreamPort to match — kept as a hardcoded default rather
than a cross-reference to keep this module’s options eval
independent of c0re’s option tree shape.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
7000
Declared by:
services.hyperhive.github.enable
Hive-wide switch for the per-agent GitHub integration (the gh CLI
wrapper + git credential helper, per hyperhive.github.enable). On by
default: every agent gets the integration, inert until a PAT is
provisioned via the dashboard credentials tab or hivectl github set-token. Set false to turn it off for the whole hive — the
meta-flake renderer (hive-c0re/src/meta.rs) then injects
hyperhive.github.enable = false into every agent. Exposed to hive-c0re
as HYPERHIVE_GITHUB_DISABLED (set only when the integration is off).
Type: boolean
Default:
true
Example:
false
Declared by:
services.hyperhive.hiveName
Human-readable name of this single-host hive instance.
Required when services.hyperhive.enable. Distinct from
services.hyperhive.domain (the machine-addressable DNS name)
but no longer merely cosmetic: a hive occupies
<hiveName>.<swarm.domain>, so this is the label the hive is
addressed by as well as the one it is called. Exposed to
agents as HYPERHIVE_HIVE_NAME; surfaced in the dashboard
chrome and per-agent system prompt.
Type: null or string
Default:
null
Example:
"pr1ma"
Declared by:
services.hyperhive.network.bridgeIp
IPv4 address assigned to the bridge interface on the host
side. Agents use this address as their DNS server (the hive’s
dnsmasq binds here). Default 10.42.0.1
is in RFC 1918 space and unlikely to clash with operator’s
existing setup; override if a different range is already in
use.
Type: string
Default:
"10.42.0.1"
Example:
"172.30.0.1"
Declared by:
services.hyperhive.network.bridgeName
Name of the host-side bridge interface the hive uses for
inter-container traffic. Kept short so it survives the
IFNAMSIZ (15-char) cap, and prefixed so it’s obviously
hive-managed in ip link output.
Type: string
Default:
"hive-br0"
Example:
"h0"
Declared by:
services.hyperhive.network.bridgePrefixLength
Netmask prefix length for the bridge subnet. Default /24
gives 254 usable per-agent addresses, enough for any
single-host hive. Operator with a larger swarm or a tighter
addressing scheme overrides.
Type: signed integer
Default:
24
Example:
16
Declared by:
services.hyperhive.network.exposeHostPorts
TCP ports on the host that agent containers may reach at the bridge
IP (bridgeIp). Each listed port P is opened on the bridge-interface
firewall, so an agent can connect to ${bridgeIp}:P (default
10.42.0.1:P).
Use this to let agents reach a host-local service you run yourself —
a database, a scratch HTTP endpoint, anything listening on
${bridgeIp}:P.
The host service must bind an address reachable from the bridge —
0.0.0.0 or the bridge IP (bridgeIp) — not loopback-only. The
bridge→127.0.0.0/8 DROP rule (defence-in-depth) is unchanged: this
only opens the firewall, it does not bridge loopback. A service that
binds 127.0.0.1 only is still unreachable; rebind it to 0.0.0.0.
The exposed port is reachable by EVERY agent on the bridge subnet (same as DNS/gateway), so only expose services safe for any agent to reach.
Type: list of 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
[ ]
Example:
[
5432
]
Declared by:
services.hyperhive.otel.enable
Whether to enable hive-wide export of every agent’s Claude Code stats (token usage, cost, tool calls) to an OTLP endpoint via Claude Code’s built-in OpenTelemetry. One switch for all agents.
Enabling this also runs this hive’s collector on the host: there is exactly one way telemetry leaves this hive, and it is through that collector. Agents export unauthenticated to a bridge address only their own containers can reach.
That collector forwards to the swarm’s
(services.hyperhive.deploy.swarm-otel.enable), which holds the
upstream credential and writes the swarm’s store. So an agent never
sees the credential, and neither does this tier.
⚠️ The collector is therefore in the path of all telemetry. It runs on the same host as the agents and restarts on failure, and telemetry is not the control plane, so degraded telemetry is not degraded operation — but the export no longer survives independently of anything host-side .
Type: boolean
Default:
false
Example:
true
Declared by:
services.hyperhive.otel.clientSecretFile
Absolute path to this hive’s OAuth2 client secret, used to authenticate to the swarm’s collector as this hive.
Whether this is set is what decides whether this tier authenticates at all. A credential is the only thing that makes authenticated egress possible, so its presence is the condition rather than a second switch that could disagree with it.
Defaults to the secret this host’s own authelia minted, which is
correct exactly when the swarm’s IdP runs here. On a hive that is
not that host, the file has to arrive some other way and this
option names wherever it landed — the same manual-copy shape
services.hyperhive.swarm.authelia.oidc.hiveIdentities documents,
where delivering a secret to a hive that is not this host is
deliberately not solved.
Read by LoadCredential, so it is never evaluated by nix, never
copied into the store and never passed in argv.
Type: null or string
Default:
"${deploy.authelia.hostClientSecretDir}/${swarm.authelia.hiveClientPrefix}${hiveName}.secret" when this host runs the swarm's IdP, else null
Example:
"/var/lib/secrets/hive-telemetry.secret"
Declared by:
services.hyperhive.otel.collector.port
Port the collector’s OTLP/HTTP receiver listens on, at
services.hyperhive.network.bridgeIp. 4318 is the OTLP/HTTP
default.
The port is contributed to
services.hyperhive.network.exposeHostPorts, which opens it on
the bridge interface only — so it is reachable from agent
containers and not from the outside world.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
4318
Declared by:
services.hyperhive.otel.collector.upstreamHeaderName
Name of the HTTP header the collector sends upstream, whose
value comes from headersCredential.
The name is here and the value is not, and that split is forced
rather than chosen: the collector models exporter headers as a
static map, so rendering them means nix reading the value — the
one thing headersCredential being a path exists to prevent.
A name is public, a value is not.
⇒ exactly one header is expressible this way. A credential
carrying several (a=1,b=2) would be read as a single value,
which is why the shape is a named header rather than an opaque
blob: a second header has to be declared, not smuggled.
Type: string
Default:
"Authorization"
Declared by:
services.hyperhive.otel.debug
Emit OTEL SDK diagnostic messages to every agent’s stderr by
setting CLAUDE_CODE_OTEL_DIAG_STDERR=1. Useful when
troubleshooting collector connectivity or endpoint config;
leave off in normal operation to avoid noise in agent logs.
Only meaningful when enable is true.
Type: boolean
Default:
false
Declared by:
services.hyperhive.otel.endpoint
Upstream OTLP endpoint: where telemetry ultimately goes, after it has left the swarm.
Read by the swarm’s collector
(services.hyperhive.deploy.swarm-otel.enable), which is the only
tier that holds the upstream credential. An agent is handed the
first hop instead — this hive’s own collector — so this value is
never given to a container.
Optional. Leave it empty and the swarm’s own metrics store
(services.hyperhive.deploy.victoriametrics.enable) is the
destination; that is a complete deployment, not a degraded one.
Set both and telemetry goes to both.
Type: string
Default:
""
Example:
"https://collector.example.com/otel"
Declared by:
services.hyperhive.otel.extraResourceAttributes
Extra comma-separated entries appended to
OTEL_RESOURCE_ATTRIBUTES after the built-in
service.name / agent / hive / swarm labels.
Type: string
Default:
""
Example:
"deployment.environment=prod"
Declared by:
services.hyperhive.otel.headersCredential
Absolute path to an operator-provided secret file holding the
upstream auth header as NAME=value (e.g.
Authorization=Bearer <token>).
Only the swarm’s collector reads this — the one tier that
talks to the upstream. It arrives as an EnvironmentFile, so the
value is never read by nix, never copied into the store or the
generated config, and never passed in argv; and it reaches
neither an agent container nor this hive’s own collector, which
is the point of the tiers existing. Must be absolute.
Leave null if the upstream needs no auth header; the collector then sends none rather than an empty one.
Type: null or string
Default:
null
Example:
"/run/secrets/otel-headers"
Declared by:
services.hyperhive.otel.metricIntervalMs
Metric export interval in milliseconds, set as
OTEL_METRIC_EXPORT_INTERVAL for every agent. Claude Code’s
default is 60000 (60s). Leave null to use that default.
Each agent runs claude as a short-lived per-turn process; claude force-flushes metrics on shutdown, so this is not required for metrics to be exported, but a lower value gives more frequent intermediate flushes within long turns. Cosmetic, not a correctness knob.
Type: null or (positive integer, meaning >0)
Default:
null
Example:
10000
Declared by:
services.hyperhive.otel.protocol
OTLP wire protocol for the upstream link, honoured by the swarm collector’s exporter.
Not what agents speak: their first hop is this hive’s collector,
whose OTLP/HTTP receiver takes protobuf whatever the upstream
wants (see hive-c0re/environment.nix).
Type: one of “http/protobuf”, “http/json”, “grpc”
Default:
"http/protobuf"
Declared by:
services.hyperhive.otel.scrapeTargets
Prometheus exposition endpoints this hive’s collector scrapes, as
<job name> = "<host>:<port>".
A service declares its own entry, from its own module, under its
own enable — the same rule as the swarm tier’s option of the
same name, and for the same reason: an entry exists only where the
service that named it runs, so the scraper and its target are
co-located by construction rather than by luck.
⚠️ This tier, not the swarm one, is where a HIVE-owned target
belongs. The two are not interchangeable: a swarm service does
not belong to a hive, so its samples must never acquire a hive
label — which is why that scraper lives one tier up. Putting a
hive-owned target there would either mislabel it or leave it
unattributed.
Scraping is unauthenticated on purpose. This receiver is a prometheus-to-OTLP converter sitting next to what it reads, in the same trust position as the agents already pushing to this collector; the authenticated hop is the collector’s own export onward, which is one hop for the whole hive rather than one per target.
Empty by default, and that is the shipped case — no scrape
receiver is emitted at all, because a prometheus receiver with
nothing to scrape is a config that renders, starts and collects
nothing.
Type: attribute set of string
Default:
{ }
Example:
{ hive-forge = "127.0.0.1:3000"; }
Declared by:
services.hyperhive.ruthless
Run this hive “ruthless” — with no root (manager) agent at all (no
ruth). When true, hive-c0re skips the root-agent auto-management
sweep entirely (it otherwise creates the root agent’s container when
missing and restarts it when present but stopped). Defaults to
false (the root agent is auto-managed as required
infrastructure). Exposed to hive-c0re as HYPERHIVE_RUTHLESS.
Type: boolean
Default:
false
Example:
true
Declared by:
services.hyperhive.snapshotStore.enable
Run the swarm snapshot store on this host: a btrfs receive
endpoint that hives push agent snapshots to over the WireGuard
mesh. Off by default — it is a distinct deployment role, not
part of a hive.
Requires services.hyperhive.deploy.wireguard.enable: the mesh
is both the transport and the authentication, so there is no
meaningful configuration without it.
Type: boolean
Default:
false
Declared by:
services.hyperhive.snapshotStore.path
Root of the snapshot tree. Must be on a btrfs filesystem —
btrfs receive fails otherwise. One subvolume directory per
agent is created beneath it, so an agent’s incremental chain
stays contiguous across a migration between hives.
Type: absolute path
Default:
"/var/lib/hyperhive-snapshots"
Declared by:
services.hyperhive.snapshotStore.port
TCP port the receiver listens on. Bound to this host’s WireGuard mesh address only — never a wildcard — so it is reachable exactly by mesh peers and by nothing else.
Type: 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
51821
Declared by: