From c6af5a2abff1bf2ab1f58a8becb46ea5fd11f892 Mon Sep 17 00:00:00 2001 From: iris Date: Mon, 3 Aug 2026 12:48:37 +0200 Subject: [PATCH 1/4] docs: trim impl detail out of the top-level README Per mara on hyperhive#1898: the top-level README should not go into details about impl details or specific subsystems. Trims the Multi-account Matrix support and GitHub account sections down to a one-line pointer each. The matrixAccounts option detail that was only ever documented in the README (checked: docs/matrix.md is entirely about the host hive-matrix container, not this per-agent option) moves to docs/tools/matrix.md instead, next to the account parameter every matrix tool already takes - the natural home, not a link to a page that never covered it. --- README.md | 45 +++++++++----------------------------------- docs/tools/matrix.md | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index f069ea8c..4e0a87c0 100644 --- a/README.md +++ b/README.md @@ -105,43 +105,16 @@ For the full list of host and agent NixOS options see the ## Agent configuration -Per-agent config lives in each agent's `agent.nix` (proposed, operator-approved, deployed as git commits). Key options: +Per-agent config lives in each agent's `agent.nix` (proposed, operator-approved, deployed as git commits). Two accounts an agent can hold, both provisioned mostly outside of nix: -### Multi-account Matrix support - -`hyperhive.matrixAccounts` declares _additional_ matrix accounts for an agent, beyond the hive-internal one. Each entry is keyed by account name and specifies: - -- `tokenFile` — path to the matrix bearer token (provisioned out-of-band) -- `sessionDir` — path to the per-account matrix-sdk sqlite state (crypto keys + cache) -- `homeserver` — optional homeserver URL (defaults to `hyperhive.matrix.url`) - -**Example:** - -```nix -hyperhive.matrixAccounts = { - external-public = { - tokenFile = "/agents/myagent/state/matrix-token-external"; - sessionDir = "/agents/myagent/state/matrix-sdk-state-external"; - homeserver = "https://matrix.org"; - }; -}; -``` - -The hive-internal account is always named `main` (synthesized from `hyperhive.matrix.url` + agent state). This option only declares _extras_; the `main` name is reserved and cannot be used here. Requires `hyperhive.matrix.enable = true`. - -For more details see [`docs/matrix.md`](docs/matrix.md). - -### GitHub account - -Every agent gets a managed GitHub identity — a `gh` CLI wrapper and `git push` over HTTPS — on by default (`hyperhive.github.enable`), inert until a PAT is provisioned. There is nothing per-agent to declare: paste an operator-supplied personal access token into the agent's dashboard **credentials** tab (or `hivectl github set-token --token-stdin`) and it works. The `gh` wrapper + git credential helper read the token live (git auths as `x-access-token` + the PAT; github.com only), so a rotated PAT takes effect with no rebuild. - -Turn the integration off for the whole hive with the host option: - -```nix -services.hyperhive.github.enable = false; -``` - -The PAT value is never in nix — only the enable flag. For more details see [`docs/github.md`](docs/github.md). +- **A second Matrix identity**, beyond the hive-internal one (e.g. an + external-facing account alongside the internal one) — see + [`docs/tools/matrix.md`](docs/tools/matrix.md) for the + `hyperhive.matrixAccounts` option and setup. +- **A managed GitHub identity** (`gh` CLI + `git push` over HTTPS) — on + by default, provisioned by pasting a PAT into the agent's dashboard + credentials tab, nothing to declare in nix. See + [`docs/github.md`](docs/github.md) for setup and the disable flag. ## Operator CLI diff --git a/docs/tools/matrix.md b/docs/tools/matrix.md index 014274c7..896e742b 100644 --- a/docs/tools/matrix.md +++ b/docs/tools/matrix.md @@ -67,6 +67,23 @@ room you haven't read yet. - `mark_read(room, event_id)` — advance the read receipt +## Multiple accounts + +`hyperhive.matrixAccounts` (declared in `agent.nix`) gives an agent +*additional* matrix identities beyond the hive-internal one — e.g. an +external-facing account alongside the internal one. Each entry is +keyed by account name and specifies `tokenFile` (bearer token, +provisioned out-of-band; basename must start with `matrix-token`), +`sessionDir` (per-account matrix-sdk sqlite state — crypto keys + +cache), and an optional `homeserver` (defaults to +`hyperhive.matrix.url`). The hive-internal account is always named +`main`, synthesized from `hyperhive.matrix.url` + agent state — this +option only declares extras, and `main` is a reserved key here. +Requires `hyperhive.matrix.enable = true`. + +Every matrix tool above takes an optional `account` parameter (a name +from this map) to act as that identity instead of the primary one. + ## Architecture `hive-matrix-daemon` is a single long-running process (one per agent From 04b274753b8aac48aab6c78db74d7ac047df4dfd Mon Sep 17 00:00:00 2001 From: iris Date: Mon, 3 Aug 2026 12:55:18 +0200 Subject: [PATCH 2/4] docs: give turn-loop/ a README.md landing page Part of hyperhive#1898 (b): every docs subdir should have a top-level README.md link, achieved by moving/renaming where an existing file already fits the role. docs/turn-loop.md already served as the hub + index for the three sub-pages under turn-loop/ (claude-invocation.md, config.md, mcp.md), so it moves wholesale rather than leaving a redundant top-level pointer stub. Fixes every inbound/relative link across the repo (top-level README.md, CLAUDE.md, docs/persistence.md, docs/tools/scheduling.md, the sub-pages own back-link, hive-agent README + doc comments, hive-agent/Cargo.toml, .prettierignore per-file exemption entry) - grepped the whole tree for both turn-loop.md and turn-loop/ to find every reference rather than trusting a partial list. nix fmt clean, cargo check -p hive-agent clean. --- .prettierignore | 2 +- CLAUDE.md | 4 ++-- README.md | 2 +- docs/persistence.md | 2 +- docs/tools/scheduling.md | 2 +- docs/{turn-loop.md => turn-loop/README.md} | 16 ++++++++-------- docs/turn-loop/claude-invocation.md | 2 +- hive-agent/Cargo.toml | 2 +- hive-agent/README.md | 4 ++-- hive-agent/src/login.rs | 2 +- hive-agent/src/main.rs | 4 ++-- 11 files changed, 21 insertions(+), 21 deletions(-) rename docs/{turn-loop.md => turn-loop/README.md} (93%) diff --git a/.prettierignore b/.prettierignore index 0baa578a..8c27f02e 100644 --- a/.prettierignore +++ b/.prettierignore @@ -16,6 +16,6 @@ docs/persistence.md docs/terminal-rendering.md docs/tools/forge.md docs/tools/matrix.md -docs/turn-loop.md +docs/turn-loop/README.md docs/web-ui/agent.md docs/web-ui/dashboard.md diff --git a/CLAUDE.md b/CLAUDE.md index 20201153..dd5c38a6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -179,7 +179,7 @@ read them à la carte. - **"How does the per-agent terminal classify + colour events?"** → [`docs/terminal-rendering.md`](docs/terminal-rendering.md). - **"How does claude get its prompt and what tools does it have?"** → - [`docs/turn-loop.md`](docs/turn-loop.md) (index: the loop, binary shape, + [`docs/turn-loop/`](docs/turn-loop/README.md) (index: the loop, binary shape, turn outcomes; sub-pages: [`claude-invocation`](docs/turn-loop/claude-invocation.md), [`config`](docs/turn-loop/config.md), [`mcp`](docs/turn-loop/mcp.md)). @@ -239,7 +239,7 @@ The docs below own the details — this section just points at them. - **NixOS / nspawn quirks** (bind mounts, conf flags, etc.): → [`docs/gotchas.md`](docs/gotchas.md). - **Turn loop, sentinels (rate-limit, auth-failed), context - window:** → [`docs/turn-loop.md`](docs/turn-loop.md). + window:** → [`docs/turn-loop/`](docs/turn-loop/README.md). - **Two-step spawn, approval flow, flake.lock validation:** → [`docs/approvals.md`](docs/approvals.md). - **Pre-push lint hook** (catches tracker-tag and comment-block failures diff --git a/README.md b/README.md index 4e0a87c0..897251c0 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Depth lives in [`docs/`](docs/) — pick the one matching your task: | reading path | doc | | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | dashboard layout + endpoints | [`docs/web-ui.md`](docs/web-ui.md) ([shape](docs/web-ui/shape.md) · [dashboard](docs/web-ui/dashboard.md) · [agent](docs/web-ui/agent.md)) | -| claude turn loop + MCP tools | [`docs/turn-loop.md`](docs/turn-loop.md) | +| claude turn loop + MCP tools | [`docs/turn-loop/`](docs/turn-loop/README.md) | | config-edit + approval state machine | [`docs/approvals.md`](docs/approvals.md) | | what survives destroy / purge / restart | [`docs/persistence.md`](docs/persistence.md) | | naming, wire protocol, commit style | [`docs/conventions.md`](docs/conventions.md) | diff --git a/docs/persistence.md b/docs/persistence.md index 4d138404..7f3030eb 100644 --- a/docs/persistence.md +++ b/docs/persistence.md @@ -239,7 +239,7 @@ Survives destroy/recreate, gone on `--purge`. Empty marker file. Its presence parks the agent's turn loop: the harness keeps serving its web UI and MCP daemons but drives no turns, and inbox messages queue unacked until it's removed (see -[turn loop](turn-loop.md#the-loop)). +[turn loop](turn-loop/README.md#the-loop)). Unusually, it's read and written from **both** sides of the harness bind-mount, and that's the whole design: the harness stats it diff --git a/docs/tools/scheduling.md b/docs/tools/scheduling.md index 9d92a2ca..1b02918c 100644 --- a/docs/tools/scheduling.md +++ b/docs/tools/scheduling.md @@ -89,6 +89,6 @@ lifecycle events, or another container's boot log. ## See also - `remind` (no-approval self-wake path) — documented in - [`docs/turn-loop.md`](../turn-loop.md). + [`docs/turn-loop/`](../turn-loop/README.md). - [`docs/approvals.md`](../approvals.md) — approval flow for `request_schedule_prompt`. diff --git a/docs/turn-loop.md b/docs/turn-loop/README.md similarity index 93% rename from docs/turn-loop.md rename to docs/turn-loop/README.md index 6e5bf6ea..d73a2b42 100644 --- a/docs/turn-loop.md +++ b/docs/turn-loop/README.md @@ -14,7 +14,7 @@ agents) runs: queued and unacked, so a resume drains the backlog instead of losing it; reminders and todo wakes buffer in their channels. Set it with `hivectl agent pause` or the dashboard toggle; see - [persistence](persistence.md#-harnesspaused-per-agent). + [persistence](../persistence.md#-harnesspaused-per-agent). 1. Long-poll `Recv` on its socket. The host-side broker (`broker.rs::recv_blocking_batch`) returns immediately if there's a pending message, otherwise waits up to 30 s for a broker `Sent` @@ -31,7 +31,7 @@ agents) runs: hard failure. The outcome drives the post-turn action (see [Turn outcomes](#turn-outcomes)); compaction is handled inside the session (see - [Compaction](turn-loop/claude-invocation.md#compaction)). Rate-limit + [Compaction](claude-invocation.md#compaction)). Rate-limit and auth-failure detection is described [below](#failure-detection-and-login). 7. Emit `LiveEvent::TurnEnd { ok, note }`. Sleep `poll_ms` to avoid tight loops on transient failures. @@ -94,12 +94,12 @@ loop (`serve_loop` / `handle_turn`) has no per-role branches. flake sets it unconditionally for any container-deployed agent; see `docs/conventions.md::Hive identity` for the env stack), opens turn-stats sqlite, prepares the on-boot files (see -[claude-invocation](turn-loop/claude-invocation.md#on-boot-files)), +[claude-invocation](claude-invocation.md#on-boot-files)), installs claude plugins, spawns `web_ui::serve` + `vacuum::run`, and either drops into `serve_loop` directly (`Online`) or parks on the login flow first (`NeedsLogin`). (The forge notification poller used to be spawned here too; it is its own process now — -`hive-forge-notify`, see [`forge.md`](forge.md).) +`hive-forge-notify`, see [`forge.md`](../forge.md).) `spawn_todo_socket` opens the todos store and, alongside `todo_server::run` (the socket the out-of-process producers dial), @@ -153,17 +153,17 @@ harness between turns. ## Sub-pages -The rest lives in three topic pages under [`turn-loop/`](turn-loop/): +The rest lives alongside this page, in three topic files: -- **[claude-invocation.md](turn-loop/claude-invocation.md)** — how the harness +- **[claude-invocation.md](claude-invocation.md)** — how the harness spawns `claude --print` each turn, the two-pronged compaction (reactive + proactive), and the on-boot files it materialises (`--mcp-config`, `--system-prompt-file`). -- **[config.md](turn-loop/config.md)** — the optional per-agent knobs the meta +- **[config.md](config.md)** — the optional per-agent knobs the meta flake wires in (reference docs, icon, passwordless sudo, dashboard links, custom static files, connectivity overrides, claude plugins, cargo message filtering). -- **[mcp.md](turn-loop/mcp.md)** — the MCP tool surface claude sees: core tools, +- **[mcp.md](mcp.md)** — the MCP tool surface claude sees: core tools, privileged tool groups, self-wake, authoritative state, the tool envelope, and the built-in tool whitelist. diff --git a/docs/turn-loop/claude-invocation.md b/docs/turn-loop/claude-invocation.md index b9d2f26c..f5b3df9a 100644 --- a/docs/turn-loop/claude-invocation.md +++ b/docs/turn-loop/claude-invocation.md @@ -116,7 +116,7 @@ window with two triggers baked into its `run`: *still* overflows, `run` surfaces `Error::PromptTooLong`; `drive_turn` then archives the session (session lifecycle stays hive-side) and the serve loop requeues the message so it redelivers into a fresh session - (see [Turn outcomes](../turn-loop.md#turn-outcomes) — the wake prompt itself is tiny, so + (see [Turn outcomes](README.md#turn-outcomes) — the wake prompt itself is tiny, so the overflow was the accumulated context the archive clears). - **Proactive** — a turn finishes cleanly but the last inference's context size crossed the policy watermark. While the session is still healthy it diff --git a/hive-agent/Cargo.toml b/hive-agent/Cargo.toml index a4029b5c..3b6ffff4 100644 --- a/hive-agent/Cargo.toml +++ b/hive-agent/Cargo.toml @@ -41,4 +41,4 @@ tempfile = "3" # The sibling MCP server is its own bin crate now (`hive-agent-mcp`). # Privilege boundary is enforced server-side at the socket (tool # groups / manager surface). -# See `docs/turn-loop.md::Harness binary shape`. +# See `docs/turn-loop/README.md::Harness binary shape`. diff --git a/hive-agent/README.md b/hive-agent/README.md index 05f7406d..2fadfb8f 100644 --- a/hive-agent/README.md +++ b/hive-agent/README.md @@ -15,7 +15,7 @@ understand or change: what happens between "a message lands in the inbox" and "claude produces a reply", how login/auth is bootstrapped, how the per-agent web UI is served, or how turn/event stats get recorded. Architecture detail lives in -[`docs/turn-loop.md`](../docs/turn-loop.md); this README is just the +[`docs/turn-loop/`](../docs/turn-loop/README.md); this README is just the map of the module tree. ## Shape @@ -48,4 +48,4 @@ map of the module tree. Sibling: **`hive-agent-mcp`** (the MCP server this loop points claude at every turn). Both are described together in -[`docs/turn-loop.md::Harness binary shape`](../docs/turn-loop.md). +[`docs/turn-loop/::Harness binary shape`](../docs/turn-loop/README.md). diff --git a/hive-agent/src/login.rs b/hive-agent/src/login.rs index f5302e77..b6f028a8 100644 --- a/hive-agent/src/login.rs +++ b/hive-agent/src/login.rs @@ -118,7 +118,7 @@ impl LoginState { /// infinite-401 loop a bare-existence check would produce when stale /// credentials are already on disk. Mtime-snapshot resumption rationale /// and `DirSnapshot` two-axis design: see -/// [`docs/turn-loop.md::The loop`](../../docs/turn-loop.md). +/// [`docs/turn-loop/::The loop`](../../docs/turn-loop/README.md). /// /// # Panics /// diff --git a/hive-agent/src/main.rs b/hive-agent/src/main.rs index 8ac8460e..7ac23fe9 100644 --- a/hive-agent/src/main.rs +++ b/hive-agent/src/main.rs @@ -4,7 +4,7 @@ //! generic and testable. Sibling: `hive-agent-mcp` (the MCP server this //! loop points claude at). //! Architecture lives in -//! [`docs/turn-loop.md::Harness binary shape`](../../../docs/turn-loop.md). +//! [`docs/turn-loop/::Harness binary shape`](../../../docs/turn-loop/README.md). //! //! Single bin crate: the module tree below (formerly this crate's `lib.rs`, //! before lib + bin were collapsed into one) plus the serve loop. @@ -510,7 +510,7 @@ fn spawn_todo_socket( /// Boot — wires up the web UI, login state, stats, plugins, forge /// notifier, and either drops into `serve_loop` directly (`Online`) or /// parks on the login flow first (`NeedsLogin`). See -/// `docs/turn-loop.md::Boot wiring`. +/// `docs/turn-loop/README.md::Boot wiring`. async fn serve_main(socket: &Path, poll_ms: u64) -> Result<()> { let port = std::env::var("HIVE_PORT") .ok() From 3993f635d52716a93a0569032429c1e640be4783 Mon Sep 17 00:00:00 2001 From: iris Date: Mon, 3 Aug 2026 12:57:00 +0200 Subject: [PATCH 3/4] docs: add tools/ landing page Part of hyperhive#1898 (b), the other missing docs subdir. Unlike turn-loop/ this one has no single existing file that already covers the whole directory - hivectl.md/hivectl-cli.md are genuinely operator-facing (the operator's own host CLI), while bash.md/forge.md/ lifecycle.md/matrix.md/scheduling.md document the agents' own MCP tool surface (a different audience: what the agent can do, not what the operator does). Writes a new README.md rather than moving one, splitting the link list along that line so the operator-relevant half leads. --- docs/tools/README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 docs/tools/README.md diff --git a/docs/tools/README.md b/docs/tools/README.md new file mode 100644 index 00000000..67d988eb --- /dev/null +++ b/docs/tools/README.md @@ -0,0 +1,33 @@ +# Tools + +`hivectl` is *your* tool — the operator's own host CLI. Everything +else here documents the tool surface your **agents** get inside their +containers (the MCP tools an agent's own claude session can call). +You never call these directly, but they're the reference for what an +agent can actually do — useful when you're trying to understand or +debug agent behavior. + +## For the operator + +- **[hivectl](hivectl.md)** — the curated guide: provisioning forge + and matrix accounts, gateway htpasswd management, container + lifecycle shortcuts, interactive agent shell access. +- **[hivectl-cli](hivectl-cli.md)** — the exhaustive, auto-generated + flag-by-flag reference, kept in lockstep with the binary by CI. + +## What your agents can do + +- **[bash](bash.md)** — background shell execution (`mcp__bash__*`), + available on every agent unconditionally. +- **[forge](forge.md)** — the `hive-forge` Forgejo CLI every agent has + for issues, PRs, and comments. Not an MCP tool — a binary agents + shell out to instead of ad-hoc curl. +- **[lifecycle](lifecycle.md)** — kill/start/restart/update for an + agent's own direct children, plus the approval-gated config-change + tools. +- **[matrix](matrix.md)** — the matrix MCP tool surface + (`mcp__matrix__*`) for agents with a matrix account, multiple + accounts per agent, and declaring extra MCP servers generally. +- **[scheduling](scheduling.md)** — scheduled prompts (operator + approval required) and the diagnostics tools (`get_logs`, + `get_host_journal`). From 6809c782a30ad296eeaae22196eaa873035eb2d7 Mon Sep 17 00:00:00 2001 From: iris Date: Mon, 3 Aug 2026 12:59:28 +0200 Subject: [PATCH 4/4] docs: actually remove the Agent configuration section, not trim it Missed mara'\''s reply on this PR before pushing two more commits on top - she said remove, my first commit trimmed to two bullets, which is still going into Matrix/GitHub as named subsystems. Deletes the section outright; the two docs it pointed at (docs/tools/matrix.md, docs/github.md) are still reachable from CLAUDE.md's reading path and from docs/tools/README.md, just not named in the top-level README. --- README.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/README.md b/README.md index 897251c0..41afa1aa 100644 --- a/README.md +++ b/README.md @@ -103,19 +103,6 @@ older/newer channel hits breakage hyperhive's CI doesn't catch. For the full list of host and agent NixOS options see the **[options reference](https://hyperhive.darkest.space/options/)**. -## Agent configuration - -Per-agent config lives in each agent's `agent.nix` (proposed, operator-approved, deployed as git commits). Two accounts an agent can hold, both provisioned mostly outside of nix: - -- **A second Matrix identity**, beyond the hive-internal one (e.g. an - external-facing account alongside the internal one) — see - [`docs/tools/matrix.md`](docs/tools/matrix.md) for the - `hyperhive.matrixAccounts` option and setup. -- **A managed GitHub identity** (`gh` CLI + `git push` over HTTPS) — on - by default, provisioned by pasting a PAT into the agent's dashboard - credentials tab, nothing to declare in nix. See - [`docs/github.md`](docs/github.md) for setup and the disable flag. - ## Operator CLI `hivectl` is the operator-facing host CLI for ad-hoc administration that