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()