refactor(c0re): pass hive-c0re serve config via a --config file, shrink ExecStart

The systemd ExecStart carried every host-level setting as its own flag —
nine of them, including two escaped JSON blobs (the context-window map and
the model-price table). Collapse them into a single `--config <file>` JSON.

- Reuse the existing HiveEnv as the container-injected config shape (add
  Deserialize + Default), and add a ServeConfig wrapper = flattened HiveEnv
  plus the hive-c0re-local model_prices table (kept out of HiveEnv since it
  is never injected into containers). serde(default) lets any field be
  omitted and fall back to its canonical default.
- clap: add --config; the per-setting flags become optional overrides
  (config file is the base, explicit flags win — preserves hivectl/debug
  ergonomics and bare `hive-c0re serve`).
- Coordinator::open and cmd_serve now take the bundled HiveEnv, which drops
  their too_many_arguments clippy allows. cmd_serve keeps a single
  too_many_lines allow (inherent daemon-boot orchestration, not arg-driven).
- nix: write the config as JSON to the store + pass --config, so ExecStart
  is one short line.
- Add a round-trip test proving the flatten + per-field defaults work.

Closes the ExecStart-length issue.
This commit is contained in:
atlas 2026-06-08 21:28:01 +02:00 committed by mara
commit 98660d134a
3 changed files with 223 additions and 120 deletions

View file

@ -28,6 +28,28 @@ let
[safe]
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;
nixpkgs_flake = cfg.nixpkgsFlake;
nixpkgs_unstable_flake = cfg.nixpkgsUnstableFlake;
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;
}
);
in
{
# The forge is part of the standard install — hive-c0re mirrors
@ -736,7 +758,7 @@ in
);
};
serviceConfig = {
ExecStart = "${cfg.package}/bin/hive-c0re --socket /run/hyperhive/host.sock serve --hyperhive-flake ${cfg.hyperhiveFlake} --nixpkgs-flake ${cfg.nixpkgsFlake} --nixpkgs-unstable-flake ${cfg.nixpkgsUnstableFlake} --dashboard-port ${toString cfg.dashboardPort} --operator-pronouns ${lib.escapeShellArg cfg.operatorPronouns} --context-window-tokens ${lib.escapeShellArg (builtins.toJSON cfg.contextWindowTokens)} --agent-cpu-quota ${lib.escapeShellArg cfg.agentCpuQuota} --agent-memory-max ${lib.escapeShellArg cfg.agentMemoryMax} --model-prices ${lib.escapeShellArg (builtins.toJSON cfg.modelPrices)}";
ExecStart = "${cfg.package}/bin/hive-c0re --socket /run/hyperhive/host.sock serve --config ${serveConfig}";
# Migrate hive-c0re's *own* state to the service user after an
# upgrade from a root-run install (systemd's StateDirectory only
# chowns the top-level dir, not pre-existing files inside it). The