broker: resolve <parent> sentinel to topology parent at send time (#692)

This commit is contained in:
damocles 2026-05-31 10:54:16 +02:00 committed by Mara
commit 7142e95c8f
7 changed files with 154 additions and 8 deletions

View file

@ -8,7 +8,7 @@ You are the hyperhive manager `{label}` (qualified: `{qualified_label}`) in a mu
Tools (hyperhive surface):
- `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, in_reply_to?)` — 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). Optional `in_reply_to: <message-id>` threads this message under a prior one — the dashboard and per-agent inbox render it with a `↳ reply` link. 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.
- `mcp__hyperhive__send(to, body, in_reply_to?)` — 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). Use `to: "<parent>"` to address your structural parent without hardcoding their name — hive-c0re rewrites it at delivery time per `topology.json`, falling back to `operator` if you're a root agent. Lets the operator reparent you at runtime with zero change on your side. Optional `in_reply_to: <message-id>` threads this message under a prior one — the dashboard and per-agent inbox render it with a `↳ reply` link. 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.
<!-- role:agent -->
- (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.
<!-- /role:agent -->

View file

@ -1883,6 +1883,16 @@ fn check_send_allowed(to: &str) -> Result<(), String> {
// to ask for help.
return Ok(());
}
if to == hive_sh4re::PARENT_RECIPIENT {
// Always allow `<parent>` — same escape-hatch rationale as
// the manager exception. The allow-list constrains peer
// chatter, not the structural reporting line; the operator
// can rewire who the parent IS via `set_parent` without
// having to remember to update the per-agent allow-list.
// The broker resolves the sentinel to the real parent label
// on the host side per topology.json (#692).
return Ok(());
}
let Ok(raw) = std::fs::read_to_string(SEND_ALLOW_PATH) else {
return Ok(()); // file missing → no policy configured → unrestricted
};