From ef4dd67e9a242a43abb055f4dc3454d0bbe56370 Mon Sep 17 00:00:00 2001 From: atlas Date: Sat, 4 Jul 2026 11:24:28 +0200 Subject: [PATCH] fix(#1747): stable hive-c0re ExecStart via /etc/hyperhive/serve.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, serveConfig was a pkgs.writeText store path embedded in ExecStart. Any repo edit (gateway.nix, frontend, unrelated nix modules) changes hyperhiveFlakeSource → serveConfig hash → ExecStart → systemd restarts hive-c0re → StartupSweep → every agent rebuilt unnecessarily. Fix: write the JSON to /etc/hyperhive/serve.json via environment.etc (a managed /etc symlink to the store-path content). ExecStart now references the stable /etc path, changing only when cfg.package (the hive-c0re binary) changes. Unrelated module edits no longer bounce c0re or trigger a cascade agent rebuild. hive-c0re still restarts — and triggers the sweep — when its binary changes, which is the correct invariant: a new release legitimately needs to resync all agents with updated harness modules. --- nix/modules/hive-c0re.nix | 52 ++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/nix/modules/hive-c0re.nix b/nix/modules/hive-c0re.nix index b8d3acb5..233cec1e 100644 --- a/nix/modules/hive-c0re.nix +++ b/nix/modules/hive-c0re.nix @@ -29,27 +29,30 @@ let directory = * ''; - # The `hive-c0re serve` config, written to the store as JSON and passed - # via a single `--config` flag so the systemd ExecStart line stays short - # instead of carrying every host-level setting as its own flag (the - # context-window + model-price maps alone were escaped JSON blobs on the - # command line). Keys are snake_case to match the `ServeConfig` serde - # shape the daemon deserialises (the container-injected HiveEnv fields, - # flattened, plus the hive-c0re-local model_prices table); per-flag - # overrides still work for ad-hoc invocations. - serveConfig = pkgs.writeText "hive-c0re-serve.json" ( - builtins.toJSON { - hyperhive_flake = cfg.hyperhiveFlake; - hyperhive_docs_flake = cfg.hyperhiveDocs; - nixpkgs_flake = cfg.nixpkgsFlake; - dashboard_port = cfg.dashboardPort; - operator_pronouns = cfg.operatorPronouns; - context_window_tokens = cfg.contextWindowTokens; - agent_cpu_quota = cfg.agentCpuQuota; - agent_memory_max = cfg.agentMemoryMax; - model_prices = cfg.modelPrices; - } - ); + # The `hive-c0re serve` config JSON. Keys are snake_case to match the + # `ServeConfig` serde shape the daemon deserialises (the + # container-injected HiveEnv fields, flattened, plus the hive-c0re-local + # model_prices table); per-flag overrides still work for ad-hoc + # invocations. + # + # Written to `/etc/hyperhive/serve.json` (managed by + # `environment.etc`) rather than embedded as a store-path argument in + # ExecStart. This keeps ExecStart byte-stable across deploys that only + # change hyperhive module files (gateway, frontend, unrelated nix + # modules) so systemd does NOT restart hive-c0re — and therefore does + # NOT trigger a startup sweep that rebuilds every agent — unless the + # c0re binary itself changes. + serveConfigJson = builtins.toJSON { + hyperhive_flake = cfg.hyperhiveFlake; + hyperhive_docs_flake = cfg.hyperhiveDocs; + nixpkgs_flake = cfg.nixpkgsFlake; + dashboard_port = cfg.dashboardPort; + operator_pronouns = cfg.operatorPronouns; + context_window_tokens = cfg.contextWindowTokens; + agent_cpu_quota = cfg.agentCpuQuota; + agent_memory_max = cfg.agentMemoryMax; + model_prices = cfg.modelPrices; + }; # Stylix theme integration (zero-op auto-detect). When the operator's # host config has stylix enabled, generate a base16 `colors.css` from @@ -776,6 +779,11 @@ in pkgs.git ]; + # Serve config at a stable /etc path so hive-c0re's ExecStart + # doesn't embed a volatile store-path argument. See serveConfigJson + # above for the rationale. + environment.etc."hyperhive/serve.json".text = serveConfigJson; + # Pull the per-container toplevels into the host system closure. # `system.extraDependencies` adds paths to the system build # without referencing them at runtime — nixos-rebuild fetches / @@ -1049,7 +1057,7 @@ in ); }; serviceConfig = { - ExecStart = "${cfg.package}/bin/hive-c0re --socket /run/hyperhive/host.sock serve --config ${serveConfig}"; + ExecStart = "${cfg.package}/bin/hive-c0re --socket /run/hyperhive/host.sock serve --config /etc/hyperhive/serve.json"; SyslogIdentifier = "hive-c0re"; # Migrate hive-c0re's *own* state to the service user after an # upgrade from a root-run install (systemd's StateDirectory only