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:
- **`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.

View file

@ -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?** →

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
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 = "<event>:<agent>"`,
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 = "<event>:<agent>"`, 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

View file

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

View file

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

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.
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/<you>/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.

View file

@ -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::<HelperEvent>(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}"),
});

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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