Apply contraction fixes across ~40 doc files (setup, integrations, lifecycle, networking, scheduler, swarm, tools, trust-boundary, UI, etc.). Skipped 14 hits: - 10 where words appear in ALL CAPS for deliberate emphasis (is NOT, do NOT, etc.) - 4 where text could not be safely located due to markdown formatting or column position Applied via systematic scan with checks for fenced code blocks, inline code spans, and intentional caps. Preserves sentence-initial capitalization throughout.
127 lines
5.9 KiB
Markdown
127 lines
5.9 KiB
Markdown
# Bash execution tools
|
|
|
|
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 =
|
|
["*"]`), so `mcp__bash__*` is in `--allowedTools` for every claude
|
|
invocation regardless of tool groups.
|
|
|
|
## Tools
|
|
|
|
### `run(cmd, timeout_secs?, wait_seconds?, name?)`
|
|
|
|
Submit a shell command for background execution (runs via `bash`).
|
|
Stdout and stderr stream to `harness/bash-tasks/<id>.{out,err}`.
|
|
When the task completes (or times out, or the process errors), it
|
|
surfaces as a todo in the agent's loose-ends (via `get_loose_ends`),
|
|
carrying the exit code and a `Read(<path>)` pointer to the captured
|
|
output. Handle it on a future turn — unless `wait_seconds` already
|
|
delivered the terminal result inline, in which case no todo is created
|
|
(see `status` below).
|
|
|
|
- `timeout_secs` — kill the task after N seconds and mark it
|
|
`timed_out`. Omit for no timeout (runs until natural exit).
|
|
- `wait_seconds` — inline poll before returning (capped at 30).
|
|
When the task finishes within the window the full status is
|
|
returned immediately and no todo is created; when the window expires
|
|
the task keeps running and the normal `task started: id=<id>`
|
|
response is returned. **Defaults to 3** — pass `wait_seconds: 0`
|
|
to disable inline waiting and always get the immediate response.
|
|
- `name` — optional caller-chosen task id. When set it replaces the
|
|
auto-generated hex id, so it surfaces in `status(<name>)` lookups and
|
|
the loose-ends list — a memorable label instead of an opaque id. A name
|
|
is **reusable once its previous task has finished**; submitting a
|
|
name whose task is still `pending`/`running` is rejected. Allowed
|
|
characters: `[a-z0-9-]` (a valid identifier — lowercase, digits,
|
|
hyphen; max 63). Omit for the auto-generated id.
|
|
|
|
Exposed as `mcp__bash__run`.
|
|
|
|
### `status(id, wait_seconds?)`
|
|
|
|
Poll the status of a task submitted with `run`. Returns:
|
|
|
|
- `status` — `pending` / `running` / `done` / `timed_out` / `interrupted` / `killed`
|
|
- `exit_code` — set when done
|
|
- run duration
|
|
- last 4 KiB of stdout and stderr (full output in the `.out` / `.err` files)
|
|
|
|
`wait_seconds` — optional inline poll (capped at 30): when the task
|
|
finishes within the window the full status is returned immediately.
|
|
Useful to avoid a separate round-trip when the task is expected to
|
|
finish soon.
|
|
|
|
Any `status` call (waited or not) that observes a terminal task clears
|
|
that task's completion todo — you already have the result in this
|
|
response, so no redundant loose-end follows. Narrow best-effort race: a
|
|
`status`/`run` inline wait that resolves in the same instant the task
|
|
actually finishes can still occasionally get both.
|
|
|
|
Tasks marked `interrupted` had their process killed by a harness
|
|
restart; a best-effort todo is still surfaced so the agent isn't
|
|
silently blocked.
|
|
|
|
Exposed as `mcp__bash__status`.
|
|
|
|
### `kill(id, force?)`
|
|
|
|
Stop a running or pending task by its ID (from `run`). Fire-and-forget:
|
|
sends the signal and returns without waiting — the completion surfaces
|
|
in the agent's loose-ends; handle it on a future turn.
|
|
|
|
- `force: false` (default) — SIGINT to the task's **process group**
|
|
(graceful; lets the process clean up). The whole process group is
|
|
signalled, so children spawned by the shell (cargo, nix, etc.) are
|
|
also stopped.
|
|
- `force: true` — SIGKILL.
|
|
|
|
If a SIGINT'd task doesn't exit, call `kill` again with `force: true`.
|
|
A still-pending task is cancelled before it starts. The task ends as
|
|
`killed` and surfaces in the loose-ends like any completion.
|
|
|
|
Exposed as `mcp__bash__kill`.
|
|
|
|
## Namespace note
|
|
|
|
`run` and `status` live in the `bash` MCP server, not `hyperhive`. So
|
|
the tool names in claude are `mcp__bash__run` and `mcp__bash__status`.
|
|
The `Bash` built-in tool is blocked — all shell execution goes through
|
|
this structured path so tasks get task-id tracking and structured output.
|
|
|
|
## Architecture
|
|
|
|
`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)
|
|
|
|
When a bash task changes state, `hive-bash-daemon` upserts a single keyed
|
|
todo (`key = task id`) on the harness's in-agent socket (`HIVE_AGENT_SOCKET`)
|
|
— "running" at start, then the completion summary when it finishes. The
|
|
summary change signals the harness turn loop directly (in-process, no broker
|
|
round-trip), so the agent is driven a turn to handle it via `get_loose_ends`,
|
|
then clears the todo with `cancel_loose_end(kind: "todo", id: N)` (dials the
|
|
in-container socket directly — no bash task involved, so clearing doesn't
|
|
spawn another todo; see #2639). Same mechanism the matrix daemon uses for
|
|
unread rooms. An inline `wait_seconds` / `status` observation that already
|
|
delivered the result instead clears the keyed todo, so no redundant
|
|
loose-end follows.
|
|
|
|
## Relationship to the `execution` tool group
|
|
|
|
`ToolGroup::Execution` exists and appears in `AGENT_DEFAULT`, but its
|
|
`tools()` returns `["run", "status"]` which the harness expands to
|
|
`mcp__hyperhive__run` / `mcp__hyperhive__status` — tools that don't
|
|
exist in the hyperhive MCP server (dead entries). Removing `execution`
|
|
from an agent's groups has no effect on bash availability. Bash is
|
|
registered separately via the `extraMcpServers` path described above.
|