feat(#2659): serve hive-bash-mcp over persistent streamable-http, drop stdio bridge

This commit is contained in:
damocles 2026-07-23 17:34:02 +02:00 committed by mara
commit c4fcf7fbf1
26 changed files with 376 additions and 574 deletions

View file

@ -121,7 +121,7 @@ Bin-loop helpers `build_row` + `record` land each row at
the turn loop continue.
A sibling `bash_commands(ts INTEGER, head TEXT)` table in the same
file is written by the `hive-bash-mcp` daemon (not the harness): one
file is written by the `hive-bash-daemon` (not the harness): one
row per executed bash task recording the normalised command head -
the basename of the first real command, looking past `cd repo &&`
prefixes, env-assignments, and prefix-runners like `sudo`/`env`. It
@ -234,7 +234,7 @@ Under `/var/lib/hyperhive/agents/<name>/`:
hourly and deletes terminal task trios older than 48 hours;
non-terminal (still-running) tasks are never deleted by vacuum.
- `hyperhive-todos.sqlite` — loose-ends-v2 todo store. In-container
MCP daemons (`hive-bash-mcp`, `hive-matrix-mcp`) and `forge_notify`
MCP daemons (`hive-bash-daemon`, `hive-matrix-mcp`) and `forge_notify`
upsert keyed todos here over the harness's in-agent socket
(`HIVE_AGENT_SOCKET`); the harness merges them into `get_loose_ends`
output and clears a row on `mark_todo_done`. Replaced the old

View file

@ -1,6 +1,6 @@
# Bash execution tools
Background shell execution via `hive-bash-mcp`. Tools land as
Background shell execution via `hive-bash-daemon`. Tools land as
`mcp__bash__<tool>` (the MCP server name is `bash`, not `hyperhive`).
Available on every agent unconditionally — `nix/agent-modules/mcp.nix` always
injects bash into `hyperhive.extraMcpServers` (with `allowedTools =
@ -91,21 +91,17 @@ this structured path so tasks get task-id tracking and structured output.
## Architecture
The bash tooling follows the same daemon + stdio-bridge pattern as the
matrix MCP:
- **`hive-bash-daemon`** — long-running process (one per agent container,
systemd service in `nix/agent-modules/mcp.nix`). Owns subprocess management,
output file writing, and todo delivery on the harness's in-agent socket.
Listens on `/run/hive-bash/socket` inside the container.
- **`hive-bash-mcp`** — stdio bridge spawned by claude per turn (declared
in `hyperhive.extraMcpServers.bash`). Connects to the daemon socket and
forwards `run` / `status` tool calls. Has no subprocess management logic
of its own.
This split keeps claude's turn-local MCP bridge lightweight while the
daemon tracks long-running tasks that outlive a single turn.
`hive-bash-daemon` is a single long-running process (one per agent
container, systemd service in `nix/agent-modules/mcp.nix`) — no stdio
bridge, no separate bin. It owns subprocess management, output file
writing, todo delivery on the harness's in-agent socket, **and** serves
the `run`/`status`/`kill` MCP tools directly over streamable-http on
`hyperhive.mcp.bashHttpPort` (declared in `hyperhive.extraMcpServers.bash`
as `{ type = "http"; url = ...; }`). Same shape as the built-in
`hyperhive` surface (`hive-mcp-http`) — claude reconnects to the stable
URL every turn instead of respawning a stdio child, so there's no
per-turn MCP re-registration race and no round-trip socket hop for tool
calls.
### Completion as a todo (loose-ends v2)

View file

@ -7,9 +7,12 @@ per-container private netns). Claude connects to its stable URL via
`--mcp-config` rather than respawning a stdio child each turn, so the
URL survives the per-turn claude re-spawn (and a host-side hive-c0re
restart) — there is no per-turn MCP re-registration race for the
built-in surface. HTTP is the sole transport for it (no stdio fallback);
extra servers (`hyperhive.extraMcpServers`, e.g. matrix/bash) stay stdio
bridges. The server name is `hyperhive`, so the tools land in claude as
built-in surface. HTTP is the sole transport for it (no stdio fallback).
Extra servers (`hyperhive.extraMcpServers`) pick their own transport per
entry (`type = "stdio" | "http"`, default `"stdio"`): `matrix` stays a
stdio bridge, `bash` runs its own persistent streamable-http listener
(`hive-bash-daemon`) — same reasoning as the built-in surface. The
server name is `hyperhive`, so the tools land in claude as
`mcp__hyperhive__<tool>`.
Tool access is gated by tool groups (`HIVE_TOOL_GROUPS`). The default
@ -81,7 +84,7 @@ at_unix_timestamp?)`, `request_next_turn()`.
- `get_loose_ends(agent?)` — list pending questions (asked/owed),
scheduled reminders, and active local tasks published by external MCP
daemons (e.g. running bash tasks from `hive-bash-mcp`). Each row
daemons (e.g. running bash tasks from `hive-bash-daemon`). Each row
carries an id + kind for `cancel_loose_end`. Omit `agent` to list
your own threads. Pass `agent: "<name>"` to inspect a direct child
agent (always accessible per topology enforcement); non-children

View file

@ -454,7 +454,7 @@ error / rate-limit / compaction outcomes are visible over time
(the doughnut shows only the window total).
A **favorite tools** doughnut shows the most-run shell commands —
normalised `bash_commands` heads written per bash task by the
hive-bash-mcp capture: the basename of the *first real command*,
hive-bash-daemon capture: the basename of the *first real command*,
looking past `cd repo &&` prefixes, env-assignments, and
prefix-runners like `sudo` / `env` (so `cd /repo && cargo build`
records `cargo`, not `cd`). Read via `bash_breakdown`; the card

View file

@ -563,7 +563,7 @@ charts): ST4TS is the swarm-level rollup.
- **Model mix** — turns per model across the swarm, as CSS bars.
- **Favorite tools** — most-run normalised bash-command heads across the
swarm (top 10, as CSS bars), aggregated from each agent's
`bash_commands` table (written by the hive-bash-mcp capture). The
`bash_commands` table (written by the hive-bash-daemon capture). The
header + list stay hidden until at least one agent has recorded a
command, so the section never shows an empty block on a fresh hive.