diff --git a/nix/templates/agent-base.nix b/nix/templates/agent-base.nix index 53aa0e60..82ea3c84 100644 --- a/nix/templates/agent-base.nix +++ b/nix/templates/agent-base.nix @@ -1,70 +1,11 @@ -{ pkgs, config, ... }: -let - userName = config.hyperhive.user.name; -in +{ ... }: { imports = [ ./harness-base.nix ]; - systemd.services.hive-ag3nt = { - description = "hive-ag3nt 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` is 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. - 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 = "/home/${userName}"; - # 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 — both come - # from harness-base.nix. - HIVE_STATIC_DIR = "${config.hyperhive.frontend.mergedDist}"; - # Static runtime assets (branding + claude prompts). Set on the - # unit directly — `environment.variables` in harness-base.nix only - # populates /etc/profile, which systemd services don't inherit. - HIVE_ASSETS_DIR = "${pkgs.hyperhive-assets}/share/hyperhive"; - }; - serviceConfig = { - ExecStart = "${pkgs.hyperhive}/bin/hive-ag3nt 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 harness-base.nix `hyperhive.user.passwordlessSudo`) - # keeps the previous root-by-default surface available - # explicitly for tools that need it. - User = userName; - Group = userName; - }; - }; + # Sub-agent role: the role-driven `systemd.services.hive-ag3nt` plus + # the default forge notification surface live in `harness-base.nix`. + # This file is the bare entry-point referenced from `flake.nix` + # (`nixosConfigurations.agent-base`) and the meta-flake's + # `applied//flake.nix` for sub-agent containers. + hyperhive.role = "agent"; } diff --git a/nix/templates/manager.nix b/nix/templates/manager.nix index d5c79d7a..1c857e3b 100644 --- a/nix/templates/manager.nix +++ b/nix/templates/manager.nix @@ -1,71 +1,15 @@ -{ pkgs, config, ... }: -let - userName = config.hyperhive.user.name; -in +{ ... }: { imports = [ ./harness-base.nix ]; - # Manager auto-unsubscribes from repo watches and skips the subscription/ - # participation firehose — only direct mentions, reviews, and assignments - # land in the inbox. Sub-agents default to keepSubscriptions=true and - # skipNotifyReasons=[]. - hyperhive.forge.keepSubscriptions = false; - hyperhive.forge.skipNotifyReasons = [ - "subscribed" - "participating" - ]; - - # HIVE_PORT/HIVE_LABEL/gitconfig are also injected by the generated - # `applied/hm1nd/flake.nix` (see `lifecycle::setup_applied`); the values - # here are the base config so the container stays sensible if anyone - # ever evaluates `nixosConfigurations.manager` standalone. - systemd.services.hive-m1nd = { - description = "hive-m1nd manager harness"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - environment = { - HIVE_PORT = "8000"; - HIVE_LABEL = "hm1nd"; - SHELL = "${pkgs.bashInteractive}/bin/bash"; - # `HOME` set explicitly so claude finds `~/.claude/` at the - # bind-mounted location after #658 (User= drop from root). - HOME = "/home/${userName}"; - # Manager runs the same hive-m1nd harness binary that serves - # the per-agent web UI; point it at the merged agent static dist - # (same shape as for sub-agents). - HIVE_STATIC_DIR = "${config.hyperhive.frontend.mergedDist}"; - # Static runtime assets (branding + claude prompts). Set on the - # unit directly — `environment.variables` in harness-base.nix only - # populates /etc/profile, which systemd services don't inherit. - HIVE_ASSETS_DIR = "${pkgs.hyperhive-assets}/share/hyperhive"; - }; - # See note in agent-base.nix for the rationale on both entries — - # `/run/wrappers/bin` so the setuid sudo shim resolves before the - # bare nix-store binary (#658 fixup), `/run/current-system/sw` - # so the harness PATH tracks `environment.systemPackages`. - path = [ - "/run/wrappers/bin" - "/run/current-system/sw" - ]; - serviceConfig = { - ExecStart = "${pkgs.hyperhive}/bin/hive-m1nd 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"; - # Same drop-from-root as agent-base.nix (#658). Manager - # interactions with the host (rebuild approvals, config - # writes) still happen via the dedicated unix sockets - # bind-mounted from hive-c0re — those don't need root - # inside the container. - User = userName; - Group = userName; - }; - }; + # Manager role: the role-driven `systemd.services.hive-m1nd` plus + # the manager-only forge defaults (`keepSubscriptions = false`, + # `skipNotifyReasons = [ "subscribed" "participating" ]`) live in + # `harness-base.nix` under `lib.mkIf (config.hyperhive.role == + # "manager")`. This file is the bare entry-point referenced from + # `flake.nix` (`nixosConfigurations.manager`) and the meta-flake's + # `applied/hm1nd/flake.nix`. HIVE_PORT / HIVE_LABEL are injected by + # the meta-flake at deploy time and have manager-only standalone-eval + # fallbacks in `harness-base.nix`. + hyperhive.role = "manager"; }