From 6865b63016c6ed8907727b1f86aa95207e5981c8 Mon Sep 17 00:00:00 2001 From: damocles Date: Mon, 1 Jun 2026 13:54:21 +0200 Subject: [PATCH 1/8] docs: add execution tool group to conventions.md tool groups table --- docs/conventions.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/conventions.md b/docs/conventions.md index 29f2793a..063f259d 100644 --- a/docs/conventions.md +++ b/docs/conventions.md @@ -285,6 +285,7 @@ binary flavor. | `messaging` | `send`, `recv`, `ask`, `answer` | | `meta` | `set_status`, `get_agent_meta` | | `inbox` | `get_loose_ends`, `cancel_loose_end`, `remind`, `request_next_turn` | +| `execution` | `bash_run`, `bash_status` | | `lifecycle` | `kill`, `start`, `restart`, `update` *(privileged)* | | `approvals` | `request_init_config`, `request_apply_commit`, `request_update_meta_inputs` *(privileged)* | | `scheduling` | `request_schedule_prompt`, `fire_schedule_now`, `cancel_schedule`, `edit_schedule`, `list_schedules` *(privileged)* | @@ -307,7 +308,7 @@ the new `HIVE_TOOL_GROUPS` env var. Agents with no entry get no var. **Runtime resolution** — at session start the harness reads `HIVE_TOOL_GROUPS` (a comma-separated list of snake_case group names injected by the meta renderer from `tool-groups.json`). Unrecognised tokens are logged and skipped. Falls back -to `ToolGroup::AGENT_DEFAULT` (`messaging`, `meta`, `inbox`) or +to `ToolGroup::AGENT_DEFAULT` (`messaging`, `meta`, `inbox`, `execution`) or `ToolGroup::MANAGER_DEFAULT` (all groups) when the var is absent or empty. **Updating the surface** — when a new `#[tool]` fn is added to `AgentServer` From 14339319043262d6b63bb769aed645a8e5ba4c90 Mon Sep 17 00:00:00 2001 From: damocles Date: Mon, 1 Jun 2026 13:55:19 +0200 Subject: [PATCH 2/8] docs: document bash_run and bash_status tools in turn-loop.md --- docs/turn-loop.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/turn-loop.md b/docs/turn-loop.md index 2e4f24cc..87df5583 100644 --- a/docs/turn-loop.md +++ b/docs/turn-loop.md @@ -369,6 +369,20 @@ it as a stdio child via `--mcp-config`. The hyperhive socket name is continue without waiting for an external message. The next turn starts with `from: "self"` and `body: "continue"`. No-op if new inbox messages arrive before this turn ends. No args. +- `bash_run(cmd, timeout_secs?)` — submit a shell command for + background execution (`sh -c `). Returns a task ID immediately; + the command runs asynchronously in a harness-managed tokio task. Stdout + and stderr stream to `harness/bash-tasks/.{out,err}`. When the + task completes (or times out, or the process errors), the harness wakes + the agent with a summary body — handle on a future turn. Default + timeout 180s; pass `timeout_secs` to override. Requires the + `execution` tool group. +- `bash_status(id)` — poll the status of a task submitted with + `bash_run`. Returns status (`pending`/`running`/`done`/`timed_out`/ + `interrupted`), exit code, run duration, and the last 4 KiB of stdout + and stderr (full output in the `.out`/`.err` files). Tasks marked + `interrupted` had their process killed by a harness restart; a best- + effort wake was still sent so the agent is not silently blocked. ### Waking the agent from inside the container From 73bf7bef95716590637c87f50617f7bf7fa835e7 Mon Sep 17 00:00:00 2001 From: damocles Date: Mon, 1 Jun 2026 13:56:46 +0200 Subject: [PATCH 3/8] docs: document harness/ dir layout including bash-tasks --- docs/persistence.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/persistence.md b/docs/persistence.md index 386e9e0c..bc77d7b8 100644 --- a/docs/persistence.md +++ b/docs/persistence.md @@ -174,6 +174,18 @@ Under `/var/lib/hyperhive/agents//`: inside the container (uniform for sub-agents + manager). The `$HYPERHIVE_STATE_DIR` env var exposes the same path to in-container scripts. +- `harness/` — harness-internal ephemeral state; not intended for + agent consumption. Bind-mounted to `/agents//harness` + inside the container (`$HYPERHIVE_HARNESS_DIR`). Contents: + - `bash-tasks/` — task JSON + stdout/stderr files for + background `bash_run` jobs. JSON files are + `.json` (status + tails), `.out` / `.err` + (full captured output). Cleaned up by the agent after + inspecting with `bash_status`. + - `hyperhive-events.sqlite` — turn-loop event log. + - `hyperhive-turn-stats.sqlite` — per-turn timing stats. + - `hyperhive-harness.json` — consolidated flags (rate-limited, + model override, etc.) written atomically on each turn. Under `/var/lib/hyperhive/applied//` — the hive-c0re-only applied repo. Tracks `flake.nix` (module-only boilerplate; never From 494a326029e1ddbcef2247c2ea1e8c02958d76fe Mon Sep 17 00:00:00 2001 From: damocles Date: Mon, 1 Jun 2026 14:09:11 +0200 Subject: [PATCH 4/8] docs: fix persistence.md paths for harness-state split --- docs/persistence.md | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/docs/persistence.md b/docs/persistence.md index bc77d7b8..989b86bc 100644 --- a/docs/persistence.md +++ b/docs/persistence.md @@ -64,17 +64,17 @@ Retention: `cancelled_at_unix`, then `reap_cancelled` drops the row on the next worker pass. -### `/state/hyperhive-events.sqlite` (per agent) +### `/harness/hyperhive-events.sqlite` (per agent) -Lives inside each container's bind-mounted `/state/` dir (host -path: `/var/lib/hyperhive/agents//state/hyperhive-events.sqlite`). +Lives inside each container's bind-mounted `/harness/` dir (host +path: `/var/lib/hyperhive/agents//harness/hyperhive-events.sqlite`). One table: - `events(id, ts, kind, payload_json)` — every `LiveEvent` the harness emits during turn loop execution. The harness writes; the host vacuums. `hive-c0re::events_vacuum` -runs hourly and sweeps every existing agent state dir, deleting +runs hourly and sweeps every existing agent harness dir, deleting rows older than 7 days. Age-only — no row cap — so a chatty turn doesn't lose history sooner than a quiet one; disk pressure on a sustained burst is the cheaper problem to have. Centralising @@ -82,12 +82,12 @@ retention on the host means a misbehaving harness can't disable its own vacuum and agents don't need any cleanup wiring of their own. -Path overridable via `HYPERHIVE_EVENTS_DB` (for dev / no-`/state` +Path overridable via `HYPERHIVE_EVENTS_DB` (for dev / no-`/harness` setups). On open failure the `Bus` falls back to no-store mode rather than crashing the harness — events still broadcast over SSE, just nothing persisted. -### `/state/hyperhive-turn-stats.sqlite` (per agent) +### `/harness/hyperhive-turn-stats.sqlite` (per agent) Per-turn analytics sink. One row per claude turn captures identity (`model`, `wake_from`, `result_kind`), timing @@ -149,7 +149,7 @@ Writes are best-effort: `append_stdout` / `append_stderr` / `finish` log a warning on sqlite error and let the build continue. A failed log row never blocks a rebuild. -### `/state/hyperhive-model` (per agent) +### `/harness/hyperhive-model` (per agent) Single-line text file holding the claude model name currently selected for this agent (default `haiku` when absent). Written by @@ -169,11 +169,10 @@ Under `/var/lib/hyperhive/agents//`: `/agents` tree bind. - `claude/` — claude OAuth credentials, bind-mounted RW to `/home//.claude` inside the container. -- `state/` — durable notes, the events.sqlite db, and the - turn-stats sqlite db. Bind-mounted to `/agents//state` - inside the container (uniform for sub-agents + manager). - The `$HYPERHIVE_STATE_DIR` env var exposes the same path to - in-container scripts. +- `state/` — durable notes and `hyperhive-harness.json`. Bind-mounted + to `/agents//state` inside the container (uniform for + sub-agents + manager). The `$HYPERHIVE_STATE_DIR` env var exposes + the same path to in-container scripts. - `harness/` — harness-internal ephemeral state; not intended for agent consumption. Bind-mounted to `/agents//harness` inside the container (`$HYPERHIVE_HARNESS_DIR`). Contents: @@ -184,8 +183,7 @@ Under `/var/lib/hyperhive/agents//`: inspecting with `bash_status`. - `hyperhive-events.sqlite` — turn-loop event log. - `hyperhive-turn-stats.sqlite` — per-turn timing stats. - - `hyperhive-harness.json` — consolidated flags (rate-limited, - model override, etc.) written atomically on each turn. + - `hyperhive-model` — single-line model name override file. Under `/var/lib/hyperhive/applied//` — the hive-c0re-only applied repo. Tracks `flake.nix` (module-only boilerplate; never @@ -219,7 +217,7 @@ step would re-fire). - `PURG3` (opt-in via the dashboard button or `hive-c0re destroy --purge `) — DESTR0Y plus wipes `/var/lib/hyperhive/{agents,applied}//`. Config history, - claude creds, /state/ notes, and the events db are all gone. + claude creds, /state/ notes, and the harness dir are all gone. No undo. The manager is non-destroyable from both paths (declarative From f3e4f10deaeadf38169786d2cb239899d8201d81 Mon Sep 17 00:00:00 2001 From: damocles Date: Mon, 1 Jun 2026 14:12:22 +0200 Subject: [PATCH 5/8] docs: fix stale /state/ paths in CLAUDE.md file map (harness-state split) --- CLAUDE.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 3adcb3d1..98080117 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -81,7 +81,7 @@ hive-c0re/ host daemon + sibling operator CLI (lib + 2 bins) fans out one Message per active target, re-arms recurring rows, deletes fired one-shots src/events_vacuum.rs host-side hourly sweep of every agent's - /state/hyperhive-events.sqlite + /harness/hyperhive-events.sqlite src/crash_watch.rs poll every 10s; fire HelperEvent::ContainerCrash when a previously-running container disappears without an operator-initiated transient (or a @@ -177,14 +177,14 @@ hive-ag3nt/ in-container harness crate; produces ONE `hive` /api/compact, /api/model, /events/history, /screen, /screen/ws) src/turn_stats.rs per-turn analytics sink (one sqlite row per - turn at /state/hyperhive-turn-stats.sqlite); + turn at /harness/hyperhive-turn-stats.sqlite); schema + best-effort writer src/stats.rs read-side aggregations over turn-stats.sqlite backing the /stats page (bucketed Snapshot: turns / duration / tokens / model mix) src/events.rs LiveEvent + broadcast Bus + sqlite-backed history - (/state/hyperhive-events.sqlite) + TurnState + - model selection (persisted at /state/hyperhive-model) + (/harness/hyperhive-events.sqlite) + TurnState + + model selection (persisted at /harness/hyperhive-model) src/turn.rs claude --print + stream-json pump; --compact retry; proactive compaction + auto session-reset src/mcp.rs embedded MCP server (rmcp): AgentServer + ManagerServer @@ -383,3 +383,4 @@ The docs below own the details — this section just points at them. window:** → [`docs/turn-loop.md`](docs/turn-loop.md). - **Two-step spawn, approval flow, flake.lock validation:** → [`docs/approvals.md`](docs/approvals.md). + From 5265af9589a05e4759d9d528b5bfed54d2e5d84b Mon Sep 17 00:00:00 2001 From: damocles Date: Mon, 1 Jun 2026 14:13:22 +0200 Subject: [PATCH 6/8] docs: drop false bash-tasks cleanup claim (argus nit) --- docs/persistence.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/persistence.md b/docs/persistence.md index 989b86bc..d9cecfde 100644 --- a/docs/persistence.md +++ b/docs/persistence.md @@ -179,8 +179,8 @@ Under `/var/lib/hyperhive/agents//`: - `bash-tasks/` — task JSON + stdout/stderr files for background `bash_run` jobs. JSON files are `.json` (status + tails), `.out` / `.err` - (full captured output). Cleaned up by the agent after - inspecting with `bash_status`. + (full captured output). Task files persist until container + purge. - `hyperhive-events.sqlite` — turn-loop event log. - `hyperhive-turn-stats.sqlite` — per-turn timing stats. - `hyperhive-model` — single-line model name override file. @@ -324,3 +324,4 @@ trigger from the `.path` watcher becomes a no-op. Setting it to `false` lets re-fires actually re-execute. The trade-off is the service unit shows `inactive (dead)` between fires — visible in `journalctl` but harmless; the `.path` unit drives the lifecycle. + From 601ac647b58028f771d97adde6b02086bcf0dc27 Mon Sep 17 00:00:00 2001 From: damocles Date: Mon, 1 Jun 2026 14:15:17 +0200 Subject: [PATCH 7/8] docs: fix stale /state/hyperhive-model path in turn-loop.md --- docs/turn-loop.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/turn-loop.md b/docs/turn-loop.md index 87df5583..696870c1 100644 --- a/docs/turn-loop.md +++ b/docs/turn-loop.md @@ -148,7 +148,7 @@ default is set by `hyperhive.model` in the agent's `agent.nix` (NixOS option; propagates via `HIVE_DEFAULT_MODEL` env var; falls back to `"haiku"` if unset). The operator can flip it at runtime with `/model ` in the web terminal — the next turn picks it -up. The choice is persisted to `/state/hyperhive-model` so it +up. The choice is persisted to `/harness/hyperhive-model` so it survives restart; override path: `HYPERHIVE_MODEL_FILE` env var for tests. @@ -587,3 +587,4 @@ The harness reads `/etc/hyperhive/bash-allow.json` and replaces Commands outside the pattern list require confirmation — which in `--print` mode means they will not run. An empty list (default) keeps the current wholesale `Bash` entry. + From 42a7d2eb0a3b581140de21dae152c367a1aabae7 Mon Sep 17 00:00:00 2001 From: damocles Date: Mon, 1 Jun 2026 14:37:05 +0200 Subject: [PATCH 8/8] docs: add tool_groups, limits, flake_check to CLAUDE.md file map --- CLAUDE.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 98080117..50fdfc7b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -130,6 +130,17 @@ hive-c0re/ host daemon + sibling operator CLI (lib + 2 bins) read). Reconciled by `meta::sync_agents`; operator/manager edits land via the eventual write API. + src/tool_groups.rs per-agent tool-group config — reads/writes + `/var/lib/hyperhive/meta/tool-groups.json`; + `set_groups` + `groups_for` + `remove_agent`. + Wired into `render_flake` for `HIVE_TOOL_GROUPS` + injection; operator write via dashboard action. + src/limits.rs wire-protocol size limits (inline body cap, + reminder spill threshold) shared across agent + + manager sockets. Single source of truth. + src/flake_check.rs pre-apply `flake.lock` validation — rejects + proposals missing `inputs..follows` wiring + (duplicate `original` node check). src/forge.rs optional Forgejo wiring: per-agent users + tokens, the `agent-configs` org (`push_config`), and meta read access; mirrors each applied repo @@ -384,3 +395,4 @@ The docs below own the details — this section just points at them. - **Two-step spawn, approval flow, flake.lock validation:** → [`docs/approvals.md`](docs/approvals.md). +