From 99752f81d9dc0f2b2ca6bfc67d3e3fa3d781ae2e Mon Sep 17 00:00:00 2001 From: atlas Date: Sun, 1 Nov 2026 22:49:01 +0100 Subject: [PATCH] remove the needs_update system event: nothing emits it Refs #5948 --- AGENTS.md | 2 +- docs/README.md | 2 +- docs/agent-lifecycle/config-changes.md | 43 ++++++++++---------------- docs/scheduler/coordinator.md | 2 +- docs/turn-loop/mcp.md | 10 ++---- hive-agent/prompts/system.md | 5 +-- hive-agent/src/main.rs | 15 ++------- hive-c0re/src/coordinator.rs | 7 ++--- hive-c0re/src/workers/crash_watch.rs | 2 +- hive-sh4re/README.md | 2 +- hive-sh4re/src/manager.rs | 18 ++--------- nix/reserved-names.nix | 5 +-- swarm-authelia-bridge/src/store.rs | 2 +- 13 files changed, 38 insertions(+), 77 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6635cadb..5d425bda 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -101,7 +101,7 @@ Per-hive (host + in-container): Wire types + socket plumbing: - **`hive-types/`** — leaf newtypes, chiefly the validated `Ident`. -- **`hive-sh4re/`** — shared payload types (`Message`, `HelperEvent`, …). +- **`hive-sh4re/`** — shared payload types (`Message`, …). - **`hive-host-sock/`** (hivectl ↔ c0re), **`hive-priv-sock/`** (c0re ↔ priv), **`hive-core-agent-sock/`** (harness ↔ c0re, `/run/hive/mcp.sock`) — per-socket wire types, split out so each client links only its protocol. diff --git a/docs/README.md b/docs/README.md index f801a1ca..16caa0e8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -27,7 +27,7 @@ declarations. - **How do config changes flow from manager to operator to container?** → [`agent-lifecycle/config-changes.md`](agent-lifecycle/config-changes.md) - (config PRs, the meta flake, helper events). + (config PRs, the meta flake, system messages). - **What state survives destroy / purge / restart?** → [`agent-lifecycle/persistence.md`](agent-lifecycle/persistence.md). - **Who can do what to whom — the agent roster and privilege?** → diff --git a/docs/agent-lifecycle/config-changes.md b/docs/agent-lifecycle/config-changes.md index 7e2a391f..af161a4b 100644 --- a/docs/agent-lifecycle/config-changes.md +++ b/docs/agent-lifecycle/config-changes.md @@ -1,8 +1,8 @@ -# Config changes + helper events +# Config changes + system messages Config changes are pull requests on the agent's config repo, which an -operator merges on the forge; that merge deploys them. Helper events are -how agents stay informed about lifecycle changes that need a reaction. +operator merges on the forge; that merge deploys them. The "System messages" +section covers the plain-text `system` messages hive-c0re sends agents. ## For operators @@ -322,24 +322,17 @@ for the root agent. The root agent's role-specific behaviour comes from its AGENTS.md / agent-specific instructions, not the system prompt template. -## Helper events +## System messages -`hive_sh4re::manager::HelperEvent` is the wire type for an event urgent -enough to drive an immediate claude turn (delivered as a regular -`system` inbox message, same `recv` path as any other message). It -currently has one variant, `NeedsUpdate { agent }` (sub-agent's -recorded flake rev is stale, operator rebuilds from the dashboard) — -and nothing in the tree constructs it; this removal dropped the push path -(`Coordinator::notify_agent`) once its last caller -(`notify_manager`, used only for the crash event below) went away. -`HelperEvent` stays as the type for whatever comes along that -genuinely needs to interrupt an agent's turn loop, not because -anything live uses it today. +Hive-c0re has no typed event that drives an immediate claude turn. A +message from sender `system` is plain inbox text, and the harness logs it +(`log_system_event` in `hive-agent/src/main.rs`) without parsing the body. +Today hive-c0re sends two: the `/knowledge updated` broadcast +(`workers/knowledge.rs`) and the wake message for a graceful stop +(`Coordinator::kick_agent`). -**A previously running container crashing** used to be exactly that -case (`ContainerCrash`, routed to the root agent via -`Coordinator::notify_manager`) — it no longer drives any agent turn at -all. `crash_watch` now only `tracing::warn!`s `"container crash +**A previously running container crashing** drives no agent turn. +`crash_watch` only `tracing::warn!`s `"container crash detected"`; a swarm-level grafana alert matches that log line directly and pages the operator, with no agent (and no per-hive dashboard banner) in the loop. See @@ -348,18 +341,16 @@ banner) in the loop. See The remaining lower-urgency lifecycle notices — `Rebuilt`, `Killed`, `Destroyed`, `NeedsLogin`, `LoggedIn` — are "FYI, check when convenient" events with no reason to drive an immediate turn, so -they go out via `swarm_notices::notify` instead -of a `HelperEvent`: `subsystem = "core"`, `key = ":"`, -and a single free-text `summary` (`rebuilt_todo_summary` renders -`Rebuilt`'s `ok`/`note`/`sha`/`tag` fields into that string). +they go out via `swarm_notices::notify` instead: `subsystem = "core"`, +`key = ":"`, and a single free-text `summary` +(`rebuilt_todo_summary` renders `Rebuilt`'s `ok`/`note`/`sha`/`tag` +fields into that string). To add a new lifecycle notice: if it's "FYI, check when convenient," call `swarm_notices::notify` — no new wire type needed. If it needs to drive an immediate turn, decide first whether it actually needs an *agent* in the loop at all (the crash case above didn't, once a -swarm-level alert could carry the same signal) — only reach for a new -`HelperEvent` variant + `notify_agent`-equivalent call site + -`prompts/system.md` update when the answer is yes. +swarm-level alert could carry the same signal). ## Autoupdate on startup diff --git a/docs/scheduler/coordinator.md b/docs/scheduler/coordinator.md index 0b62fc7b..66381c83 100644 --- a/docs/scheduler/coordinator.md +++ b/docs/scheduler/coordinator.md @@ -519,7 +519,7 @@ config — all nspawn containers live in `machine.slice`. ## See also -- `docs/agent-lifecycle/config-changes.md` — config PRs, meta flake, helper events +- `docs/agent-lifecycle/config-changes.md` — config PRs, meta flake, system messages - `docs/agent-lifecycle/persistence.md` — SQLite schema, state-dir layout - `docs/process/conventions.md` — wire protocol, recipient sentinels - `docs/agent-lifecycle/agent-roster.md` — the agent roster and privilege diff --git a/docs/turn-loop/mcp.md b/docs/turn-loop/mcp.md index b8494168..86e33691 100644 --- a/docs/turn-loop/mcp.md +++ b/docs/turn-loop/mcp.md @@ -68,13 +68,9 @@ runs on the change. `ack_until(N)` to prevent re-pop. Acked rows never redeliver. Transient pings (sentinel id 0) have nothing to ack and show no marker. -**System messages** (from sender `system`): the broker delivers -`hive_sh4re::manager::HelperEvent` (one variant, `NeedsUpdate` — -declared, but no call site constructs it) as regular inbox messages -(same `recv` path; body is a JSON object with an `event` discriminant -field). A container crash used to be the other variant -(`ContainerCrash`, routed to `ruth`) but this tree no longer has that -path — a crash now only produces a log line + swarm-level grafana +**System messages** (from sender `system`): the broker delivers them as regular inbox +messages (same `recv` path). A container crash never reaches an +agent — it only produces a log line + swarm-level grafana alert, no agent turn at all (`docs/scheduler/observability.md`). Lifecycle transitions the job-queue scheduler or crash watcher drive directly — stop/kill, destroy, a flake-rev login or logout state change — reach diff --git a/hive-agent/prompts/system.md b/hive-agent/prompts/system.md index 262aa182..a3ea8fe2 100644 --- a/hive-agent/prompts/system.md +++ b/hive-agent/prompts/system.md @@ -22,10 +22,7 @@ You are built from the `{archetype}` archetype and have no config repo of your o Operator boundary: starting, stopping and rebuilding containers is the operator's — ask them when any agent needs one. _Creating_ a new agent is not something you can do from here — ask the operator, who creates agents at swarm level. The operator only signs off on changes; you run the day-to-day. -Messages from sender `system` are hyperhive helper events (JSON body, `event` field discriminates): `container_crash`, `needs_update`. Use these to react to lifecycle changes: - -- `needs_update` — agent's flake rev is stale. Ask the operator to rebuild it. -- `container_crash` — ask the operator to start it again; if it keeps crashing, say so with what you saw. +Messages from sender `system` are plain-text notices from hive-c0re, not peer messages. Two kinds today: a `/knowledge updated` broadcast (read the changed files in `/knowledge`), and the wake message for a graceful stop (check `/agents//state/` for your notes). A container crash sends you nothing; the operator is alerted separately. Lifecycle notices that don't need an immediate turn — a new agent spawned, a container rebuilt/killed/destroyed, or its login state changing — surface as todos instead of messages now. Call `get_loose_ends` to see them. diff --git a/hive-agent/src/main.rs b/hive-agent/src/main.rs index 00536983..ba59313d 100644 --- a/hive-agent/src/main.rs +++ b/hive-agent/src/main.rs @@ -107,7 +107,7 @@ use crate::turn_stats::TurnStats; use anyhow::Result; use clap::Parser; use hive_core_agent_sock::{Request, Response}; -use hive_sh4re::manager::{HelperEvent, SYSTEM_SENDER}; +use hive_sh4re::manager::SYSTEM_SENDER; use hive_sock_client::Retry; #[derive(Parser)] @@ -134,21 +134,12 @@ async fn main() -> Result<()> { // ---------- shared turn helpers ---------- /// Surface a `SYSTEM_SENDER` message in the live event bus + tracing -/// log. Both agents and the manager receive `HelperEvent` notifications -/// (just `NeedsUpdate`, now that a container crash is a log line instead -/// of a `ContainerCrash` event); the parse and log path is -/// identical. Quiet no-op when `from` isn't -/// `SYSTEM_SENDER`. +/// log. Quiet no-op when `from` isn't `SYSTEM_SENDER`. fn log_system_event(bus: &Bus, from: &str, body: &str) { if from != SYSTEM_SENDER { return; } - let parsed = serde_json::from_str::(body).ok(); - if let Some(event) = &parsed { - tracing::info!(?event, "helper event"); - } else { - tracing::info!(%from, %body, "system message"); - } + tracing::info!(%from, %body, "system message"); bus.emit(LiveEvent::Note { text: format!("[system] {body}"), }); diff --git a/hive-c0re/src/coordinator.rs b/hive-c0re/src/coordinator.rs index 8b4a81be..6ead7cb2 100644 --- a/hive-c0re/src/coordinator.rs +++ b/hive-c0re/src/coordinator.rs @@ -936,10 +936,9 @@ impl Coordinator { } /// `push_todo` summary text for a rebuild outcome, for -/// `job_queue::exec::run_emit_rebuilt`. Pure + independently testable, unlike -/// the old `HelperEvent::Rebuilt`'s separate `sha`/`tag` -/// fields — those become part of the summary text itself now, since a todo -/// carries one string, not a structured payload. +/// `job_queue::exec::run_emit_rebuilt`. Pure + independently testable; the +/// `sha`/`tag` fields are part of the summary text, since a todo carries one +/// string, not a structured payload. #[must_use] pub fn rebuilt_todo_summary( agent: &str, diff --git a/hive-c0re/src/workers/crash_watch.rs b/hive-c0re/src/workers/crash_watch.rs index 8c0f0393..2ee987e1 100644 --- a/hive-c0re/src/workers/crash_watch.rs +++ b/hive-c0re/src/workers/crash_watch.rs @@ -4,7 +4,7 @@ //! that line directly; see the module doc on [`emit_crash_transitions`]. //! Login-state transitions (`needs_login`/`logged_in`) publish onto //! `swarm_notices` instead. The `RECENT_TRANSIENT_GRACE` window: -//! `docs/agent-lifecycle/config-changes.md::Helper events`. +//! `docs/agent-lifecycle/config-changes.md::System messages`. use std::collections::HashSet; use std::sync::Arc; diff --git a/hive-sh4re/README.md b/hive-sh4re/README.md index f5bbd947..c2eaa55f 100644 --- a/hive-sh4re/README.md +++ b/hive-sh4re/README.md @@ -1,7 +1,7 @@ # hive-sh4re The **shared payload vocabulary** between `hive-c0re` and the in-container -harness — the common types (`Message`, `LooseEnd`, `HelperEvent`, …) +harness — the common types (`Message`, `LooseEnd`, …) that the per-socket wire protocols are built from. The request/response _envelopes_ themselves now live in the per-socket crates (below); this crate holds the payloads they carry. diff --git a/hive-sh4re/src/manager.rs b/hive-sh4re/src/manager.rs index 028c96aa..9798f36f 100644 --- a/hive-sh4re/src/manager.rs +++ b/hive-sh4re/src/manager.rs @@ -1,8 +1,6 @@ -//! Reserved recipient names/senders and the out-of-band `HelperEvent` -//! payload hive-c0re pushes into the manager's inbox. +//! Reserved recipient names and senders. use hive_types::Ident; -use serde::{Deserialize, Serialize}; /// Logical name of the human operator: the sender of operator-authored /// messages. Not a recipient — `send` to it fails with @@ -18,8 +16,7 @@ pub const OPERATOR_SEND_REFUSAL: &str = "send failed: `operator` is not a send r Without them there is no direct channel to the operator: they read your `set_status` \ line and turn output on the dashboard, and your logs."; -/// Sender hive-c0re uses for events it pushes into the manager's inbox. -/// Manager harness recognises this and parses the body as a `HelperEvent`. +/// Sender hive-c0re uses for messages it pushes into an agent's inbox. pub const SYSTEM_SENDER: &str = "system"; /// Parse `s` as a [`Ident`] for use as `Message.from`, falling back to @@ -41,17 +38,6 @@ pub fn trusted_sender(s: &str) -> Ident { .unwrap_or_else(|_| Ident::parse(SYSTEM_SENDER).expect("SYSTEM_SENDER is a valid Ident")) } -/// Out-of-band events the host-side daemon pushes to the manager's inbox. -/// Serialised as JSON in `Message::body` (sender = `SYSTEM_SENDER`). -/// Per-variant triggers + the optional `sha`/`tag` semantics live in -/// `docs/agent-lifecycle/config-changes.md::Helper events`. -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(tag = "event", rename_all = "snake_case")] -pub enum HelperEvent { - /// A sub-agent's recorded flake rev is stale relative to hyperhive. - NeedsUpdate { agent: String }, -} - #[cfg(test)] mod reserved_name_tests { use super::{OPERATOR_RECIPIENT, SYSTEM_SENDER}; diff --git a/nix/reserved-names.nix b/nix/reserved-names.nix index f08ff1cd..ad95f2aa 100644 --- a/nix/reserved-names.nix +++ b/nix/reserved-names.nix @@ -34,8 +34,9 @@ # (`{from: "operator", ...}`) and the fallback attribution for an answered # question. "operator" - # Helper events (`container_crash`, `needs_update`) — the sender an - # agent is told to treat as hyperhive itself rather than as a peer. + # The sender of plain-text notices from hive-c0re (knowledge updates, + # the graceful-stop wake) — an agent is told to treat it as hyperhive + # itself rather than as a peer. # `hive_sh4re::manager::SYSTEM_SENDER`. "system" # A due self-scheduled reminder arrives as its own sender, so a wake I asked diff --git a/swarm-authelia-bridge/src/store.rs b/swarm-authelia-bridge/src/store.rs index 046b3546..1d94bf40 100644 --- a/swarm-authelia-bridge/src/store.rs +++ b/swarm-authelia-bridge/src/store.rs @@ -66,7 +66,7 @@ pub struct User { /// rest are message *senders*, and they matter for a reason that is not /// cosmetic: the harness switches on the sender name, so an agent called /// `todo` would have its messages interpreted as todo-wakes and one called -/// `system` as helper events. That is a parse, not a display quirk. +/// `system` as hive-c0re notices. That is a parse, not a display quirk. /// /// Sorted so a reader can scan it; the lookup is a linear walk over eight /// short strings on a path that already reads a file off disk.