fix(#947): set HIVE_WEB_SOCKET for manager unconditionally
This commit is contained in:
parent
4435666c00
commit
0ac05f0638
1 changed files with 70 additions and 54 deletions
|
|
@ -10,8 +10,8 @@
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
# Agent user metadata. `userName` defaults to `"agent"` when the
|
# Agent user metadata (#658). `userName` defaults to `"agent"` when
|
||||||
# meta-flake doesn't inject the per-agent override (stand-alone
|
# the 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.
|
# Per-agent unix user the harness + co-process daemons run as (#658).
|
||||||
# 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,24 +83,26 @@ 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`.
|
on `HIVE_PORT`. Closes the third hop of the #784 rollout: PR
|
||||||
|
#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 to `true` via its `agent.nix`;
|
1. flip one canary agent (atlas volunteered) to `true` via its
|
||||||
|
`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;
|
end-to-end against that canary (atlas's step 3);
|
||||||
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 is on unix and
|
4. eventually drop this option once every agent's on unix +
|
||||||
the TCP fallback is removed from the harness.
|
atlas's gateway is the only path — step 4 of #784 drops the
|
||||||
|
harness's TCP fallback at the same time.
|
||||||
|
|
||||||
Sub-agent-only by design: the manager's UI serves at `/` via
|
Sub-agents only: the manager always has its unix socket set
|
||||||
the c0re dashboard upstream, not via `/agent/<name>/`, so this
|
unconditionally in the `isManager` block below, so this toggle
|
||||||
option has no effect when `hyperhive.role = "manager"` (the
|
has no effect when `hyperhive.role = "manager"`.
|
||||||
env var is set unconditionally for clarity, but the manager's
|
|
||||||
web UI doesn't route through the gateway's per-agent unix
|
|
||||||
upstream — its bind socket would just sit unused).
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -123,6 +125,9 @@ 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.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -259,8 +264,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`
|
||||||
When true (the default), the harness:
|
(#548 phase 3). 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
|
||||||
|
|
@ -268,8 +273,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 (same path-trigger shape
|
hive-c0re provisions the token (mirrors `matrix-avatar-sync`
|
||||||
as `matrix-avatar-sync`).
|
shape from #571).
|
||||||
- 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
|
||||||
|
|
@ -569,8 +574,9 @@ 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 so future hooks
|
# for interactive shells. Generic by design (mara on #779) so
|
||||||
# don't need to rename this file or invent a parallel dispatcher.
|
# future hooks don't need to either rename this file or invent
|
||||||
|
# a parallel dispatcher.
|
||||||
options.hyperhive._bashEnvFragments = lib.mkOption {
|
options.hyperhive._bashEnvFragments = lib.mkOption {
|
||||||
type = lib.types.lines;
|
type = lib.types.lines;
|
||||||
default = "";
|
default = "";
|
||||||
|
|
@ -597,7 +603,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.
|
carry no signal beyond the warning/error summary (#777).
|
||||||
|
|
||||||
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`).
|
||||||
|
|
@ -693,12 +699,18 @@ in
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
# Per-agent unix user. Runs the hive-ag3nt / hive-m1nd harness +
|
# Per-agent unix user (#658). Runs the hive-ag3nt / hive-m1nd
|
||||||
# co-process daemons under a non-root principal. UID auto-assigned by
|
# harness + co-process daemons (hive-matrix-daemon) under a
|
||||||
# NixOS. The container activation script (hive-agent-user-migrate)
|
# non-root principal. The user name follows
|
||||||
# chowns the bind-mounted state dir — including credential files
|
# `hyperhive.user.name` — defaults to `"agent"` for standalone
|
||||||
# written by hive-c0re before the container was built — to this user
|
# eval, overridden per-agent by the meta-flake to the agent's
|
||||||
# on every boot, so agent processes can always read their own tokens.
|
# own label so each container has a uniquely-named user.
|
||||||
|
#
|
||||||
|
# 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;
|
||||||
|
|
@ -733,10 +745,10 @@ in
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
# First-boot migration to the per-agent unix user — creates the
|
# Post-#658 first-boot migration to the per-agent unix user —
|
||||||
# home dir, chowns the bind-mounted state + `~/.claude/`, and
|
# creates the home dir, chowns the bind-mounted state +
|
||||||
# (marker-guarded) moves any leftover `/root/.claude` content
|
# `~/.claude/`, and (marker-guarded) moves any leftover
|
||||||
# from the previous root-run shape. See
|
# `/root/.claude` content from the pre-#658 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" ] ''
|
||||||
|
|
@ -763,8 +775,8 @@ in
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# Auto-inject the matrix MCP entry when matrix is enabled.
|
# Auto-inject the matrix MCP entry when matrix is enabled (#548
|
||||||
# Operator can override or disable by setting their own
|
# phase 3). 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 {
|
||||||
|
|
@ -772,9 +784,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"`. Keeps the
|
# via its `RuntimeDirectory = "hive-matrix"` (#658). Keeps
|
||||||
# bridge + daemon in sync without baking the path into
|
# the bridge + daemon in sync without baking the new path
|
||||||
# the Rust default — the env override wins for both.
|
# into 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 = [ "*" ];
|
||||||
};
|
};
|
||||||
|
|
@ -789,18 +801,18 @@ in
|
||||||
source = config.hyperhive.icon;
|
source = config.hyperhive.icon;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Cargo `--message-format short` injector. Contributes a `cargo`
|
# Cargo `--message-format short` injector (#777). Contributes a
|
||||||
# shell function to `hyperhive._bashEnvFragments`; the bash-env
|
# `cargo` shell function to `hyperhive._bashEnvFragments`; the
|
||||||
# infrastructure below packages that into a single file sourced
|
# bash-env infrastructure below packages that into a single file
|
||||||
# by both non-interactive and interactive shells.
|
# sourced 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. Bypassed when the caller already passes
|
# claude's context (#777). Bypassed when the caller
|
||||||
# --message-format (any form).
|
# already passes --message-format (any form).
|
||||||
cargo() {
|
cargo() {
|
||||||
# Strip leading +toolchain selectors (cargo +nightly …).
|
# Strip leading +toolchain selectors (cargo +nightly …).
|
||||||
local pre=()
|
local pre=()
|
||||||
|
|
@ -906,7 +918,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.
|
# behaviour matches across both modes (#777).
|
||||||
BASH_ENV = "/etc/hyperhive/bash-env.sh";
|
BASH_ENV = "/etc/hyperhive/bash-env.sh";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1176,9 +1188,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
|
# default matrix-spec port. Override via the future
|
||||||
# `hyperhive.matrix.url` if the operator runs the
|
# `hyperhive.matrix.url` if the operator ever runs the
|
||||||
# homeserver elsewhere.
|
# homeserver elsewhere (deferred to #548 phase 4).
|
||||||
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
|
||||||
|
|
@ -1311,13 +1323,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 path for the web UI. When set,
|
# Per-agent unix-socket flip for the web UI (#784 phase 2
|
||||||
# the harness's `web_ui::serve` binds a `UnixListener`
|
# step 2c). When set, the harness's `web_ui::serve` binds
|
||||||
# at this path instead of TCP. Path matches
|
# a `UnixListener` at this path instead of TCP. Path
|
||||||
# `hive_c0re::agent_sockets::socket_path_for(name)` so
|
# matches `hive_c0re::agent_sockets::socket_path_for(name)`
|
||||||
# the lifecycle bind-mount and the gateway's upstream
|
# so the lifecycle bind-mount (#813) and the gateway's
|
||||||
# config all derive from the same canonical
|
# upstream config all derive from the same canonical
|
||||||
# `/run/hive-agent/<name>/web.sock` shape.
|
# `/run/hive-agent/<name>/web.sock` shape — no triangulation.
|
||||||
HIVE_WEB_SOCKET = "/run/hive-agent/${userName}/web.sock";
|
HIVE_WEB_SOCKET = "/run/hive-agent/${userName}/web.sock";
|
||||||
}
|
}
|
||||||
// lib.optionalAttrs isManager {
|
// lib.optionalAttrs isManager {
|
||||||
|
|
@ -1325,6 +1337,10 @@ 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
|
||||||
|
# gateway can route /agent/<name>/ to it the same way it
|
||||||
|
# routes sub-agents. Path mirrors agent_sockets::socket_path_for.
|
||||||
|
HIVE_WEB_SOCKET = "/run/hive-agent/${userName}/web.sock";
|
||||||
};
|
};
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${pkgs.hyperhive}/bin/${binary} serve";
|
ExecStart = "${pkgs.hyperhive}/bin/${binary} serve";
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue