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