From 6ab3810e18df1bd7e5648506214dc1c642adea0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?m=C3=BCde?= Date: Wed, 20 May 2026 11:34:43 +0200 Subject: [PATCH] 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. --- CLAUDE.md | 58 ++++++++++++++---- docs/approvals.md | 29 ++++++++- docs/turn-loop.md | 32 +++++++++- docs/web-ui.md | 108 +++++++++++++++++++++++++++------- hive-ag3nt/prompts/agent.md | 3 +- hive-ag3nt/prompts/manager.md | 4 +- nix/modules/hive-forge.nix | 7 +++ 7 files changed, 205 insertions(+), 36 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index bf5c0d1..2172b05 100644 --- a/CLAUDE.md +++ b/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/` 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/` + 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
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.) diff --git a/docs/approvals.md b/docs/approvals.md index d546022..8bba144 100644 --- a/docs/approvals.md +++ b/docs/approvals.md @@ -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 ` on the CLI). 5. hive-c0re moves the working tree to `proposal/` 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()` pushes `applied/main` plus +every tag to `agent-configs/` after each ref mutation: +the spawn that seeds `deployed/0`, every `request_apply_commit` +(which plants `proposal/`), 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//.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 diff --git a/docs/turn-loop.md b/docs/turn-loop.md index cf23a49..f5900ca 100644 --- a/docs/turn-loop.md +++ b/docs/turn-loop.md @@ -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 ]` 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//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-`, 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 diff --git a/docs/web-ui.md b/docs/web-ui.md index 0aeb840..8e9135e 100644 --- a/docs/web-ui.md +++ b/docs/web-ui.md @@ -54,12 +54,21 @@ soon as they blur. **`
` open-state preservation:** any collapsible element tagged with `data-restore-key=""` survives the refresh. `snapshotOpenDetails()` walks managed sections before -render, `restoreOpenDetails()` re-applies after. Used today for -the journald viewer (`journal:`), the agent-config -viewer (`agent-config:`), and approval diff blocks -(`approval-diff:`). 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 `
` 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 `
`.
 
 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 `
` blocks: - - `↳ logs · ` — lazy-fetches journald output via - `GET /api/journal/{name}?unit=...&lines=...` (`journalctl -M - -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 · ` — lazy-fetches the applied config - file via `GET /api/agent-config/{name}` (read-only mirror of - `/var/lib/hyperhive/applied//agent.nix`). Mutating - this still requires `request_apply_commit` + approval. +- Line 3: drill-in triggers — + - `↳ logs · ` — opens the side panel and lazy- + fetches journald via `GET /api/journal/{name}?unit=&lines=` + (`journalctl -M -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/`), 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 ``. +- **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/` (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=` — 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 `
` 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 `
` 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. diff --git a/hive-ag3nt/prompts/agent.md b/hive-ag3nt/prompts/agent.md index cd4b14b..43222a6 100644 --- a/hive-ag3nt/prompts/agent.md +++ b/hive-ag3nt/prompts/agent.md @@ -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____` — 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: ""`). 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: "", ...)`. 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 ]` 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. diff --git a/hive-ag3nt/prompts/manager.md b/hive-ag3nt/prompts/manager.md index 6f6cf95..15f85a5 100644 --- a/hive-ag3nt/prompts/manager.md +++ b/hive-ag3nt/prompts/manager.md @@ -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/`; 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: ""`). 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. diff --git a/nix/modules/hive-forge.nix b/nix/modules/hive-forge.nix index 6edfcd6..2cd7eec 100644 --- a/nix/modules/hive-forge.nix +++ b/nix/modules/hive-forge.nix @@ -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