diff --git a/nix/templates/harness-base.nix b/nix/templates/harness-base.nix index fbc5c9d7..cc4b0bbb 100644 --- a/nix/templates/harness-base.nix +++ b/nix/templates/harness-base.nix @@ -75,31 +75,6 @@ in ''; }; - options.hyperhive.role = lib.mkOption { - type = lib.types.enum [ - "agent" - "manager" - ]; - default = "agent"; - example = "manager"; - description = '' - Whether this container runs as a sub-agent (`"agent"`, the - default — invokes `hive-ag3nt serve`) or as the swarm's - manager (`"manager"` — invokes `hive-m1nd serve` and - defaults the forge notification surface to mentions-only). - - meta.rs flips this to `"manager"` for the manager container - and leaves it at the default for every sub-agent. Agents - and `agent.nix` files don't normally touch this option; - it's exposed so a standalone `nixos-rebuild` against - `nixosConfigurations.manager` keeps working without the - meta-flake wrapper around it. - - Closes #671: harness + manager templates merged into a - single `harness-base.nix` driven by this option. - ''; - }; - options.hyperhive.model = lib.mkOption { type = lib.types.str; default = "haiku"; @@ -1216,106 +1191,6 @@ in }; }; - # Manager-only forge defaults (#671): skip the - # subscription/participation firehose so the manager's inbox - # only carries direct mentions, reviews, and assignments. Sub- - # agents keep the noisier defaults (`keepSubscriptions = true`, - # `skipNotifyReasons = [ ]`). `mkDefault` so any agent that - # wants to invert it can. - hyperhive.forge = lib.mkIf (config.hyperhive.role == "manager") { - keepSubscriptions = lib.mkDefault false; - skipNotifyReasons = lib.mkDefault [ - "subscribed" - "participating" - ]; - }; - - # Harness systemd unit. Role-driven so the same `harness-base.nix` - # covers both `nixosConfigurations.agent-base` (`hive-ag3nt serve`) - # and `nixosConfigurations.manager` (`hive-m1nd serve`) without a - # second template file (#671). Per-agent HIVE_PORT / HIVE_LABEL - # come from the meta-flake's generated `applied//flake.nix`; - # the manager has hardcoded fallbacks here so `nixosConfigurations.manager` - # still builds standalone. - systemd.services.${if config.hyperhive.role == "manager" then "hive-m1nd" else "hive-ag3nt"} = - let - isManager = config.hyperhive.role == "manager"; - binary = if isManager then "hive-m1nd" else "hive-ag3nt"; - in - { - description = "${binary}${lib.optionalString isManager " manager"} harness"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - # systemd units get a minimal PATH by default and don't inherit - # `environment.systemPackages`. Pointing at `/run/current-system/sw` - # gives the harness (and any tools claude shells out to via Bash) - # access to everything declared in `systemPackages` — including - # anything an agent adds to its own `agent.nix` — without having - # to touch the service definition. - # - # `/run/wrappers/bin` prepended so the `security.wrappers` - # setuid shims (notably `sudo`) resolve before the bare - # nix-store binaries in `/run/current-system/sw/bin`. - # Post-#658 the harness runs as the per-agent user — without - # the wrapper dir on PATH, `sudo` resolves to the un-setuid - # nix-store binary and refuses with "must be owned by uid 0 - # and have the setuid bit set" even when - # `hyperhive.user.passwordlessSudo = true` is configured - # (#672 fixup pulled forward into this PR to avoid the - # regression argus flagged on #676). - path = [ - "/run/wrappers/bin" - "/run/current-system/sw" - ]; - environment = { - SHELL = "${pkgs.bashInteractive}/bin/bash"; - # `HOME` defaults to `/` for systemd services without a User= - # set. With #658 the harness runs as the agent user — set HOME - # explicitly so claude (which the harness spawns) finds its - # `~/.claude/` session dir at the bind-mounted location. - HOME = homeDir; - # Path to the merged agent static dist. The harness serves this - # via `tower_http::ServeDir` for any request it doesn't route to - # an API endpoint. `mergedDist` is the agent-default dist with - # `hyperhive.frontend.extraFiles` layered on top. - HIVE_STATIC_DIR = "${config.hyperhive.frontend.mergedDist}"; - # Static runtime assets (branding + claude prompts). Set on the - # unit directly — `environment.variables` only populates - # /etc/profile, which systemd services don't inherit. - HIVE_ASSETS_DIR = "${pkgs.hyperhive-assets}/share/hyperhive"; - } - // lib.optionalAttrs isManager { - # Standalone-eval fallbacks for `nixosConfigurations.manager`. - # meta.rs overrides both via the per-agent generated - # `applied/hm1nd/flake.nix` (see `lifecycle::setup_applied`); - # the values here keep the container sensible if anyone - # evaluates the standalone config. - HIVE_PORT = "8000"; - HIVE_LABEL = "hm1nd"; - }; - serviceConfig = { - ExecStart = "${pkgs.hyperhive}/bin/${binary} serve"; - Restart = "on-failure"; - RestartSec = 2; - # `/run/hive-config/` is a per-service runtime dir owned by - # the agent user (`User=` below), auto-cleared by systemd on - # stop. The harness writes its regenerated - # claude-{mcp-config,settings,system-prompt} files there - # (see `paths::config_dir`). Kept separate from `/run/hive` - # — that bind comes in root-owned from the host and holds - # hive-c0re's `mcp.sock` we only connect to (#658 fixup). - RuntimeDirectory = "hive-config"; - # Run the harness as the per-agent user (#658). claude itself - # spawned by the harness then runs as that user too — drops - # root inside the container while sudo (`NOPASSWD: ALL` by - # default, see `hyperhive.user.passwordlessSudo`) keeps the - # previous root-by-default surface available explicitly for - # tools that need it. - User = userName; - Group = userName; - }; - }; - system.stateVersion = "25.11"; }; }