docs/hive-c0re: fix ask/answer removal doc gaps argus caught on #3741

This commit is contained in:
damocles 2026-08-30 03:02:31 +02:00
commit 16ac84ca63
10 changed files with 37 additions and 49 deletions

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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: "<parent>"` 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: "<agent>"`). 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: "<name>"` 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
<self>]`), 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: "<name>"` 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/<self>/state/reminders/`. Pending count
capped at 50 per agent (`HIVE_REMIND_MAX_PENDING_PER_AGENT`).

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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]

View file

@ -2,17 +2,14 @@
//! assembles a `Vec<LooseEnd>` 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

View file

@ -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.