docs(#2628): update bash tool descriptions, docs, and system prompt for the todo model (trim impl details for agent)

This commit is contained in:
damocles 2026-07-22 17:34:12 +02:00
commit 3188e50ab8
5 changed files with 67 additions and 70 deletions

View file

@ -13,24 +13,24 @@ invocation regardless of tool groups.
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), the
harness fires a wake with `from: "bash-task-<id>"`; the body contains
the exit code and last stdout lines. Handle the completion on a future
turn — unless `wait_seconds` already delivered the terminal result
inline, in which case the wake is suppressed (see `status` below).
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 wake is fired; when the window expires
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 the wake `from`
(`bash-task-<name>`), in `status(<name>)` lookups, and in the
loose-ends list — a memorable label instead of an opaque id. A name
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: ASCII letters, digits, `.`, `_`, `-` (max 64). Omit for
@ -52,15 +52,14 @@ 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
suppresses that task's completion wake — you already have the result
in this response, so no redundant `bash-task-<id>` inbox message
follows (#2270). Narrow best-effort race: a `status`/`run` inline wait
that resolves in the same instant the task actually finishes can still
occasionally get both.
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 wake was still sent so the agent is not
restart; a best-effort todo is still surfaced so the agent is not
silently blocked.
Exposed as `mcp__bash__status`.
@ -68,8 +67,8 @@ 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 — handle the completion
wake (`from: "bash-task-<id>"`) on a future turn.
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
@ -79,7 +78,7 @@ wake (`from: "bash-task-<id>"`) on a future turn.
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 fires the usual completion wake.
`killed` and surfaces in the loose-ends like any completion.
Exposed as `mcp__bash__kill`.
@ -97,7 +96,7 @@ 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, `mcp-loose-ends/` state, and wake signal delivery.
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
@ -108,13 +107,17 @@ matrix MCP:
This split keeps claude's turn-local MCP bridge lightweight while the
daemon tracks long-running tasks that outlive a single turn.
### Transient wake (bypass broker sqlite)
### Completion as a todo (loose-ends v2)
When a bash task finishes, `hive-bash-daemon` sends the wake signal via
the agent's per-agent socket as a **transient wake** (`AgentRequest::Wake`
with `transient: true`). This bypasses broker sqlite for lower latency —
the same mechanism used by matrix events. The message is delivered
directly to the harness without touching the persistent message store.
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 `mark_todo_done`. 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

View file

@ -90,17 +90,16 @@ returned by `get_loose_ends` so unread rooms surface in the
loose-ends list between turns.
**Invite wakes**: when the daemon's sync loop receives an
`m.room.member` invite event, it writes the invite to
`mcp-loose-ends/matrix.json` and fires a hyperhive wake. The daemon
does **not** auto-join — the agent calls `list_invites` to see pending
`m.room.member` invite event, it upserts a todo (keyed `invite:<room>`)
on the harness's in-agent socket, which drives a turn. The daemon does
**not** auto-join — the agent calls `list_invites` to see pending
invites and `resolve_invite` to accept or reject them.
**Pending invites as loose ends**: pending invites are written to
`mcp-loose-ends/matrix.json` and appear in `get_loose_ends` output as
**Pending invites as loose ends**: pending invites are upserted as
keyed todos and appear in `get_loose_ends` output as
`[matrix] pending invite: <room> — use list_invites to see,
resolve_invite to accept or reject`. The file is updated atomically
after each invite event and after each `resolve_invite` (or
`join_room`) call clears the entry.
resolve_invite to accept or reject`. The keyed todo is cleared when a
`resolve_invite` (or `join_room`) call resolves the invite.
See [`docs/matrix.md`](../matrix.md) for the homeserver setup,
provisioning flow, and federation config.