From 16ac84ca639265d459df1a907e73e1d0d876b15f Mon Sep 17 00:00:00 2001 From: damocles Date: Sun, 30 Aug 2026 03:02:31 +0200 Subject: [PATCH] docs/hive-c0re: fix ask/answer removal doc gaps argus caught on #3741 --- CLAUDE.md | 4 +-- README.md | 3 +- docs/approvals.md | 1 + docs/turn-loop/mcp.md | 41 +++++++++++----------------- hive-agent-mcp/src/mcp/render.rs | 2 +- hive-agent/src/reminder_timer.rs | 2 +- hive-c0re/README.md | 4 +-- hive-c0re/src/agent_config/limits.rs | 8 +++--- hive-c0re/src/loose_ends.rs | 19 ++++++------- hive-core-agent-sock/README.md | 2 +- 10 files changed, 37 insertions(+), 49 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index d1a69727..9b29051f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -32,7 +32,7 @@ hand-maintained per-file tree drifts out of sync with the code. user). `src/main.rs` is the `hive-c0re` binary — **daemon-only** (`serve` + the periodic vacuum/sweep loops); the operator CLI lives in the separate `hivectl` crate, which talks to the daemon over the host - admin socket. Owns the sqlite broker, approval + question + reminder + + admin socket. Owns the sqlite broker, approval + reminder + schedule queues, the meta flake, lifecycle (`nixos-container` shellouts), gateway / forge / matrix provisioning, per-container stats, and the axum operator dashboard (`dashboard.rs`). Largest crate. @@ -120,7 +120,7 @@ hand-maintained per-file tree drifts out of sync with the code. `forge_notify` are the built-in ones, but any user-configured MCP server can push todos here too, nothing restricts the `subsystem` set. Carries the loose-ends-v2 **todo** ops plus - harness-local reminders + questions. ⚠️ Distinct from + harness-local reminders. ⚠️ Distinct from `hive-core-agent-sock` above: **this socket never leaves the container** and `hive-c0re` is not in the path at all — no broker round-trip, no long-poll, no marker files. diff --git a/README.md b/README.md index f84d9096..8b5b5766 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,7 @@ durable identity, and stop them from eating production. hyperhive is the substrate. - identity = unix socket -- communication = sqlite-backed broker (`send` / `recv` / `ask` / - `answer` / `remind`) +- communication = sqlite-backed broker (`send` / `recv` / `remind`) - config = git (manager proposes, operator approves, deploys land as tagged commits) - blast radius = container diff --git a/docs/approvals.md b/docs/approvals.md index b3ddda62..5ed06c2c 100644 --- a/docs/approvals.md +++ b/docs/approvals.md @@ -629,6 +629,7 @@ root agent. Variants (`hive_sh4re::manager::HelperEvent`): - `NeedsUpdate { agent }` — sub-agent's recorded flake rev is stale. The root agent calls `update(name)` to rebuild — idempotent, no approval required. + The remaining lower-urgency lifecycle notices — `Rebuilt`, `Killed`, `Destroyed`, `NeedsLogin`, `LoggedIn`, `ConfigReady` — are "FYI, check when convenient" events with no reason to drive an immediate turn, so diff --git a/docs/turn-loop/mcp.md b/docs/turn-loop/mcp.md index 35d8b3bb..42026548 100644 --- a/docs/turn-loop/mcp.md +++ b/docs/turn-loop/mcp.md @@ -23,8 +23,7 @@ preset (`AGENT_DEFAULT`) includes `messaging`, `meta`, `inbox`, and ## Core tools (always available) **Messaging** (`messaging` group): `send(to, body, in_reply_to?)`, -`recv(max?)`, `ask(question, options?, multi?, -ttl_seconds?, to?)`, `answer(id, answer)`, `ack_until(up_to)`. +`recv(max?)`, `ack_until(up_to)`. - `send` — message a peer (logical name) or the operator (`to: "operator"`). Use `to: ""` to address the topology @@ -48,13 +47,6 @@ ttl_seconds?, to?)`, `answer(id, answer)`, `ack_until(up_to)`. other turn: if the context crossed the watermark the harness runs a notes-checkpoint turn and then `/compact`. Compacting before shutdown keeps a later cold start cheap instead of re-uploading a huge transcript. -- `ask` — surface a structured question to the operator (default) or - a peer agent (`to: ""`). Non-blocking — returns a question - id; the answer arrives as a `question_answered` system event in the - asker's inbox. `options` is advisory; `multi=true` renders as - checkboxes; `ttl_seconds` auto-cancels with answer `[expired]`. -- `answer` — respond to a `question_asked` event routed to this - agent. Strict authorisation: only the declared target can answer. - `ack_until(up_to)` — bulk-mark inbox rows handled: every row with broker id `<= up_to` is stamped as acked in a single UPDATE. Recipient-scoped (agents can only ack their own rows). Use when a @@ -64,14 +56,12 @@ ttl_seconds?, to?)`, `answer(id, answer)`, `ack_until(up_to)`. Transient pings (sentinel id 0) have nothing to ack and show no marker. **System messages** (from sender `system`): the higher-urgency -lifecycle + Q&A events (`hive_sh4re::manager::HelperEvent`) are +lifecycle events (`hive_sh4re::manager::HelperEvent`) are delivered as regular inbox messages (same `recv` path; body is a JSON object with an `event` discriminant field). The **submitting agent** (the root agent for top-level containers; an agent with the `approvals` tool group for its own subtree) receives `container_crash`, -`needs_update`, and `approval_resolved` this way. Any agent receives -Q&A events when it is the declared target (`question_asked`) or the -asker (`question_answered`). The remaining, lower-urgency lifecycle +`needs_update`, and `approval_resolved` this way. The remaining, lower-urgency lifecycle notices — `spawned`, `rebuilt`, `killed`, `destroyed`, `needs_login`, `logged_in`, `config_ready` — skip the inbox entirely: they land as todos on the submitting agent's in-container todo socket instead @@ -86,18 +76,19 @@ payload shapes and routing logic in `cancel_loose_end(kind, id)`, `remind(message, delay_seconds? | at_unix_timestamp?)`. -- `get_loose_ends(agent?)` — list pending questions (asked/owed), - scheduled reminders, and active local tasks published by external MCP - daemons (e.g. running bash tasks from `hive-bash-daemon`). Each row - carries an id + kind for `cancel_loose_end`. Omit `agent` to list - your own threads. Pass `agent: ""` to inspect a direct child - agent (always accessible per topology enforcement); non-children - require the `query_agent_state` capability. The `"*"` hive-wide - query is not available on the agent socket. -- `cancel_loose_end` — withdraw a `question` (posts `[cancelled by - ]`), hard-delete a `reminder`, or cancel a pending `approval` - row. Agents may only cancel rows they own; the `approval` kind is - further restricted to the root agent (`ruth`) server-side. +- `get_loose_ends(agent?)` — list scheduled reminders, pending + approvals you submitted, and active local tasks published by + external MCP daemons (e.g. running bash tasks from + `hive-bash-daemon`). Each row carries an id + kind for + `cancel_loose_end`. Omit `agent` to list your own threads. Pass + `agent: ""` to inspect a direct child agent (always accessible + per topology enforcement); non-children require the + `query_agent_state` capability. The `"*"` hive-wide query is not + available on the agent socket. +- `cancel_loose_end` — hard-delete a `reminder`, cancel a pending + `approval` row, or clear a `todo` row (loose-ends-v2). Agents may + only cancel rows they own; the `approval` kind is further restricted + to the root agent (`ruth`) server-side. - `remind` — schedule a reminder in this agent's own inbox. Large payloads spill to `/agents//state/reminders/`. Pending count capped at 50 per agent (`HIVE_REMIND_MAX_PENDING_PER_AGENT`). diff --git a/hive-agent-mcp/src/mcp/render.rs b/hive-agent-mcp/src/mcp/render.rs index 39e3f7f8..7656c0a8 100644 --- a/hive-agent-mcp/src/mcp/render.rs +++ b/hive-agent-mcp/src/mcp/render.rs @@ -152,7 +152,7 @@ fn msg_id_tag(id: i64) -> String { } /// Hard cap on how many individual `Todo` lines `render_loose_ends` will -/// emit. Approvals/questions/reminders stay naturally bounded (they're +/// emit. Approvals/reminders stay naturally bounded (they're /// triaged interactively and don't self-multiply), but todos are pushed by /// unattended producers — matrix/bash/forge are the built-in ones, but any /// user-configured MCP server can push its own too — an agent that goes a long diff --git a/hive-agent/src/reminder_timer.rs b/hive-agent/src/reminder_timer.rs index 394a5a3d..0b561136 100644 --- a/hive-agent/src/reminder_timer.rs +++ b/hive-agent/src/reminder_timer.rs @@ -33,7 +33,7 @@ const REMINDER_BATCH_LIMIT: u64 = 100; /// Poll interval — matches the old c0re `POLL_INTERVAL`. const POLL_INTERVAL: Duration = Duration::from_secs(5); -/// Same cap the broker used to enforce on `send`/`ask`/`remind` bodies +/// Same cap the broker enforces on `send`/`remind` bodies /// (`hive-c0re`'s `agent_config::limits::MESSAGE_MAX_BYTES`, not /// reachable from here — hive-agent doesn't depend on hive-c0re). /// Duplicated rather than shared: this is the last remaining reminder diff --git a/hive-c0re/README.md b/hive-c0re/README.md index 4b6e6e7d..28328d29 100644 --- a/hive-c0re/README.md +++ b/hive-c0re/README.md @@ -1,7 +1,7 @@ # hive-c0re The unprivileged host daemon (runs as `hive-core`). Owns the sqlite -broker, the approval/question/schedule queues, the generic job-DAG +broker, the approval/reminder/schedule queues, the generic job-DAG queue, container lifecycle, gateway/forge/matrix provisioning, per-container stats, and the axum operator dashboard. Largest crate in the workspace — bin-only, no separate lib. @@ -24,7 +24,7 @@ module's own `//!` doc-comment for real detail, don't expect this file to track it: - **`dashboard/`** — the operator dashboard (containers, approvals, - schedules, questions, logs, topology). + schedules, logs, topology). - **`job_queue/`** — the job-DAG queue + desired-state reconciliation (`docs/coordinator.md`). - **`lifecycle/`** — `nixos-container` lifecycle + per-agent config diff --git a/hive-c0re/src/agent_config/limits.rs b/hive-c0re/src/agent_config/limits.rs index 723fc58f..ae2ad299 100644 --- a/hive-c0re/src/agent_config/limits.rs +++ b/hive-c0re/src/agent_config/limits.rs @@ -10,8 +10,8 @@ //! about it — oversized reminder bodies get persisted to disk //! transparently and the inbox sees a pointer. -/// Per-message body cap. Applies to `send`, `ask` question text, -/// `answer` body, and the stored inline form of a reminder. 4 KiB +/// Per-message body cap. Applies to `send` bodies and the stored +/// inline form of a reminder. 4 KiB /// catches the bulk of conversational overflow (status reports, /// bullet-list summaries, short proposals) while staying small /// enough that a backed-up inbox of ~10 unread messages only adds @@ -112,8 +112,8 @@ mod tests { #[test] fn label_threads_through() { - let err = check_size("question", &"x".repeat(MESSAGE_MAX_BYTES + 1)).unwrap_err(); - assert!(err.starts_with("question body too long")); + let err = check_size("broadcast", &"x".repeat(MESSAGE_MAX_BYTES + 1)).unwrap_err(); + assert!(err.starts_with("broadcast body too long")); } #[test] diff --git a/hive-c0re/src/loose_ends.rs b/hive-c0re/src/loose_ends.rs index f521fab1..feb67481 100644 --- a/hive-c0re/src/loose_ends.rs +++ b/hive-c0re/src/loose_ends.rs @@ -2,17 +2,14 @@ //! assembles a `Vec` for either a single agent (`for_agent`) or //! the whole hive (`hive_wide`). `Request::GetLooseEnds` from either the //! agent or manager socket lands here so the routing logic + age-seconds -//! derivation stay in one place. Reminders AND questions are agent-local -//! (in-container stores, `hive-agent::reminders` / `hive-agent::questions`) -//! and no longer sourced from here (loose-ends-v2's questions phase) — -//! c0re remains the `Ask`/`Answer` routing + delivery rendezvous -//! (`coord.questions`), it just isn't asked for the *pending-view* -//! rendering anymore. ⚠️ The operator dashboard no longer has any -//! question-pending view either — its whole questions pane, the -//! `pending_all()`/`recent_answered_all()` reads that fed it, and the -//! `/api/answer-question`/`/api/cancel-question` endpoints are gone -//! (removed along with the rest of the dashboard's ask/answer surface). -//! An operator-targeted `ask()` now has no reader anywhere. +//! derivation stay in one place. Reminders are agent-local (in-container +//! `hive-agent::reminders` store) and never sourced from here. The +//! `ask`/`answer` MCP tools, their wire protocol (`hive-c0re::questions`, +//! `stores::operator_questions`), and the operator dashboard's questions +//! pane have all been removed entirely — this file never had a +//! `Question` loose-end path to begin with (it only ever emitted +//! `PendingMessages`/`Approval`), so nothing here changed shape when +//! that removal landed. //! //! Call frequency is low (an agent doing self-introspection between //! turns), so the sweep happens fresh every time — no caching, no diff --git a/hive-core-agent-sock/README.md b/hive-core-agent-sock/README.md index afa130a3..2032d46b 100644 --- a/hive-core-agent-sock/README.md +++ b/hive-core-agent-sock/README.md @@ -15,7 +15,7 @@ for this socket. ## Not to be confused with `hive-agent-sock` This is the **host-served** protocol: the harness talks *out* to `hive-c0re` -over `/run/hive/mcp.sock` (broker sends, approvals, questions, lifecycle). +over `/run/hive/mcp.sock` (broker sends, approvals, lifecycle). `hive-agent-sock` is the separate *in-container* socket the harness serves to its own local producers — that one never leaves the container. See `docs/boundary.md` for the socket topology.