agent capabilities live in a swarm KV record, set from swarmctl
An agent's capabilities move from the hive's meta repo
(`meta/capabilities.json`, injected as `HIVE_CAPABILITIES`) into the
`capabilities` field of its key in a new `agent-permissions` KV bucket,
which swarm-controller alone writes.
- swarm-queue-client: `agent_permissions` (bucket, key, `AgentPermissions`,
direct-get read, the import subject and its wire types).
- swarm-controller: creates the bucket at start; `GET|PUT|DELETE
/api/agents/{name}/permissions` (deny_unknown_fields and unknown
capability ⇒ 422, duplicate ⇒ 400, agent must be declared by a hive);
answers each hive's one-shot import, writing a key only where there is
none and only for agents that hive's wanted state declares.
- swarmctl: `agent permissions get|set|clear`.
- swarm-nats-auth: a hive reads every key of the bucket and sends its
import on its own subject; the controller subscribes to the imports and
may answer them (`responses`).
- hive-c0re: reads each of its agents' keys every 30s into
/var/lib/hyperhive/swarm-agent-permissions.json and restarts an agent,
gracefully, when its capabilities change. Unset is the compiled-in
default (ruth: manage_root_agent; everyone else: none). A failed read
keeps the stored value. On first boot it seeds that file from
meta/capabilities.json, sends the grants to the controller, and deletes
the file once the controller answers.
Deleted: the capabilities.json reader/writer, `HIVE_CAPABILITIES` in the
rendered meta flake, ruth's capability seed, the capabilities half of the
permissions rebuild job (`PermPayload::Capabilities`/`Combined`), the
dashboard's capabilities table and `capabilities_changed` event, and the
now-unused `Capability::description`.
Part of #5170.
This commit is contained in:
parent
fcda1f4a04
commit
f862354e43
47 changed files with 1943 additions and 1146 deletions
|
|
@ -1,8 +1,9 @@
|
|||
//! Per-agent authorization: named MCP-tool groups (`ToolGroup`) and
|
||||
//! system-level capability grants (`Capability`). Both are declared in
|
||||
//! per-agent config (`tool-groups.json` / `capabilities.json`), injected
|
||||
//! into the container as env vars, and read by the harness to decide
|
||||
//! which MCP tools claude actually sees.
|
||||
//! system-level capability grants (`Capability`). Tool groups are declared
|
||||
//! in the hive's `tool-groups.json`, injected into the container as an env
|
||||
//! var, and read by the harness to decide which MCP tools claude actually
|
||||
//! sees. Capabilities are granted in the swarm's `agent-permissions` bucket
|
||||
//! and enforced by hive-c0re.
|
||||
//!
|
||||
//! It also resolves the *built-in* claude tool list ([`builtin_tools_arg`]):
|
||||
//! that set is group-gated too (`web_tools`), so it belongs next to the
|
||||
|
|
@ -154,11 +155,11 @@ pub enum ToolGroup {
|
|||
Inbox,
|
||||
/// Gates no tool today — `list_containers`, its only member, was
|
||||
/// removed with no replacement. Kept so existing
|
||||
/// `meta/capabilities.json` grants still parse; `tools()` returns
|
||||
/// `meta/tool-groups.json` grants still parse; `tools()` returns
|
||||
/// `&[]`.
|
||||
Lifecycle,
|
||||
/// Gates no tool today — `create_repo`, its only member, was removed
|
||||
/// with no replacement. Kept so existing `meta/capabilities.json`
|
||||
/// with no replacement. Kept so existing `meta/tool-groups.json`
|
||||
/// grants still parse; `tools()` returns `&[]`.
|
||||
Forge,
|
||||
/// Gates whether the `bash` MCP server (`mcp__bash__run`/`status`/
|
||||
|
|
@ -323,16 +324,12 @@ impl ToolGroup {
|
|||
}
|
||||
}
|
||||
|
||||
/// Per-agent capability grants. Stored in `meta/capabilities.json`
|
||||
/// (same shape as `tool-groups.json`: `{ "alice": ["manage_root_agent"] }`).
|
||||
/// Capabilities control system-level access hive-c0re enforces at
|
||||
/// dispatch time; they are orthogonal to tool groups (which control
|
||||
/// which MCP tools the harness exposes to claude).
|
||||
///
|
||||
/// Injected into containers as `HIVE_CAPABILITIES` (comma-separated
|
||||
/// `snake_case`) via `meta::render_flake`. The harness reads this to
|
||||
/// conditionally register capability-gated MCP tools so claude only
|
||||
/// sees tools it can actually invoke. See `docs/process/conventions.md::Capabilities`.
|
||||
/// Per-agent capability grants: the `capabilities` field of the swarm's
|
||||
/// `agent-permissions` record (`swarm_queue_client::agent_permissions`), set
|
||||
/// with `swarmctl agent permissions set`. Capabilities control system-level
|
||||
/// access hive-c0re enforces, through the container's bind mounts; they are
|
||||
/// orthogonal to tool groups (which control which MCP tools the harness
|
||||
/// exposes to claude). See `docs/process/conventions.md::Capabilities`.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, strum::IntoStaticStr)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
|
|
@ -348,26 +345,14 @@ pub enum Capability {
|
|||
/// there was. With the hierarchy removed there is no privileged root
|
||||
/// to single out, so the same grant now means "manage any agent".
|
||||
/// Kept under the old spelling deliberately — renaming it would turn
|
||||
/// every `manage_root_agent` already stored in `capabilities.json`
|
||||
/// into an unrecognised name that `capabilities::prune_unknown`
|
||||
/// silently drops.
|
||||
/// every `manage_root_agent` already stored in a swarm record into a
|
||||
/// name the hive can no longer decode.
|
||||
ManageRootAgent,
|
||||
}
|
||||
|
||||
impl Capability {
|
||||
/// Every known capability in a stable order. Use this to enumerate
|
||||
/// columns in the permissions UI or validate incoming capability strings.
|
||||
/// Every known capability in a stable order.
|
||||
pub const ALL: &'static [Self] = &[Self::ManageRootAgent];
|
||||
|
||||
/// Short human-readable description suitable for a tooltip or help text.
|
||||
#[must_use]
|
||||
pub fn description(self) -> &'static str {
|
||||
match self {
|
||||
Self::ManageRootAgent => {
|
||||
"manage any agent: every agent's state (rw) and config (ro) mounted for recovery"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
Loading…
Reference in a new issue