nix: move the agent option namespace under services.hyperhive.agent
Every per-agent harness option lived at the top-level `hyperhive.*` while the host tier has always been `services.hyperhive.*`. Move all 52 agent-tier option leaves (33 top-level names across 16 modules) to `services.hyperhive.agent.*`, repoint every read, and keep existing agent configs evaluating through one `mkRenamedOptionModule` per old leaf path in the new nix/agent-modules/renamed-options.nix. The shims are per leaf rather than per namespace: `user`, `mcp`, `otel`, `queue`, `docs`, `forge`, `frontend`, `github`, `gui`, `logs`, `matrix` and `cargo` are plain attrsets of declarations, not submodule-typed options, so a parent-path rename would not reach their children. Three read-only options (`frontend.mergedDist`, `queue.clientIdFile`, `queue.clientSecretFile`) deliberately get no shim — a rename contributes a definition, which a read-only option refuses; the exclusions are commented in place. Refs #4473
This commit is contained in:
parent
60393d0e32
commit
3662eda440
21 changed files with 531 additions and 290 deletions
|
|
@ -10,13 +10,13 @@
|
|||
...
|
||||
}:
|
||||
let
|
||||
userName = config.hyperhive.user.name;
|
||||
userName = config.services.hyperhive.agent.user.name;
|
||||
# This container's own effective `MemoryMax=` in bytes, baked in per
|
||||
# agent by meta.rs's flake render — see
|
||||
# `hyperhive.claudeMemoryMaxBytes` in ./claude-settings.nix. `null`
|
||||
# `services.hyperhive.agent.claudeMemoryMaxBytes` in ./claude-settings.nix. `null`
|
||||
# when the cap is `infinity` or a RAM percentage, i.e. when the module
|
||||
# has no byte count to size anything against.
|
||||
containerMemoryMaxBytes = config.hyperhive.claudeMemoryMaxBytes;
|
||||
containerMemoryMaxBytes = config.services.hyperhive.agent.claudeMemoryMaxBytes;
|
||||
# Two thirds of the container's cap, as the soft ceiling on everything
|
||||
# the subagent daemon runs. The daemon spawns nested `claude` sessions
|
||||
# as plain children, so its cgroup already *is* the "all subagents"
|
||||
|
|
@ -32,7 +32,7 @@ let
|
|||
subagentMemoryHigh = containerMemoryMaxBytes * 2 / 3;
|
||||
in
|
||||
{
|
||||
options.hyperhive.allowedRecipients = lib.mkOption {
|
||||
options.services.hyperhive.agent.allowedRecipients = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
example = [
|
||||
|
|
@ -58,7 +58,7 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
options.hyperhive.extraMcpServers = lib.mkOption {
|
||||
options.services.hyperhive.agent.extraMcpServers = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule {
|
||||
options = {
|
||||
|
|
@ -173,14 +173,14 @@ in
|
|||
whatever brought the new agent.nix into deployed/*).
|
||||
|
||||
The `bash` entry above is illustrative only — it's auto-injected
|
||||
below (`hyperhive.extraMcpServers.bash` via `lib.mkDefault`) already
|
||||
tracking `hyperhive.mcp.bashHttpPort`, so overriding it directly
|
||||
below (`services.hyperhive.agent.extraMcpServers.bash` via `lib.mkDefault`) already
|
||||
tracking `services.hyperhive.agent.mcp.bashHttpPort`, so overriding it directly
|
||||
with a hardcoded port (as shown) is unusual and will drift if
|
||||
`bashHttpPort` is changed separately; bump `bashHttpPort` instead.
|
||||
'';
|
||||
};
|
||||
|
||||
options.hyperhive.mcp.httpPort = lib.mkOption {
|
||||
options.services.hyperhive.agent.mcp.httpPort = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 8790;
|
||||
example = 8791;
|
||||
|
|
@ -197,7 +197,7 @@ in
|
|||
`initialize`/`tools-list` completed, stranding the agent with `No
|
||||
such tool` — the http endpoint eliminates that). `matrix` stays a
|
||||
stdio bridge; `bash` runs its own persistent http listener (see
|
||||
`hyperhive.mcp.bashHttpPort`).
|
||||
`services.hyperhive.agent.mcp.bashHttpPort`).
|
||||
|
||||
Bound loopback-only; the rmcp streamable-http transport's default
|
||||
`allowed_hosts` (`localhost` / `127.0.0.1` / `::1`) rejects Host
|
||||
|
|
@ -220,24 +220,24 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
options.hyperhive.mcp.bashHttpPort = lib.mkOption {
|
||||
options.services.hyperhive.agent.mcp.bashHttpPort = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 8791;
|
||||
example = 8792;
|
||||
description = ''
|
||||
Loopback port `hive-bash-daemon` serves its MCP tools
|
||||
(`run`/`status`/`kill`) on. Same shape as `hyperhive.mcp.httpPort`
|
||||
(`run`/`status`/`kill`) on. Same shape as `services.hyperhive.agent.mcp.httpPort`
|
||||
for the built-in surface: HTTP is the *sole* transport (no stdio
|
||||
bridge — the daemon that owns the subprocess runner serves the MCP
|
||||
tools directly in-process), `Restart = "always"` keeps the listener
|
||||
self-healing, and loopback-only binding means no auth token is
|
||||
needed (same `allowed_hosts` reasoning as `hyperhive.mcp.httpPort`).
|
||||
needed (same `allowed_hosts` reasoning as `services.hyperhive.agent.mcp.httpPort`).
|
||||
Safe as a single fixed default across all agents (private
|
||||
per-container network namespace — see docs/networking/network.md).
|
||||
'';
|
||||
};
|
||||
|
||||
options.hyperhive.mcp.subagentHttpPort = lib.mkOption {
|
||||
options.services.hyperhive.agent.mcp.subagentHttpPort = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 8793;
|
||||
example = 8794;
|
||||
|
|
@ -247,7 +247,7 @@ in
|
|||
`hive-subagent-mcp`) — a subagent spawns a full nested `claude`
|
||||
process, a much heavier capability than a bash command, worth its own
|
||||
deployable/restartable unit. Same shape/reasoning as
|
||||
`hyperhive.mcp.bashHttpPort` otherwise: sole transport, self-healing
|
||||
`services.hyperhive.agent.mcp.bashHttpPort` otherwise: sole transport, self-healing
|
||||
restart, loopback-only so no auth token is needed. Shipped default-on
|
||||
for every agent today, same as `bash` — expected to become a real
|
||||
opt-in capability gate later, not yet.
|
||||
|
|
@ -263,22 +263,22 @@ in
|
|||
assertions =
|
||||
lib.mapAttrsToList (name: spec: {
|
||||
assertion = spec.type != "stdio" || spec.command != null;
|
||||
message = "hyperhive.extraMcpServers.${name}: type = \"stdio\" requires `command` to be set";
|
||||
}) config.hyperhive.extraMcpServers
|
||||
message = "services.hyperhive.agent.extraMcpServers.${name}: type = \"stdio\" requires `command` to be set";
|
||||
}) config.services.hyperhive.agent.extraMcpServers
|
||||
++ lib.mapAttrsToList (name: spec: {
|
||||
assertion = spec.type != "http" || spec.url != null;
|
||||
message = "hyperhive.extraMcpServers.${name}: type = \"http\" requires `url` to be set";
|
||||
}) config.hyperhive.extraMcpServers;
|
||||
message = "services.hyperhive.agent.extraMcpServers.${name}: type = \"http\" requires `url` to be set";
|
||||
}) config.services.hyperhive.agent.extraMcpServers;
|
||||
|
||||
# Auto-inject the built-in bash MCP server — always present, every
|
||||
# agent needs bash tools. `lib.mkDefault` so the operator's own
|
||||
# agent.nix can override the entry. (The matrix sibling lives in
|
||||
# ./matrix.nix, gated on hyperhive.matrix.enable.) `hive-bash-daemon`
|
||||
# ./matrix.nix, gated on services.hyperhive.agent.matrix.enable.) `hive-bash-daemon`
|
||||
# serves its MCP tools directly over streamable-http (no stdio bridge,
|
||||
# no round-trip socket) — see the `hive-bash-daemon` service below.
|
||||
hyperhive.extraMcpServers.bash = lib.mkDefault {
|
||||
services.hyperhive.agent.extraMcpServers.bash = lib.mkDefault {
|
||||
type = "http";
|
||||
url = "http://127.0.0.1:${toString config.hyperhive.mcp.bashHttpPort}/mcp";
|
||||
url = "http://127.0.0.1:${toString config.services.hyperhive.agent.mcp.bashHttpPort}/mcp";
|
||||
allowedTools = [ "*" ];
|
||||
};
|
||||
|
||||
|
|
@ -287,21 +287,22 @@ in
|
|||
# later" — not gated behind an enable option yet, unlike `matrix.nix`'s
|
||||
# pattern). `lib.mkDefault` so an agent.nix can still override/disable
|
||||
# the entry in the meantime.
|
||||
hyperhive.extraMcpServers.subagent = lib.mkDefault {
|
||||
services.hyperhive.agent.extraMcpServers.subagent = lib.mkDefault {
|
||||
type = "http";
|
||||
url = "http://127.0.0.1:${toString config.hyperhive.mcp.subagentHttpPort}/mcp";
|
||||
url = "http://127.0.0.1:${toString config.services.hyperhive.agent.mcp.subagentHttpPort}/mcp";
|
||||
allowedTools = [ "*" ];
|
||||
};
|
||||
|
||||
environment.etc."hyperhive/extra-mcp.json".text = builtins.toJSON config.hyperhive.extraMcpServers;
|
||||
environment.etc."hyperhive/extra-mcp.json".text =
|
||||
builtins.toJSON config.services.hyperhive.agent.extraMcpServers;
|
||||
|
||||
environment.etc."hyperhive/send-allow.json".text =
|
||||
builtins.toJSON config.hyperhive.allowedRecipients;
|
||||
builtins.toJSON config.services.hyperhive.agent.allowedRecipients;
|
||||
|
||||
# Bash task runner daemon — long-running process that owns subprocess
|
||||
# monitoring + completion wake signals, and serves the MCP tools
|
||||
# (`run`/`status`/`kill`) directly over streamable-http on
|
||||
# `hyperhive.mcp.bashHttpPort` — no stdio bridge, no per-turn spawn.
|
||||
# `services.hyperhive.agent.mcp.bashHttpPort` — no stdio bridge, no per-turn spawn.
|
||||
systemd.services.hive-bash-daemon = {
|
||||
description = "bash task runner + MCP daemon for hive-bash";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
|
@ -334,7 +335,7 @@ in
|
|||
# deriving a fallback, since every service here always gets it.
|
||||
};
|
||||
serviceConfig = {
|
||||
ExecStart = "${config.hyperhive.packages.hive-bash-daemon}/bin/hive-bash-daemon --http 127.0.0.1:${toString config.hyperhive.mcp.bashHttpPort}";
|
||||
ExecStart = "${config.services.hyperhive.agent.packages.hive-bash-daemon}/bin/hive-bash-daemon --http 127.0.0.1:${toString config.services.hyperhive.agent.mcp.bashHttpPort}";
|
||||
SyslogIdentifier = "hive-bash-daemon";
|
||||
# `always` (not `on-failure`): since the MCP tools are served
|
||||
# in-process now, a down window is total loss of bash tools with
|
||||
|
|
@ -349,7 +350,7 @@ in
|
|||
# Subagent task runner daemon — independent of `hive-bash-daemon` (own
|
||||
# crate, own process): spawns nested claude sessions on request, serves
|
||||
# the `start`/`continue`/`status`/`interrupt` MCP tools directly over
|
||||
# streamable-http on `hyperhive.mcp.subagentHttpPort`. The same port also
|
||||
# streamable-http on `services.hyperhive.agent.mcp.subagentHttpPort`. The same port also
|
||||
# serves a second, subagent-facing route (`/signal/mcp/<token>`:
|
||||
# `goal_reached`/`need_help`) — not something an agent's own config points
|
||||
# at: the daemon mints each subagent it spawns its own token and writes
|
||||
|
|
@ -388,7 +389,7 @@ in
|
|||
# `null` when the agent has no groups declared, which systemd drops
|
||||
# — the same "absent" the harness itself would see.
|
||||
HIVE_TOOL_GROUPS = config.systemd.services.hive-agent.environment.HIVE_TOOL_GROUPS or null;
|
||||
# Same `hyperhive.availableModels` the harness's own assertions gate
|
||||
# Same `services.hyperhive.agent.availableModels` the harness's own assertions gate
|
||||
# the primary session's model against, so a subagent can't be spawned
|
||||
# on a model the operator didn't make available to this agent. The
|
||||
# option renders into the *global* environment for the web UI's
|
||||
|
|
@ -398,16 +399,16 @@ in
|
|||
# a safety rail, not a security boundary), matching the harness
|
||||
# assertion that an empty list waives too.
|
||||
HIVE_AVAILABLE_MODELS =
|
||||
if config.hyperhive.availableModels == [ ] then
|
||||
if config.services.hyperhive.agent.availableModels == [ ] then
|
||||
null
|
||||
else
|
||||
lib.concatStringsSep "," config.hyperhive.availableModels;
|
||||
lib.concatStringsSep "," config.services.hyperhive.agent.availableModels;
|
||||
# HYPERHIVE_HARNESS_DIR / HYPERHIVE_STATE_DIR: see
|
||||
# `hive-bash-daemon`'s own comment above — same global injection,
|
||||
# same reasoning.
|
||||
};
|
||||
serviceConfig = {
|
||||
ExecStart = "${config.hyperhive.packages.hive-subagent-daemon}/bin/hive-subagent-daemon --http 127.0.0.1:${toString config.hyperhive.mcp.subagentHttpPort}";
|
||||
ExecStart = "${config.services.hyperhive.agent.packages.hive-subagent-daemon}/bin/hive-subagent-daemon --http 127.0.0.1:${toString config.services.hyperhive.agent.mcp.subagentHttpPort}";
|
||||
SyslogIdentifier = "hive-subagent-daemon";
|
||||
# `always`, same reasoning as `hive-bash-daemon`: the MCP tools are
|
||||
# served in-process, so a down window is total loss of
|
||||
|
|
@ -463,7 +464,7 @@ in
|
|||
# with the static loose-ends from hive-c0re.
|
||||
environment.HIVE_AGENT_SOCKET = "/run/hive-agent/${userName}/agent.sock";
|
||||
serviceConfig = {
|
||||
ExecStart = "${config.hyperhive.packages.hive-agent-mcp}/bin/hive-agent-mcp --http 127.0.0.1:${toString config.hyperhive.mcp.httpPort}";
|
||||
ExecStart = "${config.services.hyperhive.agent.packages.hive-agent-mcp}/bin/hive-agent-mcp --http 127.0.0.1:${toString config.services.hyperhive.agent.mcp.httpPort}";
|
||||
SyslogIdentifier = "hive-mcp-http";
|
||||
# `always` (not `on-failure`): this endpoint is load-bearing — the
|
||||
# sole hyperhive-MCP transport, so a down window is total
|
||||
|
|
|
|||
Loading…
Reference in a new issue