remove the list_containers and request_update_meta_inputs MCP tools

Both agent-facing tools go away end to end, with no replacement. This is
an intentional capability removal: agents can no longer enumerate their
own subtree, and can no longer queue a meta-flake input bump.

The system prompt and docs/tools/lifecycle.md land in this same commit
on purpose. A tool named in the prompt but absent from the server makes
agents confidently call something that doesn't exist, and the failure
then surfaces far from its cause.

Removed:

- MCP registrations and bodies (hive-agent-mcp), plus the now-unused
  UpdateMetaInputsArgs.
- Wire variants Request::ListDescendants,
  Request::RequestUpdateMetaInputs and Response::Containers, plus
  ContainerInfo, whose only consumer was that response.
- hive-c0re's handle_list_descendants (its whole module) and
  handle_request_update_meta_inputs, the two dispatch arms, and the
  require_group(agent, "approvals", ...) gate on the meta-inputs verb.
- The stream_enrich emoji entry and argument formatter.
- docs/tools/lifecycle.md (both tools it documented are gone), its two
  referrers, the tool-group tables and the agent-hierarchy prose.

Tool groups are kept, deliberately. ToolGroup::Lifecycle listed exactly
one tool and now lists none — it is vestigial, but the variant stays so
existing meta/capabilities.json grants still parse; retiring it is a
separate decision. ToolGroup::Approvals also listed exactly one tool,
but the group is NOT dead: check_can_cancel_approval still gates
cancel_loose_end's approval-cancel arm on it server-side.

ApprovalKind::UpdateMetaInputs stays too. Nothing in production code
produces it any more, but pre-existing approval rows may still carry it,
and the operator's own path to a meta update is unaffected — the
dashboard's POST /api/meta-update inserts the meta_update job directly,
bypassing approvals entirely.

The two format_ack tests in hive-agent-mcp that named
request_update_meta_inputs were only using it as a label string while
exercising the generic OkWarn/Ok renderer, so they are retargeted to a
surviving tool rather than deleted.

Note hive-c0re's priv_client::list_containers is a different thing (the
host-side privileged container listing behind hive-priv) and is
untouched.

Closes #4591
This commit is contained in:
atlas 2026-09-20 19:36:09 +02:00 • committed by mara
commit b88a5b2430
18 changed files with 74 additions and 356 deletions

View file

@ -131,17 +131,6 @@ pub struct CancelLooseEndArgs {
pub id: i64,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct UpdateMetaInputsArgs {
/// Flake input names to update (e.g. `["bitburner-agent", "nixpkgs"]`).
/// Pass an empty list to update ALL inputs.
#[serde(default)]
pub inputs: Vec<String>,
/// Optional description shown on the dashboard approval card.
#[serde(default)]
pub description: Option<String>,
}
#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct RequestSchedulePromptArgs {
/// Recipient agents — one schedule fires to many inboxes at the

View file

@ -26,7 +26,7 @@ mod render;
pub use args::{
AckUntilArgs, CancelLooseEndArgs, CancelScheduleArgs, CompactArgs, CreateRepoArgs,
EditScheduleArgs, FireScheduleNowArgs, GetAgentMetaArgs, GetHostJournalArgs, MarkTodosDoneArgs,
RecvArgs, RemindArgs, RequestSchedulePromptArgs, SendArgs, SetStatusArgs, UpdateMetaInputsArgs,
RecvArgs, RemindArgs, RequestSchedulePromptArgs, SendArgs, SetStatusArgs,
};
pub use render::{annotate_retries, format_ack, format_agent_meta, format_recv};
@ -547,44 +547,6 @@ impl AgentServer {
.await
}
// IMPORTANT: this tool is only available when the `lifecycle` tool group
// is granted to this agent. Returns the calling agent's whole subtree,
// itself included, with running status.
#[tool(
description = "List this agent's whole subtree — children, their children, and so on \
down — with running status. The calling agent is part of its own subtree, so it \
appears in the listing too. Requires the `lifecycle` tool group. \
Returns every known descendant regardless of running state — check the `running` \
field to distinguish live from stopped containers. Ordered by topology depth \
(parents before children), then alphabetically within each tier."
)]
async fn list_containers(&self) -> String {
run_tool_envelope("list_containers", String::new(), async move {
let (resp, retries) = self
.dispatch(hive_core_agent_sock::Request::ListDescendants)
.await;
let body = match resp {
Ok(hive_core_agent_sock::Response::Containers { containers }) => {
if containers.is_empty() {
"no descendant containers".to_owned()
} else {
containers
.iter()
.map(|c| {
let status = if c.running { "running" } else { "stopped" };
format!("{} ({})", c.name, status)
})
.collect::<Vec<_>>()
.join("\n")
}
}
other => reply_err(other, "list_containers"),
};
annotate_retries(body, 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
@ -627,43 +589,6 @@ impl AgentServer {
.await
}
#[tool(
description = "Queue an approval for the operator to run `nix flake update` on the \
meta flake and commit the resulting lock changes. Pass specific input names to update \
only those inputs (e.g. `[\"bitburner-agent\"]`), or pass an empty list to update ALL \
inputs. Returns immediately — the lock update runs when the operator approves. \
Does NOT trigger container rebuilds — the operator rebuilds affected agents \
after the approval resolves."
)]
async fn request_update_meta_inputs(
&self,
Parameters(args): Parameters<UpdateMetaInputsArgs>,
) -> String {
let log = format!("{args:?}");
run_tool_envelope("request_update_meta_inputs", log, async move {
let label = if args.inputs.is_empty() {
"all inputs".to_string()
} else {
args.inputs.join(", ")
};
let (resp, retries) = self
.dispatch(hive_core_agent_sock::Request::RequestUpdateMetaInputs {
inputs: args.inputs,
description: args.description,
})
.await;
annotate_retries(
format_ack(
resp,
"request_update_meta_inputs",
format!("approval queued: {label}"),
),
retries,
)
})
.await
}
#[tool(
description = "Queue an approval to add a scheduled prompt — one body delivered to \
N agent inboxes at a target time, optionally recurring every `interval_seconds`. \

View file

@ -643,12 +643,12 @@ mod tests {
Ok(hive_core_agent_sock::Response::OkWarn {
warnings: vec!["name is reserved".to_owned(), "second thing".to_owned()],
}),
"request_update_meta_inputs",
"update_meta_inputs approval queued".to_owned(),
"request_schedule_prompt",
"schedule approval queued".to_owned(),
);
// The operation HAPPENED — dropping the success line would read as a
// failure and invite a retry that queues a second approval.
assert!(out.starts_with("update_meta_inputs approval queued"));
assert!(out.starts_with("schedule approval queued"));
assert!(out.contains("⚠️ name is reserved"));
assert!(out.contains("⚠️ second thing"));
}
@ -659,7 +659,7 @@ mod tests {
// warning marker would pass the test above.
let out = format_ack(
Ok(hive_core_agent_sock::Response::Ok),
"request_update_meta_inputs",
"request_schedule_prompt",
"queued".to_owned(),
);
assert_eq!(out, "queued");