Watch
0
0
Fork
You've already forked hyperhive
0

remove the needs_update system event: nothing emits it

Refs #5948
This commit is contained in:
atlas 2026-11-01 22:49:01 +01:00
commit 99752f81d9
13 changed files with 40 additions and 79 deletions

View file

@ -101,7 +101,7 @@ Per-hive (host + in-container):
Wire types + socket plumbing: Wire types + socket plumbing:
- **`hive-types/`** — leaf newtypes, chiefly the validated `Ident`. - **`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 ↔ - **`hive-host-sock/`** (hivectl ↔ c0re), **`hive-priv-sock/`** (c0re ↔
priv), **`hive-core-agent-sock/`** (harness ↔ c0re, `/run/hive/mcp.sock`) priv), **`hive-core-agent-sock/`** (harness ↔ c0re, `/run/hive/mcp.sock`)
— per-socket wire types, split out so each client links only its protocol. — per-socket wire types, split out so each client links only its protocol.

View file

@ -27,7 +27,7 @@ declarations.
- **How do config changes flow from manager to operator to container?** → - **How do config changes flow from manager to operator to container?** →
[`agent-lifecycle/config-changes.md`](agent-lifecycle/config-changes.md) [`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?** → - **What state survives destroy / purge / restart?** →
[`agent-lifecycle/persistence.md`](agent-lifecycle/persistence.md). [`agent-lifecycle/persistence.md`](agent-lifecycle/persistence.md).
- **Who can do what to whom — the agent roster and privilege?** → - **Who can do what to whom — the agent roster and privilege?** →

View file

@ -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 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 operator merges on the forge; that merge deploys them. The "System messages"
how agents stay informed about lifecycle changes that need a reaction. section covers the plain-text `system` messages hive-c0re sends agents.
## For operators ## 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 behaviour comes from its AGENTS.md / agent-specific instructions, not
the system prompt template. the system prompt template.
## Helper events ## System messages
`hive_sh4re::manager::HelperEvent` is the wire type for an event urgent Hive-c0re has no typed event that drives an immediate claude turn. A
enough to drive an immediate claude turn (delivered as a regular message from sender `system` is plain inbox text, and the harness logs it
`system` inbox message, same `recv` path as any other message). It (`log_system_event` in `hive-agent/src/main.rs`) without parsing the body.
currently has one variant, `NeedsUpdate { agent }` (sub-agent's Today hive-c0re sends two: the `/knowledge updated` broadcast
recorded flake rev is stale, operator rebuilds from the dashboard) — (`workers/knowledge.rs`) and the wake message for a graceful stop
and nothing in the tree constructs it; this removal dropped the push path (`Coordinator::kick_agent`).
(`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.
**A previously running container crashing** used to be exactly that **A previously running container crashing** drives no agent turn.
case (`ContainerCrash`, routed to the root agent via `crash_watch` only `tracing::warn!`s `"container crash
`Coordinator::notify_manager`) — it no longer drives any agent turn at
all. `crash_watch` now only `tracing::warn!`s `"container crash
detected"`; a swarm-level grafana alert matches that log line directly detected"`; a swarm-level grafana alert matches that log line directly
and pages the operator, with no agent (and no per-hive dashboard and pages the operator, with no agent (and no per-hive dashboard
banner) in the loop. See banner) in the loop. See
@ -348,18 +341,16 @@ banner) in the loop. See
The remaining lower-urgency lifecycle notices — `Rebuilt`, `Killed`, The remaining lower-urgency lifecycle notices — `Rebuilt`, `Killed`,
`Destroyed`, `NeedsLogin`, `LoggedIn` — are "FYI, check `Destroyed`, `NeedsLogin`, `LoggedIn` — are "FYI, check
when convenient" events with no reason to drive an immediate turn, so when convenient" events with no reason to drive an immediate turn, so
they go out via `swarm_notices::notify` instead they go out via `swarm_notices::notify` instead: `subsystem = "core"`,
of a `HelperEvent`: `subsystem = "core"`, `key = "<event>:<agent>"`, `key = "<event>:<agent>"`, and a single free-text `summary`
and a single free-text `summary` (`rebuilt_todo_summary` renders (`rebuilt_todo_summary` renders `Rebuilt`'s `ok`/`note`/`sha`/`tag`
`Rebuilt`'s `ok`/`note`/`sha`/`tag` fields into that string). fields into that string).
To add a new lifecycle notice: if it's "FYI, check when convenient," 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 call `swarm_notices::notify` — no new wire type needed. If it needs to
drive an immediate turn, decide first whether it actually needs an 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 *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 swarm-level alert could carry the same signal).
`HelperEvent` variant + `notify_agent`-equivalent call site +
`prompts/system.md` update when the answer is yes.
## Autoupdate on startup ## Autoupdate on startup

View file

@ -519,7 +519,7 @@ config — all nspawn containers live in `machine.slice`.
## See also ## 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/agent-lifecycle/persistence.md` — SQLite schema, state-dir layout
- `docs/process/conventions.md` — wire protocol, recipient sentinels - `docs/process/conventions.md` — wire protocol, recipient sentinels
- `docs/agent-lifecycle/agent-roster.md` — the agent roster and privilege - `docs/agent-lifecycle/agent-roster.md` — the agent roster and privilege

View file

@ -68,13 +68,9 @@ runs on the change.
`ack_until(N)` to prevent re-pop. Acked rows never redeliver. `ack_until(N)` to prevent re-pop. Acked rows never redeliver.
Transient pings (sentinel id 0) have nothing to ack and show no marker. Transient pings (sentinel id 0) have nothing to ack and show no marker.
**System messages** (from sender `system`): the broker delivers **System messages** (from sender `system`): the broker delivers them as regular inbox
`hive_sh4re::manager::HelperEvent` (one variant, `NeedsUpdate` — messages (same `recv` path). A container crash never reaches an
declared, but no call site constructs it) as regular inbox messages agent — it only produces a log line + swarm-level grafana
(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
alert, no agent turn at all (`docs/scheduler/observability.md`). Lifecycle alert, no agent turn at all (`docs/scheduler/observability.md`). Lifecycle
transitions the job-queue scheduler or crash watcher drive directly — transitions the job-queue scheduler or crash watcher drive directly —
stop/kill, destroy, a flake-rev login or logout state change — reach stop/kill, destroy, a flake-rev login or logout state change — reach

View file

@ -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. 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: 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/<you>/state/` for your notes). A container crash sends you nothing; the operator is alerted separately.
- `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.
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. 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.

View file

@ -107,7 +107,7 @@ use crate::turn_stats::TurnStats;
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use hive_core_agent_sock::{Request, Response}; 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; use hive_sock_client::Retry;
#[derive(Parser)] #[derive(Parser)]
@ -134,21 +134,12 @@ async fn main() -> Result<()> {
// ---------- shared turn helpers ---------- // ---------- shared turn helpers ----------
/// Surface a `SYSTEM_SENDER` message in the live event bus + tracing /// Surface a `SYSTEM_SENDER` message in the live event bus + tracing
/// log. Both agents and the manager receive `HelperEvent` notifications /// log. Quiet no-op when `from` isn't `SYSTEM_SENDER`.
/// (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`.
fn log_system_event(bus: &Bus, from: &str, body: &str) { fn log_system_event(bus: &Bus, from: &str, body: &str) {
if from != SYSTEM_SENDER { if from != SYSTEM_SENDER {
return; return;
} }
let parsed = serde_json::from_str::<HelperEvent>(body).ok(); tracing::info!(%from, %body, "system message");
if let Some(event) = &parsed {
tracing::info!(?event, "helper event");
} else {
tracing::info!(%from, %body, "system message");
}
bus.emit(LiveEvent::Note { bus.emit(LiveEvent::Note {
text: format!("[system] {body}"), text: format!("[system] {body}"),
}); });

View file

@ -936,10 +936,9 @@ impl Coordinator {
} }
/// `push_todo` summary text for a rebuild outcome, for /// `push_todo` summary text for a rebuild outcome, for
/// `job_queue::exec::run_emit_rebuilt`. Pure + independently testable, unlike /// `job_queue::exec::run_emit_rebuilt`. Pure + independently testable; the
/// the old `HelperEvent::Rebuilt`'s separate `sha`/`tag` /// `sha`/`tag` fields are part of the summary text, since a todo carries one
/// fields — those become part of the summary text itself now, since a todo /// string, not a structured payload.
/// carries one string, not a structured payload.
#[must_use] #[must_use]
pub fn rebuilt_todo_summary( pub fn rebuilt_todo_summary(
agent: &str, agent: &str,

View file

@ -4,7 +4,7 @@
//! that line directly; see the module doc on [`emit_crash_transitions`]. //! that line directly; see the module doc on [`emit_crash_transitions`].
//! Login-state transitions (`needs_login`/`logged_in`) publish onto //! Login-state transitions (`needs_login`/`logged_in`) publish onto
//! `swarm_notices` instead. The `RECENT_TRANSIENT_GRACE` window: //! `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::collections::HashSet;
use std::sync::Arc; use std::sync::Arc;

View file

@ -1,7 +1,7 @@
# hive-sh4re # hive-sh4re
The **shared payload vocabulary** between `hive-c0re` and the in-container 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 that the per-socket wire protocols are built from. The request/response
_envelopes_ themselves now live in the per-socket crates (below); this crate _envelopes_ themselves now live in the per-socket crates (below); this crate
holds the payloads they carry. holds the payloads they carry.

View file

@ -1,8 +1,6 @@
//! Reserved recipient names/senders and the out-of-band `HelperEvent` //! Reserved recipient names and senders.
//! payload hive-c0re pushes into the manager's inbox.
use hive_types::Ident; use hive_types::Ident;
use serde::{Deserialize, Serialize};
/// Logical name of the human operator: the sender of operator-authored /// Logical name of the human operator: the sender of operator-authored
/// messages. Not a recipient — `send` to it fails with /// 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` \ 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."; line and turn output on the dashboard, and your logs.";
/// Sender hive-c0re uses for events it pushes into the manager's inbox. /// Sender hive-c0re uses for messages it pushes into an agent's inbox.
/// Manager harness recognises this and parses the body as a `HelperEvent`.
pub const SYSTEM_SENDER: &str = "system"; pub const SYSTEM_SENDER: &str = "system";
/// Parse `s` as a [`Ident`] for use as `Message.from`, falling back to /// 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")) .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)] #[cfg(test)]
mod reserved_name_tests { mod reserved_name_tests {
use super::{OPERATOR_RECIPIENT, SYSTEM_SENDER}; use super::{OPERATOR_RECIPIENT, SYSTEM_SENDER};

View file

@ -34,8 +34,9 @@
# (`{from: "operator", ...}`) and the fallback attribution for an answered # (`{from: "operator", ...}`) and the fallback attribution for an answered
# question. # question.
"operator" "operator"
# Helper events (`container_crash`, `needs_update`) — the sender an # The sender of plain-text notices from hive-c0re (knowledge updates,
# agent is told to treat as hyperhive itself rather than as a peer. # the graceful-stop wake) — an agent is told to treat it as hyperhive
# itself rather than as a peer.
# `hive_sh4re::manager::SYSTEM_SENDER`. # `hive_sh4re::manager::SYSTEM_SENDER`.
"system" "system"
# A due self-scheduled reminder arrives as its own sender, so a wake I asked # A due self-scheduled reminder arrives as its own sender, so a wake I asked

View file

@ -66,7 +66,7 @@ pub struct User {
/// rest are message *senders*, and they matter for a reason that is not /// 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 /// cosmetic: the harness switches on the sender name, so an agent called
/// `todo` would have its messages interpreted as todo-wakes and one 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 /// 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. /// short strings on a path that already reads a file off disk.