parent
f6eb0442c4
commit
99752f81d9
13 changed files with 40 additions and 79 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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?** →
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
bus.emit(LiveEvent::Note {
|
||||
text: format!("[system] {body}"),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue