Watch
0
0
Fork
You've already forked hyperhive
0

archetypes: prefill the create form from flake-declared agent archetypes

A flake declares agent archetypes in its `hyperhiveArchetypes` output,
`<name> = { module; meta; }`. The hyperhive flake ships `reviewer`
(default permissions without `execution`).

swarm-builder answers `$SWARM.builder.archetypes` with the `meta` of
every archetype its own hyperhive source declares. swarm-controller asks
once the queue connects and every 10 minutes, checks each archetype as
`POST /api/agents` checks its settings, and stores the result in the
`agent-archetypes` KV bucket when it changed. `GET /api/archetypes`
serves it, and the create form's archetype select prefills permissions,
resource caps and inference from it.

The agent created is an ordinary agent with its own config repo; the
archetype's module is not applied yet.

Refs #5386
This commit is contained in:
atlas 2026-10-17 00:24:08 +02:00 • committed by mara
commit 51035eac1d
22 changed files with 1244 additions and 30 deletions

87
docs/swarm/archetypes.md Normal file
View file

@ -0,0 +1,87 @@
# Agent archetypes
An archetype is a named set of settings to create an agent from. The swarm
UI's create form lists the archetypes the swarm knows. Picking one fills the
form's permissions, resource caps and inference fields from it, and you can
still change each field before you create the agent.
The agent you create this way is an ordinary agent: it gets its own
`agent-configs/<name>` repo like any other, and the request carries only the
fields as the form shows them. Nothing records which archetype you picked.
## The built-in archetypes
The hyperhive flake ships these:
| archetype | what it sets |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `reviewer` | permissions `messaging`, `meta`, `inbox`: the default set without `execution`. It has no shell, so it can't run `hive-forge`, `git` or any command. |
## Where an archetype comes from
A flake declares archetypes in its `hyperhiveArchetypes` output:
```nix
hyperhiveArchetypes.reviewer = {
module = { };
meta = {
description = "Reviews what it is sent.";
permissions = [ "messaging" "meta" "inbox" ];
limits = { memory_max = "4G"; };
inference = { effort = "high"; };
};
};
```
- `meta` is plain data: no derivation, no path, no function. The swarm
evaluates `meta` alone.
- Every archetype needs a `description`. `permissions`, `limits` and
`inference` are optional and take the shapes `POST /api/agents` takes. The swarm ignores
other keys in `meta`.
- `module` is a NixOS module for the agent's container. The swarm doesn't
apply it yet.
Today the swarm reads one flake: the hyperhive source the
[builder](builder.md)'s host runs, so only the built-ins appear.
## How the list stays current
1. swarm-controller asks the builder for the list on the queue subject
`$SWARM.builder.archetypes` once the queue connects, and every 10 minutes
after that.
2. The builder evaluates the `meta` of each `hyperhiveArchetypes` entry on
its own hyperhive and nixpkgs sources, and answers with the JSON or the
last lines `nix` printed:
```sh
nix eval --json <hyperhive>#hyperhiveArchetypes \
--apply 'builtins.mapAttrs (_: a: a.meta)'
```
3. The controller checks each archetype the way `POST /api/agents` checks
its settings and stores the result in the `agent-archetypes` KV bucket,
under the key `hyperhive`, when it differs from the stored one. The list
leaves out an archetype that fails the check, and its name and reason go
into the record's `refused` map and the controller's journal.
4. `GET /api/archetypes` answers from that record, and the create form lists
from it.
A builder host redeploy can change the list. The next pass, within 10
minutes, picks it up. When no builder answers, the controller keeps the
stored list and logs a warning on each pass. A swarm with no builder enabled
shows no archetype select.
The stored value:
```json
{
"source": "/nix/store/…-hyperhive-flake-source",
"archetypes": {
"reviewer": {
"description": "…",
"permissions": ["messaging", "meta", "inbox"]
}
},
"refused": { "broken": "limits: …" }
}
```