diff --git a/hive-ag3nt/prompts/system.md b/hive-ag3nt/prompts/system.md index fe66b96d..1cee7ae1 100644 --- a/hive-ag3nt/prompts/system.md +++ b/hive-ag3nt/prompts/system.md @@ -42,6 +42,7 @@ Tools (hyperhive surface): - `mcp__hyperhive__get_agent_meta(name?)` — fetch identity + status metadata for an agent: canonical `name`, `role` (`agent` / `manager`), current `hyperhive_rev`, plus self-reported `status` text (set via `set_status`) and how long ago it was set. Also returns the hive + swarm display names (`hive_name`, `swarm_name`) when the operator has configured `services.hyperhive.{hiveName, swarmName}`; both lines omitted when unset. Pass `name` to query a peer (e.g. check whether iris is idle before pinging them). Omit `name` to get your own trustworthy identity stamp — useful for state files, commit messages, cross-agent attribution that won't drift across renames or session-continue boundaries where the system-prompt label could be stale. - `mcp__hyperhive__request_next_turn()` — ask the harness to start another turn immediately after this one ends, even if the inbox is empty. Use for multi-turn tasks (long builds, sequential steps) where you want to continue without waiting for an external message. The next turn starts with `from: "self"` and `body: "continue"`. No-op if new inbox messages arrive before this turn ends (the harness already loops immediately on pending messages). No args. +- `mcp__hyperhive__restart(name)` — *(requires `lifecycle` tool group)* restart a direct child sub-agent (stop + start). The server enforces topology: the call is rejected unless `name` is a direct child of yours per `topology.json`. No approval required. Need new packages, env vars, or other NixOS config for yourself? You can't edit your own config directly — message the manager (recipient `root`) 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/src/mcp.rs b/hive-ag3nt/src/mcp.rs index 540c37b9..6c33ffea 100644 --- a/hive-ag3nt/src/mcp.rs +++ b/hive-ag3nt/src/mcp.rs @@ -895,6 +895,29 @@ impl AgentServer { .await } + // IMPORTANT: this tool is only available when the `lifecycle` tool group + // is granted to this agent. hive-c0re enforces the topology check + // server-side: the call is rejected unless `name` is a direct child. + #[tool( + description = "Restart a direct child sub-agent container (stop + start). \ + Only succeeds if `name` is a direct child of this agent in the topology \ + tree — the server enforces this. No approval required." + )] + async fn restart(&self, Parameters(args): Parameters) -> String { + let log = format!("{args:?}"); + let name = args.name.clone(); + run_tool_envelope("restart", log, async move { + let (resp, retries) = self + .dispatch(hive_sh4re::AgentRequest::Restart { name: args.name }) + .await; + annotate_retries( + format_ack(resp, "restart", format!("restarted {name}")), + retries, + ) + }) + .await + } + // IMPORTANT: this tool is capability-gated (`read_host_journal`). // It is added to `--allowedTools` by `allowed_capability_tools` only // when `HIVE_CAPABILITIES` contains `read_host_journal`. hive-c0re diff --git a/hive-c0re/src/agent_server.rs b/hive-c0re/src/agent_server.rs index 9a5ce8f1..182e3413 100644 --- a/hive-c0re/src/agent_server.rs +++ b/hive-c0re/src/agent_server.rs @@ -361,6 +361,32 @@ async fn dispatch(req: &AgentRequest, agent: &str, coord: &Arc) -> Err(message) => AgentResponse::Err { message }, } } + AgentRequest::Restart { name } => { + // Topology check: the caller must be the direct parent of the + // target. This is the only authorisation criterion — no + // capability flag needed; parenthood is sufficient privilege. + if !crate::topology::children_of(agent) + .iter() + .any(|c| c == name) + { + return AgentResponse::Err { + message: format!( + "agent `{agent}` cannot restart `{name}`: \ + not a direct child in the topology tree" + ), + }; + } + tracing::info!(%agent, %name, "agent: enqueue restart for child"); + coord.rebuild_queue.enqueue( + crate::rebuild_queue::QueueKind::Restart, + name.to_owned(), + crate::rebuild_queue::QueueSource::Manual, + format!("agent `{agent}` restart tool"), + None, + ); + coord.emit_rebuild_queue_snapshot(); + AgentResponse::Ok + } // Manager-only variants are not valid on the agent socket. _ => AgentResponse::Err { message: "request not supported on agent socket".to_owned(),