70 lines
3.2 KiB
Nix
70 lines
3.2 KiB
Nix
{ 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;
|
|
};
|
|
};
|
|
}
|