hyperhive/nix/modules/hive-c0re.nix
müde 49f4e9cc89 dashboard: forge-linked config + approval card + 3-way diff base
- forge nix option moves to hyperhive.forge.enable, defaults true;
  hive-c0re imports the forge module so it's on by default.
- drop the agent.nix container-row viewer + /api/agent-config; link
  to the agent-configs forge repo instead.
- restructure pending approvals into a card (identity header /
  what-changed body / decision actions) with a link to the proposal
  commit on the forge.
- diff opens in the side panel with a 3-way base toggle: vs applied
  (running) / vs last-approved / vs previous proposal, served by the
  new /api/approval-diff/{id}?base= endpoint.
2026-05-20 11:22:28 +02:00

102 lines
3.3 KiB
Nix

{
hyperhivePackage,
hyperhiveFlake,
}:
{
pkgs,
lib,
config,
...
}:
let
cfg = config.services.hive-c0re;
in
{
# The forge is part of the standard install — hive-c0re mirrors
# every agent's applied config repo into it. On by default; opt out
# with `hyperhive.forge.enable = false`.
imports = [ ./hive-forge.nix ];
options.services.hive-c0re = {
enable = lib.mkEnableOption "hive-c0re hyperhive coordinator daemon";
package = lib.mkOption {
type = lib.types.package;
default = hyperhivePackage pkgs.stdenv.hostPlatform.system;
defaultText = lib.literalExpression "hyperhive.packages.\${system}.default";
description = "Package that provides /bin/hive-c0re.";
};
hyperhiveFlake = lib.mkOption {
type = lib.types.str;
default = hyperhiveFlake;
defaultText = lib.literalMD "the flake's own 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. Defaults to this flake's own store path
only override if you want agents tracking a different ref.
'';
};
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.
'';
};
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [
cfg.package
pkgs.git
];
# Dashboard + per-container web UIs share the host's network namespace and
# need their ports reachable. Dashboard: `cfg.dashboardPort` (default 7000).
# Manager: 8000. Sub-agents: 8100..8999 (deterministic hash; see
# `lifecycle::agent_web_port`).
networking.firewall.allowedTCPPorts = [
cfg.dashboardPort
8000
];
networking.firewall.allowedTCPPortRanges = [
{
from = 8100;
to = 8999;
}
];
systemd.services.hive-c0re = {
description = "hyperhive coordinator daemon";
wantedBy = [ "multi-user.target" ];
path = [
pkgs.git
"/run/current-system/sw"
];
environment.HYPERHIVE_GIT = "${pkgs.git}/bin/git";
serviceConfig = {
ExecStart = "${cfg.package}/bin/hive-c0re --socket /run/hyperhive/host.sock serve --hyperhive-flake ${cfg.hyperhiveFlake} --dashboard-port ${toString cfg.dashboardPort} --operator-pronouns ${lib.escapeShellArg cfg.operatorPronouns}";
Restart = "on-failure";
RestartSec = 2;
RuntimeDirectory = "hyperhive";
RuntimeDirectoryMode = "0750";
RuntimeDirectoryPreserve = "yes";
StateDirectory = "hyperhive";
};
};
};
}