319 lines
13 KiB
Nix
319 lines
13 KiB
Nix
# Option declarations for `services.hyperhive.c0re.*` — the c0re
|
|
# daemon's knobs plus the package/source options the flake's
|
|
# `nixosModules.default` wires to its own outputs (they carry no
|
|
# in-module defaults; see ../../../flake.nix). The read-only
|
|
# `servedFrontend` option lives in ./theme.nix with the stylix wiring
|
|
# that computes it.
|
|
{
|
|
pkgs,
|
|
lib,
|
|
config,
|
|
...
|
|
}:
|
|
{
|
|
options.services.hyperhive.c0re = {
|
|
enable = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = config.services.hyperhive.enable;
|
|
defaultText = lib.literalExpression "config.services.hyperhive.enable";
|
|
description = "Enable hive-c0re coordinator daemon (auto-enabled by services.hyperhive.enable).";
|
|
};
|
|
package = lib.mkOption {
|
|
type = lib.types.package;
|
|
defaultText = lib.literalExpression "hyperhive.packages.\${system}.default";
|
|
description = ''
|
|
hyperhive workspace package. Provides `/bin/hive-c0re`
|
|
(coordinator daemon + admin-socket CLI) and `/bin/hivectl`
|
|
(operator-facing host CLI for ad-hoc administration). Wired to
|
|
this flake's `packages.<system>.default` by
|
|
`nixosModules.default` (via `lib.mkDefault`, so setting it here
|
|
wins).
|
|
'';
|
|
};
|
|
frontend = lib.mkOption {
|
|
type = lib.types.package;
|
|
defaultText = lib.literalExpression "hyperhive.packages.\${system}.frontend";
|
|
description = ''
|
|
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.
|
|
'';
|
|
};
|
|
assets = lib.mkOption {
|
|
type = lib.types.package;
|
|
defaultText = lib.literalExpression "hyperhive.packages.\${system}.assets";
|
|
description = ''
|
|
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.
|
|
'';
|
|
};
|
|
xdgIcons = lib.mkOption {
|
|
type = lib.types.package;
|
|
defaultText = lib.literalExpression "hyperhive.packages.\${system}.xdg-icons";
|
|
description = ''
|
|
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.
|
|
'';
|
|
};
|
|
hyperhiveFlake = lib.mkOption {
|
|
type = lib.types.str;
|
|
defaultText = lib.literalMD "the hyperhive flake's own filtered source store path";
|
|
description = ''
|
|
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.
|
|
'';
|
|
};
|
|
hyperhiveDocs = lib.mkOption {
|
|
type = lib.types.str;
|
|
defaultText = lib.literalMD "the docs/ tree's own store path";
|
|
description = ''
|
|
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.
|
|
'';
|
|
};
|
|
agentBaseToplevel = lib.mkOption {
|
|
type = lib.types.package;
|
|
defaultText = lib.literalExpression "hyperhive.packages.x86_64-linux.agent-base-toplevel";
|
|
description = ''
|
|
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.
|
|
'';
|
|
};
|
|
managerToplevel = lib.mkOption {
|
|
type = lib.types.package;
|
|
defaultText = lib.literalExpression "hyperhive.packages.x86_64-linux.ruth-toplevel";
|
|
description = ''
|
|
Pre-built manager (ruth) container system closure — see
|
|
`agentBaseToplevel`.
|
|
'';
|
|
};
|
|
nixpkgsFlake = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "path:${pkgs.path}";
|
|
defaultText = lib.literalMD "`\"path:\${pkgs.path}\"`";
|
|
description = ''
|
|
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.
|
|
'';
|
|
};
|
|
dashboardPort = lib.mkOption {
|
|
type = lib.types.port;
|
|
default = 7000;
|
|
description = "TCP port the hive-c0re dashboard listens on.";
|
|
};
|
|
operatorPronouns = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "she/her";
|
|
example = "they/them";
|
|
description = ''
|
|
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.
|
|
'';
|
|
};
|
|
preBuildAgentTemplates = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = false;
|
|
example = true;
|
|
description = ''
|
|
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.
|
|
'';
|
|
};
|
|
contextWindowTokens = lib.mkOption {
|
|
type = lib.types.attrsOf lib.types.int;
|
|
default = {
|
|
haiku = 200000;
|
|
sonnet = 1000000;
|
|
opus = 1000000;
|
|
};
|
|
example = {
|
|
haiku = 150000;
|
|
sonnet = 900000;
|
|
};
|
|
description = ''
|
|
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.
|
|
'';
|
|
};
|
|
|
|
modelPrices = lib.mkOption {
|
|
type = lib.types.attrsOf (
|
|
lib.types.submodule {
|
|
options = {
|
|
input = lib.mkOption {
|
|
type = lib.types.numbers.nonnegative;
|
|
description = "USD per million input tokens.";
|
|
};
|
|
output = lib.mkOption {
|
|
type = lib.types.numbers.nonnegative;
|
|
description = "USD per million output tokens.";
|
|
};
|
|
cache_read = lib.mkOption {
|
|
type = lib.types.numbers.nonnegative;
|
|
description = "USD per million cache-read tokens.";
|
|
};
|
|
cache_write = lib.mkOption {
|
|
type = lib.types.numbers.nonnegative;
|
|
description = "USD per million cache-creation (write) tokens.";
|
|
};
|
|
};
|
|
}
|
|
);
|
|
# Current Anthropic list prices for the Claude 4.x family (Opus
|
|
# 4.x, Sonnet 4.x, Haiku 4.5); cache_write is the 1-hour cache-TTL
|
|
# price (the default through the Claude subscription the agents run
|
|
# on). Keep in sync with `builtin_prices` in
|
|
# hive-c0re/src/hive_stats.rs.
|
|
default = {
|
|
opus = {
|
|
input = 5.0;
|
|
output = 25.0;
|
|
cache_read = 0.5;
|
|
cache_write = 10.0;
|
|
};
|
|
sonnet = {
|
|
input = 3.0;
|
|
output = 15.0;
|
|
cache_read = 0.3;
|
|
cache_write = 6.0;
|
|
};
|
|
haiku = {
|
|
input = 1.0;
|
|
output = 5.0;
|
|
cache_read = 0.1;
|
|
cache_write = 2.0;
|
|
};
|
|
};
|
|
example = {
|
|
sonnet = {
|
|
input = 3.0;
|
|
output = 15.0;
|
|
cache_read = 0.3;
|
|
cache_write = 6.0;
|
|
};
|
|
};
|
|
description = ''
|
|
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.
|
|
'';
|
|
};
|
|
|
|
agentCpuQuota = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "200%";
|
|
example = "400%";
|
|
description = ''
|
|
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`).
|
|
'';
|
|
};
|
|
|
|
agentMemoryMax = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "4G";
|
|
example = "8G";
|
|
description = ''
|
|
systemd `MemoryMax=` applied to every agent container via the
|
|
same drop-in as `agentCpuQuota`.
|
|
'';
|
|
};
|
|
|
|
buildSlots = lib.mkOption {
|
|
type = lib.types.ints.positive;
|
|
default = 1;
|
|
example = 2;
|
|
description = ''
|
|
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.
|
|
'';
|
|
};
|
|
};
|
|
}
|