Watch
0
0
Fork
You've already forked hyperhive
0

grant manage_root_agent by stored permission only, not by the name ruth

Permission::default_for and hive-sh4re's MANAGER_AGENT are gone: every
agent with no permissions key holds Permission::DEFAULT, ruth included.
The agent-name parameters that only fed default_for go with it
(permissions::effective, HiveCopy::before_read/after_read and their
callers).

swarm-controller seeds the grant ruth held by name: at start, a declared
ruth whose permissions are unset gets DEFAULT plus manage_root_agent
written into her key, once, logged. A set key is never touched. It is a
one-shot to delete once every swarm has passed it.

The swarm UI setup assistant opens the create form with
manage_root_agent checked, so a new ruth is created with the grant.
permissions_import no longer adds ruth to the import or splits her
default. Docs and help text no longer say ruth holds the grant by
default; swarmctl-cli.md regenerated.
This commit is contained in:
atlas 2026-10-16 23:10:05 +02:00 • committed by mara
commit 7b5400ecb8
26 changed files with 380 additions and 216 deletions

View file

@ -78,9 +78,9 @@ module docs for the exact call chain.
## Hard-coded manager behaviour
The **manager (`ruth`)** differs from other agents in naming/bootstrap,
its socket flavour and its default permissions; its prompt, tool
allow-list and state dirs work as for every other agent.
The **manager (`ruth`)** differs from other agents in naming/bootstrap
and its socket flavour; its permissions, prompt, tool allow-list and
state dirs work as for every other agent.
<!-- vale write-good.Passive = NO -->
@ -97,13 +97,13 @@ allow-list and state dirs work as for every other agent.
both flavours; matrix, bash and forge don't call it — their
notifications push a todo on the harness's in-agent socket (see
[`docs/turn-loop/mcp.md`](../turn-loop/mcp.md#waking-the-agent-from-inside-the-container)).
- **Storage/mounts** — the manager container gets
- **Storage/mounts** — the `manage_root_agent` permission, which the swarm
UI's setup assistant creates ruth with, gets a container
`/var/lib/hyperhive/agents` bind-mounted RW at `/agents` (so it can
manage any agent's state dir — config isn't authored there, since a
real config change is a PR from a clone), plus RO mounts for
`/applied` (diff against what's deployed) and `/meta` (system-wide
deploy log). That grant is the `manage_root_agent` permission: ruth
holds it by default, and any agent holding it gets the same mounts.
deploy log). Any agent holding it gets the same mounts.
The operator dashboard's `POST /api/meta-update` is the only path
that writes `flake.lock`.
- **Prompt** — identical for every container: `prompts/system.md`
@ -115,8 +115,8 @@ allow-list and state dirs work as for every other agent.
(`filter_role_blocks(SAMPLE, "manager")`).
- **Tool allow-list** — the MCP tools claude sees come from the agent's
permissions alone, the same mechanism for every agent
([`docs/turn-loop/mcp.md`](../turn-loop/mcp.md)). Ruth's default
permissions add only `manage_root_agent` (`Permission::default_for`).
([`docs/turn-loop/mcp.md`](../turn-loop/mcp.md)). Ruth's permissions
are the default plus `manage_root_agent`, stored for her like any grant.
- **State dirs** — _not_ special-cased: `HYPERHIVE_STATE_DIR` is
injected uniformly via `systemd.globalEnvironment` for every
container including the manager, so all token/state paths resolve

View file

@ -270,10 +270,13 @@ dirs.
⚠️ nspawn bakes bind flags at container start, so hive-c0re restarts
an agent, after its current turn, when its `manage_root_agent` changes.
The root agent holds the permission by default: an agent whose record
leaves `permissions` unset gets the default, which includes
`manage_root_agent` for `ruth` and for no other agent. Setting her
permissions without it revokes it.
No agent holds the permission by default: an agent whose record leaves
`permissions` unset gets the default, which doesn't include
`manage_root_agent`, whatever the agent's name. The swarm UI's setup
assistant creates ruth with it. For a ruth that predates that, whose
permissions were unset, swarm-controller writes the default plus
`manage_root_agent` into her key once at start, so she keeps her mounts;
it never touches a key that's already set.
Each proposed repo (`/agents/<n>/config/`) is pre-configured
with `applied` as a git remote pointing at
@ -331,8 +334,10 @@ Differences from sub-agents:
(vs `agent-base`).
- Web UI port via `lifecycle::agent_web_port("ruth")` — same
FNV-1a hash as every other agent (8100..8999 range).
- `set_nspawn_flags` adds two extra binds: `/var/lib/hyperhive/agents`
→ `/agents` (RW) so the root agent can edit per-agent proposed repos,
- The root agent holds `manage_root_agent` (the swarm UI's setup
assistant creates her with it), for which `set_nspawn_flags` adds two extra binds:
`/var/lib/hyperhive/agents` → `/agents` (RW) so the root agent can edit
per-agent proposed repos,
and `/var/lib/hyperhive/applied` → `/applied` (RO) so the root agent
can `git fetch` deployed/failed/denied tags from any agent's
authoritative applied repo (see "Root-agent view of applied" below).

View file

@ -408,7 +408,8 @@ Contents:
to live here; nothing reads or writes it now. An old copy in the meta repo
is harmless and you can delete it.
The root agent has the meta dir RO-mounted at `/meta/`.
An agent holding `manage_root_agent`, normally ruth, has the meta dir
RO-mounted at `/meta/`.
Outside the meta repo, `/var/lib/hyperhive/swarm-agent-permissions.json`
holds the permissions the swarm grants this hive's agents, as