docs: refresh for the dashboard rework + recent harness commits
- web-ui.md: side panel, approval card + 3-way diff base, stats page, forge config links, removed agent.nix viewer, per-agent loose-ends inline answer. - approvals.md: forge mirror section + diff base toggle. - turn-loop.md: recv(max), get_logs, remind, loose-ends, whoami. - agent.md / manager.md prompts: recv(max), remind, get_logs. - CLAUDE.md: forge.rs / stats.rs / hive-forge.nix in the file map, scratchpad refresh. also: forgejo migrations.ALLOW_LOCALNETWORKS = true so an in-hive mirror of the hyperhive repo can import from a localhost source.
This commit is contained in:
parent
94781ccd08
commit
6ab3810e18
7 changed files with 205 additions and 36 deletions
58
CLAUDE.md
58
CLAUDE.md
|
|
@ -7,6 +7,8 @@ scratchpad.
|
|||
|
||||
- High-level project intro: **[README.md](README.md)**.
|
||||
- Open work + backlog: **[TODO.md](TODO.md)**.
|
||||
- Deployment / ops / boundaries / gateway backlog:
|
||||
**[TODO-ops.md](TODO-ops.md)**.
|
||||
|
||||
## File map
|
||||
|
||||
|
|
@ -69,6 +71,10 @@ hive-c0re/ host daemon + CLI (one binary, subcommand-dispatched)
|
|||
prepare/finalize/abort, lock_update_*
|
||||
src/migrate.rs startup auto-migration from pre-meta layout
|
||||
(idempotent, marker-guarded phase 4)
|
||||
src/forge.rs optional Forgejo wiring: per-agent users +
|
||||
tokens, the `agent-configs` org, and
|
||||
`push_config` — mirrors each applied repo
|
||||
into `agent-configs/<n>` on the local forge
|
||||
src/dashboard.rs axum HTTP: static shell + /api/state JSON + actions
|
||||
+ journald viewer + bind-with-retry (SO_REUSEADDR)
|
||||
+ deployed_sha chip per container +
|
||||
|
|
@ -107,6 +113,9 @@ hive-ag3nt/ in-container harness crate; produces TWO binaries
|
|||
src/turn_stats.rs per-turn analytics sink (one sqlite row per
|
||||
turn at /state/hyperhive-turn-stats.sqlite);
|
||||
schema + best-effort writer
|
||||
src/stats.rs read-side aggregations over turn-stats.sqlite
|
||||
backing the /stats page (bucketed Snapshot:
|
||||
turns / duration / tokens / model mix)
|
||||
src/events.rs LiveEvent + broadcast Bus + sqlite-backed history
|
||||
(/state/hyperhive-events.sqlite) + TurnState +
|
||||
model selection (persisted at /state/hyperhive-model)
|
||||
|
|
@ -116,7 +125,8 @@ hive-ag3nt/ in-container harness crate; produces TWO binaries
|
|||
src/login_session.rs drives `claude auth login` over stdio pipes
|
||||
src/bin/hive-ag3nt.rs sub-agent main (Serve + Mcp subcommands)
|
||||
src/bin/hive-m1nd.rs manager main (Serve + Mcp subcommands)
|
||||
assets/ index.html, agent.css, app.js (include_str!)
|
||||
assets/ index.html, agent.css, app.js, stats.html,
|
||||
stats.js (include_str!)
|
||||
prompts/ static role/tools/settings for claude (include_str!):
|
||||
agent.md — sub-agent system prompt
|
||||
manager.md — manager system prompt
|
||||
|
|
@ -126,7 +136,10 @@ hive-sh4re/ wire types (HostRequest/Response, AgentRequest/Response,
|
|||
ManagerRequest/Response, Message, Approval, HelperEvent)
|
||||
|
||||
nix/
|
||||
modules/hive-c0re.nix systemd service + firewall + git wiring
|
||||
modules/hive-c0re.nix systemd service + firewall + git wiring;
|
||||
imports hive-forge.nix
|
||||
modules/hive-forge.nix optional in-container Forgejo
|
||||
(`hyperhive.forge.enable`, default on)
|
||||
templates/harness-base.nix shared scaffolding for sub-agents + manager
|
||||
templates/agent-base.nix sub-agent nixosConfiguration
|
||||
templates/manager.nix manager nixosConfiguration
|
||||
|
|
@ -185,6 +198,33 @@ read them à la carte.
|
|||
In-flight or recent context that hasn't earned a section yet.
|
||||
Prune freely.
|
||||
|
||||
- **Just landed:** dashboard side panel + forge-linked
|
||||
config/approvals + per-bucket model stats. (a) Long content
|
||||
(file previews, approval diffs, journald logs) opens in a
|
||||
right-side slide-in panel instead of expanding inline;
|
||||
markdown `.md` previews render through the vendored `marked`
|
||||
bundle (`/static/marked.js` route added to the dashboard).
|
||||
(b) the container-row `agent.nix` viewer + `/api/agent-config`
|
||||
are gone — each row links to the agent's `agent-configs/<n>`
|
||||
repo on the forge instead. (c) pending approvals render as a
|
||||
card (identity / what-changed / decision actions) with a
|
||||
`commit on forge` deep-link and a 3-way diff base toggle — vs
|
||||
applied / vs last-approved / vs previous proposal — served by
|
||||
the new `/api/approval-diff/{id}?base=` endpoint. (d) the
|
||||
`/stats` page gained a per-bucket turns-by-model stacked bar
|
||||
(`Snapshot.models` + `Bucket.model_counts`) since model
|
||||
choice drives token cost. `/api/state` carries `forge_present`
|
||||
so the links only show when the forge is up. Docs refreshed:
|
||||
web-ui.md, approvals.md, turn-loop.md, agent.md, manager.md.
|
||||
- **Just landed:** `hyperhive.forge.enable` (default **true**) —
|
||||
the forge option moved out of `services.hive-forge.*` into the
|
||||
`hyperhive.*` namespace, and `hive-c0re.nix` imports
|
||||
`hive-forge.nix` so the forge ships with the standard core
|
||||
install. Forgejo settings gained
|
||||
`migrations.ALLOW_LOCALNETWORKS = true` so an in-hive mirror
|
||||
of the hyperhive repo can import from a `localhost` source
|
||||
(Forgejo blocks loopback/RFC-1918 migration sources by
|
||||
default).
|
||||
- **Just landed:** failed `nixos-container update` self-documents.
|
||||
`lifecycle::run` now appends the tail (40 lines) of the target
|
||||
container's own journal to the bail message when an `update`
|
||||
|
|
@ -565,11 +605,9 @@ Prune freely.
|
|||
agent_web_port + collision banner + spawn/rebuild preflight,
|
||||
browser notifications, focus-preserving refresh, generalised
|
||||
<details data-restore-key> survival, prompt-on-submit pattern.
|
||||
- **Open threads:** custom per-agent MCP tools (groundwork for
|
||||
moving bitburner-agent into hyperhive), two-step spawn,
|
||||
per-agent send allow-list, telemetry/charts, notes
|
||||
compaction, unprivileged containers, Bash allow-list,
|
||||
xterm.js. **Known bug** (in TODO.md): question id=5 was
|
||||
queued but didn't render — likely a `pending()` row-decode
|
||||
error swallowed by `unwrap_or_default`; investigate by curl
|
||||
/api/state | jq '.questions' + browser console.
|
||||
- **Open threads:** two-step spawn, notes compaction,
|
||||
unprivileged containers, Bash allow-list, xterm.js. The
|
||||
deployment / gateway / privsep cluster is tracked in
|
||||
`TODO-ops.md`. (Landed since this note was first written:
|
||||
extra per-agent MCP servers, per-agent send allow-list,
|
||||
telemetry + the `/stats` page.)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,10 @@ happens after a decision lands.
|
|||
force-push, or `rm -rf` the proposed repo and the queued
|
||||
approval still points at an immutable git object inside
|
||||
applied.
|
||||
4. Operator sees the diff on the dashboard, clicks ◆ APPR0VE (or
|
||||
4. Operator sees the proposal as a card on the dashboard — a
|
||||
full multi-file diff, toggleable between three bases (vs the
|
||||
running tree / vs the last approved proposal / vs the
|
||||
previous queued proposal) — and clicks ◆ APPR0VE (or
|
||||
`hive-c0re approve <id>` on the CLI).
|
||||
5. hive-c0re moves the working tree to `proposal/<id>` and runs
|
||||
the build under a sequence of tags (see below). On success,
|
||||
|
|
@ -158,6 +161,30 @@ approval id to retry. Because tags are first-class git objects,
|
|||
rejected and failed trees stay browsable forever — `git log
|
||||
--tags` in the applied repo is the audit trail.
|
||||
|
||||
### Forge mirror
|
||||
|
||||
When the bundled `hive-forge` container is running — on by
|
||||
default, `hyperhive.forge.enable` — hive-c0re mirrors every
|
||||
agent's applied repo into a private `agent-configs` Forgejo
|
||||
org. `forge::push_config(<name>)` pushes `applied/main` plus
|
||||
every tag to `agent-configs/<name>` after each ref mutation:
|
||||
the spawn that seeds `deployed/0`, every `request_apply_commit`
|
||||
(which plants `proposal/<id>`), every approve / deny, and a
|
||||
sweep at startup. Pushes are best-effort — a missing or stopped
|
||||
forge never blocks a deploy.
|
||||
|
||||
The org is private and agents are not members, so only the
|
||||
`core` user (a Forgejo site admin) can read it: an agent can't
|
||||
reach another agent's config — or even its own — through the
|
||||
forge. The tokenised push URL is passed inline to `git push`,
|
||||
never written into `applied/<n>/.git/config`; that repo is
|
||||
RO-bind-mounted into the manager, and a stored token would leak
|
||||
core's admin credential to an agent.
|
||||
|
||||
The dashboard deep-links into this org — a `config repo` link
|
||||
per container row and a `commit on forge` link per approval
|
||||
card. See `docs/web-ui.md`.
|
||||
|
||||
### Manager view of applied + meta
|
||||
|
||||
The manager container gets three host-side bind mounts via
|
||||
|
|
|
|||
|
|
@ -102,11 +102,14 @@ it as a stdio child via `--mcp-config`. The hyperhive socket name is
|
|||
- `send(to, body)` — message a peer (logical agent name), another
|
||||
agent, or the operator (recipient `operator`, surfaces in the
|
||||
dashboard inbox).
|
||||
- `recv(wait_seconds?)` — drain one inbox message. Without
|
||||
- `recv(wait_seconds?, max?)` — drain inbox messages. Without
|
||||
`wait_seconds` (or with `0`) returns immediately, a cheap
|
||||
"anything pending?" peek. Positive value parks the turn up
|
||||
to that many seconds (cap 180) — incoming messages wake
|
||||
instantly, otherwise returns empty at the timeout.
|
||||
instantly, otherwise returns empty at the timeout. `max`
|
||||
(default 1, server-side cap 32) drains up to N popped rows
|
||||
in one round-trip; `wait_seconds` applies to the *first*
|
||||
message, then the call drains up to `max` total.
|
||||
- `ask(question, options?, multi?, ttl_seconds?, to?)` —
|
||||
surface a structured question. Same shape as the manager's;
|
||||
recipient defaults to the operator (dashboard) but can be set
|
||||
|
|
@ -119,6 +122,21 @@ it as a stdio child via `--mcp-config`. The hyperhive socket name is
|
|||
routed to this agent. Authorisation is strict: only the
|
||||
declared target (or the operator via the dashboard) can
|
||||
answer.
|
||||
- `get_loose_ends()` — list everything still pending against
|
||||
this agent: unanswered questions it asked / was asked, plus
|
||||
reminders it scheduled. Each row carries an id + kind for
|
||||
`cancel_loose_end`.
|
||||
- `cancel_loose_end(kind, id)` — withdraw a `question`
|
||||
(posts `[cancelled by <self>]` to unblock the asker) or a
|
||||
`reminder` (hard-delete before fire). Sub-agents may only
|
||||
cancel rows they own.
|
||||
- `remind(message, due)` — schedule a reminder that lands in
|
||||
this agent's own inbox at a future time (sender shows as
|
||||
`reminder`). Large payloads spill to
|
||||
`/agents/<self>/state/reminders/` with the inbox message a
|
||||
short pointer.
|
||||
- `whoami()` — `{ name, role, pronouns, hyperhive_rev }` for
|
||||
self-identification without scraping the system prompt.
|
||||
|
||||
### Waking the agent from inside the container
|
||||
|
||||
|
|
@ -191,6 +209,16 @@ meta's.
|
|||
that was routed to the manager (a sub-agent did
|
||||
`ask(to: "manager", ...)`). Surfaces in the asker's inbox as
|
||||
the same `question_answered` event.
|
||||
- `get_logs(agent, lines?)` — fetch recent journal lines for a
|
||||
sub-agent container (diagnose MCP-registration failures,
|
||||
startup crashes, etc.). Pass the plain logical agent name;
|
||||
hive-c0re resolves the machine name (`h-<name>`, manager
|
||||
`hm1nd`). `lines` defaults to 50, host-capped at 500.
|
||||
- `remind` / `get_loose_ends` / `cancel_loose_end` / `whoami` —
|
||||
same as the sub-agent tools above, but `get_loose_ends` is
|
||||
hive-wide (every agent's pending questions + reminders, not
|
||||
just the manager's) and `cancel_loose_end` may cancel any
|
||||
agent's row.
|
||||
|
||||
The boundary: lifecycle ops on *existing* sub-agents
|
||||
(`kill`/`start`/`restart`) are at the manager's discretion — no
|
||||
|
|
|
|||
108
docs/web-ui.md
108
docs/web-ui.md
|
|
@ -54,12 +54,21 @@ soon as they blur.
|
|||
**`<details>` open-state preservation:** any collapsible element
|
||||
tagged with `data-restore-key="<stable-key>"` survives the
|
||||
refresh. `snapshotOpenDetails()` walks managed sections before
|
||||
render, `restoreOpenDetails()` re-applies after. Used today for
|
||||
the journald viewer (`journal:<container>`), the agent-config
|
||||
viewer (`agent-config:<name>`), and approval diff blocks
|
||||
(`approval-diff:<id>`). Setting `.open = true` programmatically
|
||||
also fires the `toggle` event, so any lazy-fetch wired to it
|
||||
re-runs cleanly on restore.
|
||||
render, `restoreOpenDetails()` re-applies after. Long-content
|
||||
drill-ins (file previews, diffs, journald logs) now open in the
|
||||
**side panel** (see below) rather than expanding inline, so the
|
||||
only restore-keyed `<details>` left is the answered-questions
|
||||
history list.
|
||||
|
||||
**Side panel (dashboard):** long content opens in a drawer that
|
||||
swipes in from the right — a singleton `#side-panel` with a
|
||||
titled header, a close button, and a scrollable body. Closes on
|
||||
the button, a backdrop click, or `Escape`. `Panel.open(title,
|
||||
node)` swaps the body; the JS builders for file previews,
|
||||
approval diffs, and journald logs all render into it. Markdown
|
||||
file previews (`.md` / `.markdown`) render through the vendored
|
||||
`marked` bundle (`GET /static/marked.js`) into a `.md` block;
|
||||
other files stay raw in a `<pre>`.
|
||||
|
||||
Both bind their listeners with `SO_REUSEADDR` via
|
||||
`tokio::net::TcpSocket` plus a retry loop on `AddrInUse` (12 tries,
|
||||
|
|
@ -136,21 +145,50 @@ Two-line layout (`assets/app.js::renderContainers`):
|
|||
on sub-agents, `↺ R3ST4RT` + (sub-agents) `■ ST0P` when running,
|
||||
`▶ ST4RT` when stopped. Buttons dim + disable while a transient
|
||||
lifecycle action is in flight.
|
||||
- Plus two collapsible `<details>` blocks:
|
||||
- `↳ logs · <container>` — lazy-fetches journald output via
|
||||
`GET /api/journal/{name}?unit=...&lines=...` (`journalctl -M
|
||||
<container> -b --no-pager --output=short-iso`). A unit
|
||||
dropdown switches between the harness service (default) and
|
||||
the full machine journal; refresh button re-fetches.
|
||||
- `↳ agent.nix · <name>` — lazy-fetches the applied config
|
||||
file via `GET /api/agent-config/{name}` (read-only mirror of
|
||||
`/var/lib/hyperhive/applied/<name>/agent.nix`). Mutating
|
||||
this still requires `request_apply_commit` + approval.
|
||||
- Line 3: drill-in triggers —
|
||||
- `↳ logs · <container>` — opens the side panel and lazy-
|
||||
fetches journald via `GET /api/journal/{name}?unit=&lines=`
|
||||
(`journalctl -M <container> -b --no-pager --output=short-iso`).
|
||||
A unit dropdown (harness service / full machine journal) and
|
||||
a refresh button live in the panel.
|
||||
- `↳ config repo ↗` — link to the agent's applied config repo
|
||||
on the bundled forge (`agent-configs/<name>`), opened in a
|
||||
new tab. Shown only when `forge_present`. Replaces the old
|
||||
one-file `agent.nix` viewer — the forge shows the full repo
|
||||
with history. Mutating config still requires
|
||||
`request_apply_commit` + approval.
|
||||
|
||||
`↻ UPD4TE 4LL` button appears above the containers list when any
|
||||
agent is stale. Banner pulses on each broker SSE event
|
||||
(`pulseBanner` with a 4s grace timer).
|
||||
|
||||
### Approval card
|
||||
|
||||
Each pending approval renders as a card (`assets/app.js::
|
||||
renderApprovals`) with three stacked sections:
|
||||
|
||||
- **identity header** — glyph, `#id`, agent, kind chip, and (for
|
||||
`apply_commit`) the short proposal sha as `<code>`.
|
||||
- **what-changed body** — the manager's description, then
|
||||
drill-in triggers: `↳ view diff` opens the diff in the side
|
||||
panel; `↳ commit on forge ↗` deep-links the proposal commit
|
||||
into `agent-configs/<agent>` (shown only when `forge_present`).
|
||||
Spawn approvals show a one-line "container will be created"
|
||||
note instead.
|
||||
- **decision actions** — `◆ APPR0VE` and `DENY`. Deny pops a
|
||||
`prompt()` for an optional reason carried to the manager as
|
||||
`HelperEvent::ApprovalResolved.note`.
|
||||
|
||||
The diff panel has a 3-way base toggle — **vs applied** (the
|
||||
running tree, served instantly from the diff already on the
|
||||
approval), **vs last-approved**, **vs previous proposal** — the
|
||||
latter two fetched on click from `GET /api/approval-diff/{id}
|
||||
?base=approved|previous`. Each line is classified client-side
|
||||
(`+` / `-` / `@@` / `--- ` / `+++ ` → add / del / hunk / file).
|
||||
|
||||
A `pending · N` / `history · N` tab pair switches the section
|
||||
between the live queue and the last 30 resolved approvals.
|
||||
|
||||
### Browser notifications
|
||||
|
||||
Pure frontend (`Notification` API). Three signals trigger them:
|
||||
|
|
@ -198,9 +236,13 @@ not ours.
|
|||
the operator inbox without a snapshot refetch. Used by the
|
||||
compose textbox under MESS4GE FL0W.
|
||||
- `GET /api/journal/{name}?unit=&lines=` — journalctl viewer for
|
||||
a managed container.
|
||||
- `GET /api/agent-config/{name}` — read-only view of the applied
|
||||
`agent.nix`.
|
||||
a managed container; rendered in the side panel.
|
||||
- `GET /api/approval-diff/{id}?base=applied|approved|previous` —
|
||||
on-demand unified diff for an `ApplyCommit` approval against
|
||||
the chosen base (running tree / last approved proposal /
|
||||
previous queued proposal). Raw diff text, classified
|
||||
client-side. `GET /static/marked.js` serves the vendored
|
||||
`marked` bundle the side panel uses for markdown previews.
|
||||
- `GET /api/state-file?path=<host-or-container-path>` — bounded
|
||||
text read of a file under the per-agent `state/` subtree or
|
||||
the shared `/var/lib/hyperhive/shared/`. Accepts the
|
||||
|
|
@ -343,8 +385,16 @@ Layout, top to bottom:
|
|||
- Inbox `<details>` block (collapsed): `inbox · N` — last 30
|
||||
messages addressed to this agent, fetched via
|
||||
`AgentRequest::Recent { limit: 30 }`. (Separate from
|
||||
`AgentRequest::Recv { wait_seconds }` which the harness uses
|
||||
internally to long-poll the broker.)
|
||||
`AgentRequest::Recv { wait_seconds, max }` which the harness
|
||||
uses internally to long-poll the broker.)
|
||||
- Loose-ends `<details>` block: `loose ends · N` — questions,
|
||||
approvals, and reminders pending against this agent (the
|
||||
`get_loose_ends` data, via `GET /api/loose-ends`). Question
|
||||
rows carry an inline answer form (textarea — Enter submits,
|
||||
Shift+Enter newlines); submitting POSTs cross-origin to the
|
||||
core dashboard's `/answer-question/{id}` so the operator
|
||||
answers *as operator*. The per-agent socket deliberately gets
|
||||
no operator-authority path — see `TODO-ops.md`.
|
||||
- Terminal-wrap: live event tail (sticky-bottom auto-scroll +
|
||||
`↓ N new` pill when not at bottom) followed by an
|
||||
operator-input textarea acting as a prompt.
|
||||
|
|
@ -454,3 +504,19 @@ Bus events (new vocabulary on `/events/stream`):
|
|||
totals).
|
||||
- `turn_state_changed { state, since_unix }` — drives the
|
||||
state badge (`idle`/`thinking`/`compacting`).
|
||||
|
||||
### Stats page
|
||||
|
||||
`GET /stats` is a separate per-agent page (served by the
|
||||
harness, linked from the per-agent page's `📊 stats →` and from
|
||||
each dashboard container row). Turn analytics, read-only, from
|
||||
`/state/hyperhive-turn-stats.sqlite`. `GET /api/stats?window=
|
||||
24h|7d|30d` returns a time-bucketed `Snapshot`; the page renders
|
||||
it with Chart.js (vendored from a CDN). Charts: turns,
|
||||
duration (p50 · p95 · avg), context tokens, token cost per
|
||||
bucket, a **turns-by-model** stacked bar (model choice drives
|
||||
token cost, so it sits directly under the cost chart), and
|
||||
doughnuts for tool / wake-source / result mix. A summary chip
|
||||
row carries window totals. `stats.rs` opens the sqlite db
|
||||
read-only and degrades to an empty snapshot on any error — the
|
||||
page is decorative, never authoritative.
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ You are hyperhive agent `{label}` in a multi-agent system. The operator (recipie
|
|||
|
||||
Tools (hyperhive surface):
|
||||
|
||||
- `mcp__hyperhive__recv(wait_seconds?)` — drain one more message from your inbox (returns `(empty)` if nothing pending). Without `wait_seconds` (or with `0`) it returns immediately — a cheap "anything pending?" peek you can sprinkle between tool calls. To **wait** for work when you have nothing else useful to do this turn, call with a long wait (e.g. `wait_seconds: 180`, the max) — incoming messages wake you instantly, otherwise the call returns empty at the timeout. That's strictly better than a fixed `sleep` shell command: lower latency on new work, no busy-loop.
|
||||
- `mcp__hyperhive__recv(wait_seconds?, max?)` — drain inbox messages (returns `(empty)` if nothing pending). Without `wait_seconds` (or with `0`) it returns immediately — a cheap "anything pending?" peek you can sprinkle between tool calls. To **wait** for work when you have nothing else useful to do this turn, call with a long wait (e.g. `wait_seconds: 180`, the max) — incoming messages wake you instantly, otherwise the call returns empty at the timeout. That's strictly better than a fixed `sleep` shell command: lower latency on new work, no busy-loop. `max` (default 1, cap 32) drains several queued messages in one call — the wake prompt tells you the pending count.
|
||||
- `mcp__hyperhive__send(to, body)` — message a peer (by their name) or the operator (recipient `operator`, surfaces in the dashboard). Use `to: "*"` to broadcast to all agents (they receive a hint that it's a broadcast and may not need action). Some agents have a per-agent allow-list (`hyperhive.allowedRecipients` in their `agent.nix`) — if so the tool refuses recipients outside the list with a clear error; route through the manager (`send(to: "manager", …)`) which is always reachable.
|
||||
- (some agents only) **extra MCP tools** surfaced as `mcp__<server>__<tool>` — these are agent-specific (matrix client, scraper, db connector, etc.) declared in your `agent.nix` under `hyperhive.extraMcpServers`. Treat them as first-class tools alongside the hyperhive surface; the operator already auto-approved them at deploy time.
|
||||
- `mcp__hyperhive__ask(question, options?, multi?, ttl_seconds?, to?)` — surface a structured question to the human operator (default, or `to: "operator"`) OR a peer agent (`to: "<agent-name>"`). Returns immediately with a question id — do NOT wait inline. When the recipient answers, a system message with event `question_answered { id, question, answer, answerer }` lands in your inbox; handle it on a future turn. Use this for clarifications, permission for risky actions, choice between options, or peer Q&A without burning regular inbox slots. `options` is advisory: a short fixed-choice list when applicable, otherwise leave empty for free text. `multi: true` lets the answerer pick multiple (checkboxes), answer comes back comma-joined. `ttl_seconds` auto-cancels with answer `[expired]` (and `answerer: "ttl-watchdog"`) when the decision becomes moot.
|
||||
- `mcp__hyperhive__answer(id, answer)` — answer a question that was routed to YOU. You'll see one in your inbox as a `question_asked { id, asker, question, options, multi }` system event when a peer or the manager calls `ask(to: "<your-name>", ...)`. The answer surfaces in the asker's inbox as a `question_answered` event. Strict authorisation: you can only answer questions where you are the declared target.
|
||||
- `mcp__hyperhive__get_loose_ends()` — list your loose ends: unanswered questions where you're asker (waiting on someone) or target (owing a reply), plus reminders you've scheduled that haven't fired. No args, cheap server-side sweep. Useful at turn start to remember what's outstanding without scanning inbox archaeology.
|
||||
- `mcp__hyperhive__cancel_loose_end(kind, id)` — cancel one of your own open threads. `kind` is `"question"` (the asker — you, in this case — gets a `[cancelled by <you>]` answer so the waiter unblocks) or `"reminder"` (hard-deleted before it fires). `id` from the matching `get_loose_ends` row or the original submission reply.
|
||||
- `mcp__hyperhive__remind(message, delay_seconds? | at_unix_timestamp?, file_path?)` — schedule a message to land in your *own* inbox at a future time (sender shows as `reminder`). Set exactly one of `delay_seconds` (relative) or `at_unix_timestamp` (absolute). Use for self-paced follow-ups instead of blocking a whole turn on a long `recv` wait. A large `message` auto-spills to a file under `/agents/{label}/state/reminders/`; pass `file_path` to point at one yourself.
|
||||
- `mcp__hyperhive__whoami()` — self-introspection: returns your canonical agent name (from socket identity, not the prompt-substituted label), role, and current hyperhive rev. No args. Use it when you want a trustworthy identity stamp for state files, commit messages, or cross-agent attribution that won't drift across renames.
|
||||
|
||||
Need new packages, env vars, or other NixOS config for yourself? You can't edit your own config directly — message the manager (recipient `manager`) describing what you need + why. The manager evaluates the request (it doesn't rubber-stamp), edits `/agents/{label}/config/agent.nix` on your behalf, commits, and submits an approval that the operator can accept on the dashboard; on approve hive-c0re rebuilds your container with the new config.
|
||||
|
|
|
|||
|
|
@ -2,18 +2,20 @@ You are the hyperhive manager `{label}` in a multi-agent system. You coordinate
|
|||
|
||||
Tools (hyperhive surface):
|
||||
|
||||
- `mcp__hyperhive__recv(wait_seconds?)` — drain one more message from your inbox. Without `wait_seconds` (or with `0`) it returns immediately — a cheap inbox peek you can drop between actions. To **wait** when you have nothing else to do, call with a long wait (e.g. `wait_seconds: 180`, the max) — you'll wake instantly on new work, otherwise return after the timeout. Use that instead of ending the turn or sleeping in a Bash command.
|
||||
- `mcp__hyperhive__recv(wait_seconds?, max?)` — drain inbox messages. Without `wait_seconds` (or with `0`) it returns immediately — a cheap inbox peek you can drop between actions. To **wait** when you have nothing else to do, call with a long wait (e.g. `wait_seconds: 180`, the max) — you'll wake instantly on new work, otherwise return after the timeout. Use that instead of ending the turn or sleeping in a Bash command. `max` (default 1, cap 32) drains several queued messages in one call.
|
||||
- `mcp__hyperhive__send(to, body)` — message an agent (by name), another peer, or the operator (`operator` surfaces in the dashboard). Use `to: "*"` to broadcast to all agents (they receive a hint that it's a broadcast and may not need action).
|
||||
- `mcp__hyperhive__request_spawn(name, description?)` — queue a brand-new sub-agent for operator approval (≤9 char name). Pass an optional `description` and it appears on the dashboard approval card — no need to send a separate message explaining the request.
|
||||
- `mcp__hyperhive__kill(name)` — graceful stop on a sub-agent. No approval required.
|
||||
- `mcp__hyperhive__start(name)` — start a stopped sub-agent. No approval required.
|
||||
- `mcp__hyperhive__restart(name)` — stop + start a sub-agent. No approval required.
|
||||
- `mcp__hyperhive__update(name)` — rebuild a sub-agent (re-applies the current hyperhive flake + agent.nix, restarts the container). No approval required — idempotent. Use when you receive a `needs_update` system event.
|
||||
- `mcp__hyperhive__get_logs(agent, lines?)` — fetch recent journal lines for a sub-agent container. Use to diagnose MCP-server registration failures, startup crashes, or harness issues you can't see from inside. Pass the plain logical agent name; `lines` defaults to 50 (capped at 500).
|
||||
- `mcp__hyperhive__request_apply_commit(agent, commit_ref, description?)` — submit a config change for any agent (`hm1nd` for self) for operator approval. Pass an optional `description` and it appears on the dashboard approval card so the operator knows what changed without opening the diff. At submit time hive-c0re fetches your commit into the agent's applied repo and pins it as `proposal/<id>`; from that moment your proposed-side commit can be amended or force-pushed freely without changing what the operator will build.
|
||||
- `mcp__hyperhive__ask(question, options?, multi?, ttl_seconds?, to?)` — surface a structured question to the operator (default, or `to: "operator"`) OR a sub-agent (`to: "<agent-name>"`). Returns immediately with a question id; the answer arrives later as a system `question_answered { id, question, answer, answerer }` event in your inbox. Options are advisory: the dashboard always lets the operator type a free-text answer in addition. Set `multi: true` to render options as checkboxes (operator can pick multiple); the answer comes back as `, `-separated. Set `ttl_seconds` to auto-cancel after a deadline (capped at 6h server-side) — on expiry the answer is `[expired]` and `answerer` is `"ttl-watchdog"`. Do not poll inside the same turn — finish the current work and react when the event lands.
|
||||
- `mcp__hyperhive__answer(id, answer)` — answer a question that was routed to YOU (a sub-agent did `ask(to: "manager", ...)`). The triggering event in your inbox is `question_asked { id, asker, question, options, multi }`. The answer surfaces in the asker's inbox as a `question_answered` event.
|
||||
- `mcp__hyperhive__get_loose_ends()` — hive-wide loose ends: every pending approval + every unanswered question + every pending reminder across the swarm. Cheap server-side sweep, no args. Use to find stalled threads (sub-agent A asked B something three days ago and B never answered) before they rot.
|
||||
- `mcp__hyperhive__cancel_loose_end(kind, id)` — cancel any question or reminder in the swarm (manager bypasses the owner check used on sub-agents). Use for hive-wide cleanup when a sub-agent is offline / can't withdraw its own ask / reminder.
|
||||
- `mcp__hyperhive__remind(message, delay_seconds? | at_unix_timestamp?, file_path?)` — schedule a message to land in your own inbox at a future time (sender shows as `reminder`). Set exactly one of `delay_seconds` (relative) or `at_unix_timestamp` (absolute). Good for deadline follow-ups — "check whether agent X answered the question I relayed". Large payloads auto-spill to a file under `/state/reminders/`; pass `file_path` to control the destination.
|
||||
- `mcp__hyperhive__whoami()` — self-introspection: canonical name (`manager`), role, current hyperhive rev. No args. Useful for boot announcements and cross-agent attribution that won't drift across config reloads.
|
||||
|
||||
Approval boundary: lifecycle ops on *existing* sub-agents (`kill`, `start`, `restart`) are at your discretion — no operator approval. *Creating* a new agent (`request_spawn`) and *changing* any agent's config (`request_apply_commit`) still go through the approval queue. The operator only signs off on changes; you run the day-to-day.
|
||||
|
|
|
|||
|
|
@ -137,6 +137,13 @@ in
|
|||
DEFAULT_BRANCH = "main";
|
||||
DEFAULT_PRIVATE = "private";
|
||||
};
|
||||
# Repo migrations / pull-mirrors fetch from the source
|
||||
# URL *inside* Forgejo. hyperhive code is synced from
|
||||
# `localhost` (and the host LAN), which Forgejo's
|
||||
# migration guard blocks by default ("cannot import from
|
||||
# disallowed hosts"). Allow loopback + RFC-1918 sources
|
||||
# so an in-hive mirror of the hyperhive repo works.
|
||||
migrations.ALLOW_LOCALNETWORKS = true;
|
||||
log.LEVEL = "Warn";
|
||||
# F3 (federation) computes its data dir relative to the
|
||||
# forgejo binary, which lands in the read-only nix
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue