manager: start/restart at will, no approval; refuse self
new manager tools mcp__hyperhive__{start,restart} that delegate to the
existing lifecycle::start / lifecycle::restart on the host. kill was
already at the manager's discretion; rounding out start + restart for
parity so day-to-day container care doesn't have to round-trip through
the operator.
guard: refuse self-targeting on kill/start/restart — the manager would
just be cutting its own legs. spawn (request_spawn) and config changes
(request_apply_commit) still go through the approval queue, since those
are the actual gate. prompt + claude.md updated to make the boundary
explicit. kill now also emits HelperEvent::Killed (it didn't before).
This commit is contained in:
parent
d943bddd9e
commit
ac1b5fde8e
6 changed files with 104 additions and 3 deletions
|
|
@ -41,6 +41,10 @@ enum Cmd {
|
|||
RequestSpawn { name: String },
|
||||
/// Kill a sub-agent.
|
||||
Kill { name: String },
|
||||
/// Start a stopped sub-agent.
|
||||
Start { name: String },
|
||||
/// Restart a sub-agent (stop + start).
|
||||
Restart { name: String },
|
||||
/// Submit a config commit on the agent's config repo for user approval.
|
||||
RequestApplyCommit { agent: String, commit_ref: String },
|
||||
/// Run the manager MCP server on stdio. Spawned by claude via
|
||||
|
|
@ -103,6 +107,8 @@ async fn main() -> Result<()> {
|
|||
one_shot(&cli.socket, ManagerRequest::RequestSpawn { name }).await
|
||||
}
|
||||
Cmd::Kill { name } => one_shot(&cli.socket, ManagerRequest::Kill { name }).await,
|
||||
Cmd::Start { name } => one_shot(&cli.socket, ManagerRequest::Start { name }).await,
|
||||
Cmd::Restart { name } => one_shot(&cli.socket, ManagerRequest::Restart { name }).await,
|
||||
Cmd::RequestApplyCommit { agent, commit_ref } => {
|
||||
one_shot(
|
||||
&cli.socket,
|
||||
|
|
|
|||
|
|
@ -211,6 +211,18 @@ pub struct KillArgs {
|
|||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||
pub struct StartArgs {
|
||||
/// Sub-agent name (without the `h-` container prefix).
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||
pub struct RestartArgs {
|
||||
/// Sub-agent name (without the `h-` container prefix).
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
|
||||
pub struct AskOperatorArgs {
|
||||
/// The question to surface on the dashboard.
|
||||
|
|
@ -308,7 +320,7 @@ impl ManagerServer {
|
|||
|
||||
#[tool(
|
||||
description = "Stop a sub-agent container (graceful). The state dir is kept; \
|
||||
recreating reuses prior config + Claude credentials."
|
||||
recreating reuses prior config + Claude credentials. No approval required."
|
||||
)]
|
||||
async fn kill(&self, Parameters(args): Parameters<KillArgs>) -> String {
|
||||
let log = format!("{args:?}");
|
||||
|
|
@ -322,6 +334,35 @@ impl ManagerServer {
|
|||
.await
|
||||
}
|
||||
|
||||
#[tool(
|
||||
description = "Start a stopped sub-agent container. No approval required — \
|
||||
lifecycle ops on existing containers are at the manager's discretion."
|
||||
)]
|
||||
async fn start(&self, Parameters(args): Parameters<StartArgs>) -> String {
|
||||
let log = format!("{args:?}");
|
||||
let name = args.name.clone();
|
||||
run_tool_envelope("start", log, async move {
|
||||
let resp = self
|
||||
.dispatch(hive_sh4re::ManagerRequest::Start { name: args.name })
|
||||
.await;
|
||||
format_ack(resp, "start", format!("started {name}"))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
#[tool(description = "Restart a sub-agent container (stop + start). No approval required.")]
|
||||
async fn restart(&self, Parameters(args): Parameters<RestartArgs>) -> String {
|
||||
let log = format!("{args:?}");
|
||||
let name = args.name.clone();
|
||||
run_tool_envelope("restart", log, async move {
|
||||
let resp = self
|
||||
.dispatch(hive_sh4re::ManagerRequest::Restart { name: args.name })
|
||||
.await;
|
||||
format_ack(resp, "restart", format!("restarted {name}"))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
#[tool(
|
||||
description = "Surface a question to the operator on the dashboard. Returns immediately \
|
||||
with a question id — do NOT wait inline. When the operator answers, a system message \
|
||||
|
|
@ -426,6 +467,8 @@ pub fn allowed_mcp_tools(flavor: Flavor) -> Vec<String> {
|
|||
"recv",
|
||||
"request_spawn",
|
||||
"kill",
|
||||
"start",
|
||||
"restart",
|
||||
"request_apply_commit",
|
||||
"ask_operator",
|
||||
],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue