Watch
0
0
Fork
You've already forked hyperhive
0

docs: scheduled prompts are swarm-level; the hive page is a read-only list

Drops docs/tools/scheduling.md and every description of hive-level
schedule creation, the worker, the removed MCP tools, the scheduling tool
group and the removed endpoints/events, pointing at docs/swarm/schedules.md.
This commit is contained in:
atlas 2026-10-04 21:23:18 +02:00
commit b4a2aeb5ba
18 changed files with 90 additions and 346 deletions

View file

@ -94,12 +94,8 @@ apply.
approval step — every other agent is created at swarm level
(`swarmctl agent create`).
Roster-wise, `ruth` is just another entry.
- **Wire-protocol** — the `*(privileged)*` `Request` variants in
`hive-core-agent-sock`'s unified enum are the scheduling ops
(`RequestSchedulePrompt`, `CancelSchedule`, `FireScheduleNow`,
`EditSchedule`), reachable only from the manager's socket flavour,
matching the `scheduling` tool group
([`docs/turn-loop/mcp.md`](../turn-loop/mcp.md)). Container lifecycle
- **Wire-protocol** — `hive-core-agent-sock`'s unified `Request` enum
is the same on both socket flavours. Container lifecycle
ops (kill/start/restart/rebuild) go through the separate host-admin
socket `hivectl` speaks. `Wake` (inject a `from: <X>` message straight
into the caller's own inbox) is on this socket too, unprivileged on

View file

@ -1,7 +1,8 @@
# Approvals + helper events
The approval queue is where an agent asks the operator for something it
can't do itself: a scheduled prompt, or a meta-input bump. Config
can't do itself. Nothing submits a new approval today: the one kind
left, a meta-input bump, only reads back from existing rows. Config
changes don't go through this queue: they're pull requests
on the agent's config repo, which an operator merges on the forge, and
that merge deploys them. The submitting agent — any agent with the
@ -16,13 +17,6 @@ it stays informed about what happens after a decision lands.
config (or its own, via a sub-manager) as a pull request on
`agent-configs/<agent>`. Review it on the forge like any other PR, and
merge it there to deploy it. See [Config changes](#config-changes).
- **Scheduled prompt** (`SchedulePrompt`) — an agent asked to schedule
a message to one or more inboxes at a future time. It lands on your
dashboard's Y3R C4LL tab (or `hivectl approvals pending` /
`approve <id>` from the CLI). You can also add schedules yourself
directly from the SCH3DUL3S tab, which skips this approval step
entirely — the gate here is specifically for an *agent* asking to
schedule something, not for you doing it.
- **Meta/flake update** (`UpdateMetaInputs`) — an existing row reads
back and you can approve it. Approving runs the update and commits
the lock change; it doesn't rebuild anything by itself.
@ -113,9 +107,8 @@ merged by an operator on the forge (see [Config changes](#config-changes)).
### Approval kinds (wire shapes)
`ApprovalKind` carries two variants; each maps to a different
`commit_ref` encoding because `ApprovalKind` overloads that field as
the kind-specific payload carrier.
`ApprovalKind` carries one variant, and it overloads `commit_ref` as
its payload carrier.
<!-- vale write-good.Passive = NO -->
- `UpdateMetaInputs` — `commit_ref` stores the JSON-encoded inputs
@ -123,64 +116,8 @@ the kind-specific payload carrier.
etc.). hive-c0re sets the `agent` field to the requesting root agent.
On approve hive-c0re runs `nix flake update [inputs...]` on the
meta flake and commits the resulting lock changes.
- `SchedulePrompt` — `commit_ref` stores the JSON-encoded
`SchedulePromptPayload` (target list, body, schedule) so the
approval row carries the full submission verbatim. On approve
hive-c0re inserts a row into `scheduled_prompts` with
`source = approval:<id>`; the worker fans the body out as
inbox messages to each target at the scheduled time, recurring
when `interval_seconds` is set.
<!-- vale write-good.Passive = YES -->
### Scheduled prompts (submit paths)
Two ways a row lands in `scheduled_prompts`:
- **Operator-direct** (`source = "operator"`): the operator adds a schedule through the dashboard form. Lands in the table immediately, no approval gate — operator action is already the trust boundary.
- **Agent-requested** (`source = "approval:<id>"`): an agent submits a `RequestSchedulePrompt` through its MCP socket (the `request_schedule_prompt` tool, `scheduling` group). hive-c0re queues an `ApprovalKind::SchedulePrompt` row; on approve, it inserts the schedule row with `source = approval:<id>` so the audit trail points back at the operator decision (above).
No self-target shortcut: even agent-self schedules need approval. The existing `remind` MCP tool stays the quick self-wake path (no approval, lands directly in the agent's own inbox); this module is the bigger, multi-recipient, operator-visible thing.
### Scheduled prompt worker (catch-up clamp)
When hive-c0re comes back from being down, the worker sees rows whose `next_fire_at_unix` is well in the past. For recurring rows that would mean firing N delayed pulses in a row — spammy and useless. Instead the worker fires **once** per row and bumps `next_fire_at_unix` to the next interval slot ≥ `now`, recording how many cycles it skipped in `last_result` (per-target). Operators see "fired late, caught up from 17 skipped" instead of 17 wake-up storms.
The worker fires one-shot rows once (if past due, on the next worker pass) and deletes them; recurring rows survive until cancelled.
`targets` is its own table (`scheduled_prompt_targets`) so partial cancellation flips a single row and the dashboard can show last-fired / last-result per recipient. Cancelling every target reaps the parent row on the next worker pass.
### Scheduled prompt delivery: todo, not a broker message
An agent target's delivery is `push_todo` (`Coordinator::push_todo`,
`docs/scheduler/coordinator.md` covers the mechanism generally), not a broker
`Message` — a scheduled prompt wakes its target with a todo instead of
driving an immediate turn, by design. `key = "schedule:<id>"` per
target drives `push_todo`'s own upsert-by-key dedup: a re-fire of the
*same schedule* against a target that hasn't reviewed the last one
collapses into that one todo instead of stacking up.
### Missing-target failure
When a target name doesn't resolve to a known agent (container
destroyed, typo, etc.) the worker:
1. Records `last_result = "no such agent: <name>"` on the
per-target row.
2. Sends a single advisory `Message` from `system` to `operator`
naming the schedule, target, and reason. This one stays a `Message`
regardless of target type — it's a to-operator advisory about a
broken schedule, not the schedule's own delivery.
3. Continues fanning out to the other live targets.
Transient broker errors (sqlite lock contention, etc.) get the same
`last_result` annotation plus a `tracing::warn`, and then:
- **Recurring rows** re-arm to the next interval slot — the retry
self-heals on the next worker pass.
- **One-shot rows**: the worker deletes them unconditionally after their single
fan-out pass; a broker error on a one-shot isn't retried (the
operator advisory and `last_result` are the only audit trail).
### Reminder delivery: file-path semantics
A reminder may carry a `file_path` (the agent-visible path inside its
@ -324,7 +261,6 @@ by the approval handler rather than run inline:
| `ApprovalKind` | DAG submitted | source |
|---|---|---|
| `UpdateMetaInputs` | `meta_update` (`MetaLock` + rebuild fan-out) | `approval` |
| `SchedulePrompt` | — runs inline (single sqlite insert) | — |
The DAG carries the originating `approval_id`. **Every** queued kind
resolves through `actions::resolve_approval_dag` when its DAG settles
@ -508,10 +444,8 @@ the `submitter` column on the `approvals` table). The harness delivers it
as a regular `system` inbox message so it drives a normal claude turn.
`finish_approval` fires an `ApprovalResolved` HelperEvent this way for
**every** approval kind's terminal state. A
"FYI, check when convenient" event doesn't need a message — those go
through `Coordinator::push_todo` instead, a direct live dial of the target
agent's in-container todo socket (same `UpsertTodo` request in-container
producers use). Legacy
"FYI, check when convenient" event doesn't need a message — hive-c0re publishes those as swarm
lifecycle notices instead (`swarm_notices::notify`). Legacy
approval rows that predate the submitter column fall back to the
root agent. Variants (`hive_sh4re::manager::HelperEvent`):
@ -533,9 +467,8 @@ root agent. Variants (`hive_sh4re::manager::HelperEvent`):
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 deliver via `push_todo` (see above) instead
of `HelperEvent`: an `agent_todo_socket` push instead of a broker
message, `subsystem = "core"`, `key = "<event>:<agent>"` for dedup,
they go out via `swarm_notices::notify` (see above) 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).
@ -543,7 +476,7 @@ To add a new lifecycle notice: if it needs to drive an immediate turn
(something genuinely urgent, like `ContainerCrash`), add a
`HelperEvent` variant + call sites + update `prompts/system.md`'s
message-event list. If it's "FYI, check when convenient," call
`push_todo` directly instead — no new wire type
`swarm_notices::notify` instead — no new wire type
needed.
## Autoupdate on startup

View file

@ -40,8 +40,8 @@ schemas, file layouts, and internal migration mechanics.
### `/var/lib/hyperhive/db/broker.sqlite` (host)
Seven tables, all in one file — three queues, a small key/value
table, the schedule header/targets split, and the per-agent
Six tables, all in one file — two queues, a small key/value table,
the read-only schedule header/targets split, and the per-agent
power-intent registry:
- `messages` — every inter-agent / operator-bound message.
@ -56,21 +56,19 @@ power-intent registry:
per-agent store — see [`/harness/` contents
below](#state-dirs-per-agent) for where reminders (and todos)
live.
- `approvals` — the queue. `agent / kind (update_meta_inputs |
schedule_prompt) /
- `approvals` — the queue. `agent / kind (update_meta_inputs) /
commit_ref / requested_at / status / resolved_at / note`.
- `scheduled_prompts` — recurring + one-shot prompt queue.
- `scheduled_prompts` — the scheduled prompts left from before they
moved to swarm level ([`swarm/schedules.md`](../swarm/schedules.md)).
`owner / body / interval_seconds (NULL = one-shot) /
next_fire_at_unix / created_at_unix / source ("operator" or
"approval:<id>") / cancelled_at_unix / description`. `owner`
drives cancel-permission checks (operator vs the submitting
agent). The worker tombstones and reaps cancelled rows
on its next pass.
"approval:<id>") / cancelled_at_unix / description / paused_at_unix`.
Read-only: the dashboard's SCH3DUL3S tab lists them so the operator
can recreate them with `swarmctl schedule`; nothing writes or fires
them.
- `scheduled_prompt_targets` — per-target state for each schedule.
`schedule_id / target / cancelled_at_unix /
last_fired_at_unix / last_result`. `ON DELETE CASCADE` from
`scheduled_prompts(id)` — requires `PRAGMA foreign_keys = ON`
per connection (set at open).
last_fired_at_unix / last_result`.
- `agent_power` — one row per agent: `agent PK / wanted (up |
offline) / updated_at`, owned by `hive-c0re/src/stores/power.rs`.
This is the durable power *intent* the job queue reconciles the
@ -90,11 +88,7 @@ Retention:
an unacked row on a crash.
- hive-c0re keeps approvals indefinitely — an audit trail. `actions::destroy`
rows stay visible to anything that queries by id.
- Scheduled prompts: the worker deletes one-shot rows on fire;
recurring rows live until the operator cancels them
(`cancel_schedule` MCP / dashboard ✗) which tombstones via
`cancelled_at_unix`, then `reap_cancelled` drops the row on
the next worker pass.
- Scheduled prompts: nothing deletes them; the rows stay as they are.
- `agent_power` rows live until the operator destroys the agent (one row per
agent — nothing to vacuum).