fix(947): strip prose/issue-tags from harness-base.nix

This commit is contained in:
damocles 2026-06-01 16:44:57 +02:00 committed by mara
commit 2f25131403

View file

@ -10,8 +10,8 @@
... ...
}: }:
let let
# Agent user metadata (#658). `userName` defaults to `"agent"` when # Agent user metadata. `userName` defaults to `"agent"` when the
# the meta-flake doesn't inject the per-agent override (stand-alone # meta-flake doesn't inject the per-agent override (stand-alone
# `nixos-rebuild` against `nixosConfigurations.agent-base` works # `nixos-rebuild` against `nixosConfigurations.agent-base` works
# without erroring on a missing per-agent name). `homeDir` derives # without erroring on a missing per-agent name). `homeDir` derives
# from `userName` to keep them coupled. # from `userName` to keep them coupled.
@ -29,7 +29,7 @@ in
# only opts in from its own `agent.nix`. # only opts in from its own `agent.nix`.
imports = [ ./weston-vnc.nix ]; imports = [ ./weston-vnc.nix ];
# Per-agent unix user the harness + co-process daemons run as (#658). # Per-agent unix user the harness + co-process daemons run as.
# Defaults to `"agent"` so a standalone evaluation (e.g. # Defaults to `"agent"` so a standalone evaluation (e.g.
# `nix flake check` against `nixosConfigurations.agent-base`) builds # `nix flake check` against `nixosConfigurations.agent-base`) builds
# cleanly; the meta-flake's per-agent module rebinds this to the # cleanly; the meta-flake's per-agent module rebinds this to the
@ -83,25 +83,20 @@ in
When `true`, set `HIVE_WEB_SOCKET=/run/hive-agent/${userName}/web.sock` When `true`, set `HIVE_WEB_SOCKET=/run/hive-agent/${userName}/web.sock`
on the harness service env, which makes `web_ui::serve` bind a on the harness service env, which makes `web_ui::serve` bind a
`UnixListener` at that path instead of the legacy TCP listener `UnixListener` at that path instead of the legacy TCP listener
on `HIVE_PORT`. Closes the third hop of the #784 rollout: PR on `HIVE_PORT`.
#800 added the harness-side opt-in, #809 / #813 added the c0re
bind-mount + JSON-map plumbing, this is the per-agent flip
that activates the unix-domain path.
Default `false` so an agent's web UI keeps binding TCP until Default `false` so an agent's web UI keeps binding TCP until
the per-agent flip is explicit. Rollout shape: the per-agent flip is explicit. Rollout shape:
1. flip one canary agent (atlas volunteered) to `true` via its 1. flip one canary agent to `true` via its `agent.nix`;
`agent.nix` once #813 lands;
2. validate the gateway's `proxy_pass http://unix:.../web.sock` 2. validate the gateway's `proxy_pass http://unix:.../web.sock`
end-to-end against that canary (atlas's step 3); end-to-end against that canary;
3. flip remaining agents per-agent as the gateway side soaks; 3. flip remaining agents per-agent as the gateway side soaks;
4. eventually drop this option once every agent's on unix + 4. eventually drop this option once every agent is on unix and
atlas's gateway is the only path step 4 of #784 drops the the TCP fallback is removed from the harness.
harness's TCP fallback at the same time.
Sub-agents only: the manager always has its unix socket set Sub-agents only: the manager always has `HIVE_WEB_SOCKET` set
unconditionally in the `isManager` block below, so this toggle unconditionally in the `isManager` env block, so this toggle
has no effect when `hyperhive.role = "manager"`. has no effect when `hyperhive.role = "manager"`.
''; '';
}; };
@ -125,9 +120,6 @@ in
it's exposed so a standalone `nixos-rebuild` against it's exposed so a standalone `nixos-rebuild` against
`nixosConfigurations.manager` keeps working without the `nixosConfigurations.manager` keeps working without the
meta-flake wrapper around it. meta-flake wrapper around it.
Closes #671: harness + manager templates merged into a
single `harness-base.nix` driven by this option.
''; '';
}; };
@ -264,8 +256,8 @@ in
type = lib.types.bool; type = lib.types.bool;
default = true; default = true;
description = '' description = ''
Enable per-agent matrix integration via `hive-matrix-mcp` Enable per-agent matrix integration via `hive-matrix-mcp`.
(#548 phase 3). When true (the default), the harness: When true (the default), the harness:
- runs `hive-matrix-daemon` as a systemd unit that holds a - runs `hive-matrix-daemon` as a systemd unit that holds a
matrix-sdk Client + sync against the homeserver at matrix-sdk Client + sync against the homeserver at
@ -273,8 +265,8 @@ in
in-host tuwunel from `nix/modules/hive-matrix.nix`). The in-host tuwunel from `nix/modules/hive-matrix.nix`). The
daemon auto-skips when `<state>/matrix-token` is missing, daemon auto-skips when `<state>/matrix-token` is missing,
and a `systemd.paths` watcher restarts it the moment and a `systemd.paths` watcher restarts it the moment
hive-c0re provisions the token (mirrors `matrix-avatar-sync` hive-c0re provisions the token (same path-trigger shape
shape from #571). as `matrix-avatar-sync`).
- exposes the matrix tool surface (send_message, send_dm, - exposes the matrix tool surface (send_message, send_dm,
send_reaction, send_reply, mark_read, list_rooms, send_reaction, send_reply, mark_read, list_rooms,
list_room_members, read_room) to claude via an auto-injected list_room_members, read_room) to claude via an auto-injected
@ -574,9 +566,8 @@ in
# all contributions across modules into one file. Loaded via # all contributions across modules into one file. Loaded via
# `$BASH_ENV` for non-interactive shells (claude's `Bash` tool # `$BASH_ENV` for non-interactive shells (claude's `Bash` tool
# runs `bash -c`) and via `programs.bash.interactiveShellInit` # runs `bash -c`) and via `programs.bash.interactiveShellInit`
# for interactive shells. Generic by design (mara on #779) so # for interactive shells. Generic by design so future hooks
# future hooks don't need to either rename this file or invent # don't need to rename this file or invent a parallel dispatcher.
# a parallel dispatcher.
options.hyperhive._bashEnvFragments = lib.mkOption { options.hyperhive._bashEnvFragments = lib.mkOption {
type = lib.types.lines; type = lib.types.lines;
default = ""; default = "";
@ -603,7 +594,7 @@ in
anything else) invokes `cargo` inside this container. anything else) invokes `cargo` inside this container.
Saves tokens + context the verbose default output floods Saves tokens + context the verbose default output floods
the response window with per-crate progress lines that the response window with per-crate progress lines that
carry no signal beyond the warning/error summary (#777). carry no signal beyond the warning/error summary.
Implementation: contributes a `cargo` shell function to Implementation: contributes a `cargo` shell function to
`/etc/hyperhive/bash-env.sh` (see `hyperhive._bashEnvFragments`). `/etc/hyperhive/bash-env.sh` (see `hyperhive._bashEnvFragments`).
@ -699,18 +690,12 @@ in
} }
]; ];
# Per-agent unix user (#658). Runs the hive-ag3nt / hive-m1nd # Per-agent unix user. Runs the hive-ag3nt / hive-m1nd harness +
# harness + co-process daemons (hive-matrix-daemon) under a # co-process daemons under a non-root principal. UID auto-assigned by
# non-root principal. The user name follows # NixOS. The container activation script (hive-agent-user-migrate)
# `hyperhive.user.name` — defaults to `"agent"` for standalone # chowns the bind-mounted state dir — including credential files
# eval, overridden per-agent by the meta-flake to the agent's # written by hive-c0re before the container was built — to this user
# own label so each container has a uniquely-named user. # on every boot, so agent processes can always read their own tokens.
#
# UID auto-assigned by NixOS (per mara's #8109: "no hardcoded
# uids"). Home is `/home/${userName}`. `wheel` membership +
# the sudoers rule below grants `NOPASSWD: ALL` when
# `passwordlessSudo` is true — same blast radius as the
# previous root-by-default shape, just explicit.
users.users.${userName} = { users.users.${userName} = {
isNormalUser = true; isNormalUser = true;
home = homeDir; home = homeDir;
@ -745,10 +730,10 @@ in
} }
]; ];
# Post-#658 first-boot migration to the per-agent unix user — # First-boot migration to the per-agent unix user — creates the
# creates the home dir, chowns the bind-mounted state + # home dir, chowns the bind-mounted state + `~/.claude/`, and
# `~/.claude/`, and (marker-guarded) moves any leftover # (marker-guarded) moves any leftover `/root/.claude` content
# `/root/.claude` content from the pre-#658 root-run shape. See # from the previous root-run shape. See
# `docs/persistence.md::First-boot agent-user migration` for the # `docs/persistence.md::First-boot agent-user migration` for the
# step-by-step rationale; this script implements it. # step-by-step rationale; this script implements it.
system.activationScripts.hive-agent-user-migrate = lib.stringAfter [ "users" "specialfs" ] '' system.activationScripts.hive-agent-user-migrate = lib.stringAfter [ "users" "specialfs" ] ''
@ -775,8 +760,8 @@ in
fi fi
''; '';
# Auto-inject the matrix MCP entry when matrix is enabled (#548 # Auto-inject the matrix MCP entry when matrix is enabled.
# phase 3). Operator can override or disable by setting their own # Operator can override or disable by setting their own
# `extraMcpServers.matrix` (nix submodule merge takes the operator's # `extraMcpServers.matrix` (nix submodule merge takes the operator's
# value) or by flipping `hyperhive.matrix.enable = false`. # value) or by flipping `hyperhive.matrix.enable = false`.
hyperhive.extraMcpServers = lib.mkIf config.hyperhive.matrix.enable { hyperhive.extraMcpServers = lib.mkIf config.hyperhive.matrix.enable {
@ -784,9 +769,9 @@ in
command = "${pkgs.hyperhive}/bin/hive-matrix-mcp"; command = "${pkgs.hyperhive}/bin/hive-matrix-mcp";
args = [ ]; args = [ ];
# Same socket path the hive-matrix-daemon service binds # Same socket path the hive-matrix-daemon service binds
# via its `RuntimeDirectory = "hive-matrix"` (#658). Keeps # via its `RuntimeDirectory = "hive-matrix"`. Keeps the
# the bridge + daemon in sync without baking the new path # bridge + daemon in sync without baking the path into
# into the Rust default — the env override wins for both. # the Rust default — the env override wins for both.
env.HIVE_MATRIX_SOCKET = "/run/hive-matrix/socket"; env.HIVE_MATRIX_SOCKET = "/run/hive-matrix/socket";
allowedTools = [ "*" ]; allowedTools = [ "*" ];
}; };
@ -801,18 +786,18 @@ in
source = config.hyperhive.icon; source = config.hyperhive.icon;
}; };
# Cargo `--message-format short` injector (#777). Contributes a # Cargo `--message-format short` injector. Contributes a `cargo`
# `cargo` shell function to `hyperhive._bashEnvFragments`; the # shell function to `hyperhive._bashEnvFragments`; the bash-env
# bash-env infrastructure below packages that into a single file # infrastructure below packages that into a single file sourced
# sourced by both non-interactive and interactive shells. # by both non-interactive and interactive shells.
# `command cargo …` falls back to the un-wrapped binary in PATH # `command cargo …` falls back to the un-wrapped binary in PATH
# (the rust toolchain's cargo — either from `environment.systemPackages` # (the rust toolchain's cargo — either from `environment.systemPackages`
# or from whatever `nix develop` shell the agent's working in). # or from whatever `nix develop` shell the agent's working in).
hyperhive._bashEnvFragments = lib.mkIf config.hyperhive.cargo.shortMessages '' hyperhive._bashEnvFragments = lib.mkIf config.hyperhive.cargo.shortMessages ''
# Auto-injects --message-format short on cargo compile # Auto-injects --message-format short on cargo compile
# subcommands so per-crate progress lines don't flood # subcommands so per-crate progress lines don't flood
# claude's context (#777). Bypassed when the caller # claude's context. Bypassed when the caller already passes
# already passes --message-format (any form). # --message-format (any form).
cargo() { cargo() {
# Strip leading +toolchain selectors (cargo +nightly …). # Strip leading +toolchain selectors (cargo +nightly …).
local pre=() local pre=()
@ -918,7 +903,7 @@ in
# feature hook's snippet into scope without touching # feature hook's snippet into scope without touching
# `/etc/profile` (login-only). Interactive shells source the # `/etc/profile` (login-only). Interactive shells source the
# same file via the `interactiveShellInit` hook below so # same file via the `interactiveShellInit` hook below so
# behaviour matches across both modes (#777). # behaviour matches across both modes.
BASH_ENV = "/etc/hyperhive/bash-env.sh"; BASH_ENV = "/etc/hyperhive/bash-env.sh";
}; };
@ -1188,9 +1173,9 @@ in
fi fi
TOKEN=$(cat "$TOKEN_FILE") TOKEN=$(cat "$TOKEN_FILE")
# Local tuwunel reachable on shared host netns at the # Local tuwunel reachable on shared host netns at the
# default matrix-spec port. Override via the future # default matrix-spec port. Override via
# `hyperhive.matrix.url` if the operator ever runs the # `hyperhive.matrix.url` if the operator runs the
# homeserver elsewhere (deferred to #548 phase 4). # homeserver elsewhere.
MATRIX_URL=http://localhost:8008 MATRIX_URL=http://localhost:8008
# whoami → user_id. Needed to scope the avatar set call. # whoami → user_id. Needed to scope the avatar set call.
# Tolerant of the homeserver being unreachable (`-f` makes # Tolerant of the homeserver being unreachable (`-f` makes
@ -1323,13 +1308,13 @@ in
HIVE_ROLE = config.hyperhive.role; HIVE_ROLE = config.hyperhive.role;
} }
// lib.optionalAttrs config.hyperhive.web.useUnixSocket { // lib.optionalAttrs config.hyperhive.web.useUnixSocket {
# Per-agent unix-socket flip for the web UI (#784 phase 2 # Per-agent unix-socket path for the web UI. When set,
# step 2c). When set, the harness's `web_ui::serve` binds # the harness's `web_ui::serve` binds a `UnixListener`
# a `UnixListener` at this path instead of TCP. Path # at this path instead of TCP. Path matches
# matches `hive_c0re::agent_sockets::socket_path_for(name)` # `hive_c0re::agent_sockets::socket_path_for(name)` so
# so the lifecycle bind-mount (#813) and the gateway's # the lifecycle bind-mount and the gateway's upstream
# upstream config all derive from the same canonical # config all derive from the same canonical
# `/run/hive-agent/<name>/web.sock` shape — no triangulation. # `/run/hive-agent/<name>/web.sock` shape.
HIVE_WEB_SOCKET = "/run/hive-agent/${userName}/web.sock"; HIVE_WEB_SOCKET = "/run/hive-agent/${userName}/web.sock";
} }
// lib.optionalAttrs isManager { // lib.optionalAttrs isManager {
@ -1337,9 +1322,8 @@ in
# HIVE_PORT = FNV-1a("hm1nd") % 900 + 8100. # HIVE_PORT = FNV-1a("hm1nd") % 900 + 8100.
HIVE_PORT = "8875"; HIVE_PORT = "8875";
HIVE_LABEL = "hm1nd"; HIVE_LABEL = "hm1nd";
# Manager always uses a unix socket for its web UI so the # Manager always uses a unix socket so the gateway can route
# gateway can route /agent/<name>/ to it the same way it # /agent/<name>/ to it the same way it routes sub-agents.
# routes sub-agents. Path mirrors agent_sockets::socket_path_for.
HIVE_WEB_SOCKET = "/run/hive-agent/${userName}/web.sock"; HIVE_WEB_SOCKET = "/run/hive-agent/${userName}/web.sock";
}; };
serviceConfig = { serviceConfig = {
@ -1359,3 +1343,4 @@ in
system.stateVersion = "25.11"; system.stateVersion = "25.11";
}; };
} }