From 1e04047059df47feadff386b62900fc3f4f296c5 Mon Sep 17 00:00:00 2001 From: iris Date: Tue, 2 Jun 2026 11:00:17 +0200 Subject: [PATCH 1/3] docs(conventions): add Capabilities section parallel to Tool groups Capabilities were added with the permissions tab but conventions.md only documented tool groups. Adds a full Capabilities section covering: the known capabilities table, config storage path, HIVE_CAPABILITIES env var injection, runtime resolution, operator-only grant constraint, and the pattern for adding a new capability. --- docs/conventions.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/conventions.md b/docs/conventions.md index 7c6f465c..3a94076a 100644 --- a/docs/conventions.md +++ b/docs/conventions.md @@ -316,6 +316,46 @@ or `ManagerServer` in `hive-ag3nt/src/mcp.rs`, add its name to the matching `ToolGroup::tools()` slice in `hive-sh4re/src/lib.rs`. That's the single source of truth; `allowed_mcp_tools` reads it at session start. +## Capabilities + +Capabilities gate system-level access that goes beyond the MCP tool surface — +things an agent can *access*, not just *call*. Parallel to tool groups but +orthogonal: an agent can have a tool group that registers a tool AND a capability +that allows the underlying resource access. + +| Capability | Effect | +|---|---| +| `manage_root_agent` | may lifecycle-manage the root/manager agent via `kill`/`start`/`restart` | +| `read_host_journal` | `get_host_journal` MCP tool is registered + `GET /journal-host` requests are served | +| `query_agent_state` | may call `get_loose_ends` / `CountPendingReminders` targeting non-child agents | + +**Config storage** — per-agent capabilities live in +`/var/lib/hyperhive/meta/capabilities.json` alongside `tool-groups.json`. +Format: `{ "atlas": ["read_host_journal"], "root": ["manage_root_agent"] }`. +An absent entry means "no extra capabilities". `render_flake` in `meta.rs` +reads this file and injects `HIVE_CAPABILITIES` (comma-separated +`snake_case` names) into each agent's systemd service env; absent entries emit +no env var so agents without capabilities don't trigger a spurious rebuild. + +**Setting capabilities** — the operator sets capabilities via the +C4P4B1L1T13S section in the dashboard's P3RM1SS10NS tab. +`hive-c0re::capabilities::set_caps(name, caps)` is the write path. +After a change `meta::sync_agents` commits the updated file; the next agent +rebuild picks up the new `HIVE_CAPABILITIES` env var. + +**Runtime resolution** — at session start the harness reads `HIVE_CAPABILITIES` +and resolves each token to a `Capability` variant. Unrecognised tokens are +logged and skipped. An absent or empty var means no extra capabilities. + +**Capability NOT configurable from `agent.nix`** — same reasoning as tool +groups: an agent that could grant its own capabilities via a config commit would +bypass the operator approval gate. + +**Adding a new capability** — add a variant to `Capability` in +`hive-sh4re/src/lib.rs` + an arm to `as_str`. Add it to `Capability::ALL` (the +source of truth for the permissions UI columns). Implement the access check in +the relevant handler (`agent_server.rs`, `mcp.rs`, or `dashboard.rs`). + ## Async forms Dashboard + per-agent mutating forms carry `data-async`; a delegated From febb10a7d7ffa17734ba69f2e1ea474fee843359 Mon Sep 17 00:00:00 2001 From: iris Date: Tue, 2 Jun 2026 11:04:28 +0200 Subject: [PATCH 2/3] docs(CLAUDE.md): note capabilities in conventions.md file map entry --- CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index dc2fe3e4..28e4272e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -317,7 +317,7 @@ nix/ forge-theme/theme-catppuccin-vibec0re.css Catppuccin Mocha forge theme docs/ - conventions.md naming, identity=socket, tool groups, async forms, commit style + conventions.md naming, identity=socket, tool groups, capabilities, async forms, commit style gotchas.md NixOS / nspawn quirks and lessons learned web-ui.md index → web-ui/shape.md (shared skeleton, SSE, terminal, listener bind, relative paths, atomic From 50f14f28ff6a2023fa96803da28f959c059d0cbf Mon Sep 17 00:00:00 2001 From: iris Date: Tue, 2 Jun 2026 11:29:58 +0200 Subject: [PATCH 3/3] fix(dashboard): have get_capabilities iterate Capability::ALL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hardcoded vec was a maintenance hazard — any new capability added to Capability::ALL would silently be omitted from the permissions UI column list until get_capabilities was manually updated. Now both the GET and POST handlers derive their known-capability lists from the same Capability::ALL source of truth. --- hive-c0re/src/dashboard.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hive-c0re/src/dashboard.rs b/hive-c0re/src/dashboard.rs index d2af3218..87519331 100644 --- a/hive-c0re/src/dashboard.rs +++ b/hive-c0re/src/dashboard.rs @@ -2571,12 +2571,7 @@ struct CapabilitiesSnapshot { } async fn get_capabilities(State(_state): State) -> axum::Json { - use hive_sh4re::Capability; - let caps = vec![ - Capability::ManageRootAgent.as_str(), - Capability::ReadHostJournal.as_str(), - Capability::QueryAgentState.as_str(), - ]; + let caps = hive_sh4re::Capability::ALL.iter().map(|c| c.as_str()).collect(); let assignments = crate::capabilities::read(); axum::Json(CapabilitiesSnapshot { caps, assignments }) }