Watch
0
0
Fork
You've already forked hyperhive
0

drop the proposed config repo: applied seeds from forge main, and the dead pending-init topology list goes with it

This commit is contained in:
damocles 2026-11-01 14:25:46 +01:00 • committed by mara
commit 25295fd33f
2 changed files with 225 additions and 520 deletions

View file

@ -102,7 +102,7 @@ body strings before calling it.
`HostRequest::Destroy { name, purge }` is the lifecycle tear-down.
Stops + removes the nspawn container and drops the systemd drop-in.
Persistent state (proposed/applied repos, claude credentials, `/state/`
Persistent state (the applied repo, claude credentials, `/state/`
notes) is
**kept by default** — recreating the agent with the same name
reuses prior config + login. With `purge = true` the agent's
@ -186,20 +186,10 @@ the swarm builder built the agent from the updated repo (the
reconcile ([below](#autoupdate-on-startup)) and the dashboard's update chip
read them.
## Two repos per agent
## The applied repo per agent
```
/var/lib/hyperhive/agents/<name>/config/ proposed — parent mount is RO
└── <anything> # any files the submitting
# agent wants in the commit.
# agent.nix is the
# convention entry
# point; flake.nix is
# tracked boilerplate
# (submitting agent doesn't
# edit it).
/var/lib/hyperhive/applied/<name>/ applied — core-only
/var/lib/hyperhive/applied/<name>/ applied - core-only
├── .git/ # tag-rich history
├── flake.nix # tracked, fixed
│ # boilerplate exporting
@ -207,16 +197,18 @@ the swarm builder built the agent from the updated repo (the
├── agent.nix # working tree of main
└── <other committed files> # also tracked
/var/lib/hyperhive/meta/ plain hive state — core
/var/lib/hyperhive/meta/ plain hive state - core
├── topology.json # the live agent set
└── swarm-resource-limits.json # the swarm's per-agent caps
```
Why two physical repos: the submitting agent's `/agents/<n>/config/` is
RW — a buggy or hostile agent can `git clean -fdx` its own
proposed tree. The applied repo is never bind-mounted (except
the read-only `.git` exposure described below) so a destructive
move inside the container can't reach it.
hive-c0re seeds the applied repo at first spawn from the forge's
`agent-configs/<name>` `main`, or from a template when the forge has none yet,
and fast-forwards it to each merged config commit that deploys. An agent never
edits it: the agent sees it read-only at `/agents/<name>/config`, so it can
read what governs it, while a config change is a PR against its forge repo.
Older hives also kept a *proposed* clone at `agents/<name>/config`. Nothing
reads it any more, and you can delete it.
The container's `--flake` ref is `internal/meta` (see "Meta flake" above).
The agent's own `applied/<n>/flake.nix`
@ -240,9 +232,8 @@ Every agent created through the swarm has a repo in the private
`agent-configs` Forgejo org, created and seeded by swarm-controller.
hive-c0re pushes nothing to it: the applied repo's tags (`deployed/0`)
exist only locally, and forge `main` advances only by an operator's merge.
hive-c0re reads from it — reseeding a purged `applied`
(`forge::fetch_config_main_into_applied`), catching `applied` up, and
seeding `proposed` at first spawn (`forge::clone_config_into_proposed`).
hive-c0re reads from it - reseeding a purged `applied`, catching `applied` up, and
and seeding `applied` at first spawn (`forge::fetch_config_main_into_applied`).
A legacy agent spawned by the hive alone has no swarm-seeded repo; if its
`agent-configs/<name>` has no `main`, a first spawn falls back to the local
@ -284,9 +275,9 @@ the swarm's `agent-permissions` record; see
`docs/process/conventions.md#permissions`) get additional host-side bind
mounts via `set_nspawn_flags`:
- `/var/lib/hyperhive/agents/` → `/agents/` (RW) — **every** agent's
proposed repo, not just direct children. The permission means "may
manage any agent", so the mounted set is every agent.
- `/var/lib/hyperhive/agents/<n>/state` → `/agents/<n>/state` (RW) for
**every** agent, and `/agents/<n>/config` (RO, the applied repo). The
permission means "may manage any agent," so the mounted set is every agent.
- `/var/lib/hyperhive/applied/` → `/applied/` (RO) — every agent's
authoritative applied repo, including `.git`.
- `/var/lib/hyperhive/meta/` → `/meta/` (RO) — the hive's plain state
@ -306,17 +297,13 @@ 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
`/applied/<n>/.git`. Useful incantations from inside an agent with
the full `/applied` mount:
With the full `/applied` mount, an agent can read what hive-c0re deployed,
failed or denied for any agent:
```sh
git -C /agents/<n>/config fetch applied
git -C /agents/<n>/config log applied/main --oneline
git -C /agents/<n>/config show applied/refs/tags/deployed/0 # the seed commit
git -C /agents/<n>/config show applied/refs/tags/denied/<id> # body = operator note
git -C /agents/<n>/config rebase applied/main # base in-flight work on what's deployed
git -C /applied/<n> log main --oneline
git -C /applied/<n> show refs/tags/deployed/0 # the seed commit
git -C /applied/<n> show refs/tags/denied/<id> # body = operator note
```
The RO binds block push at the kernel level — git plumbing inside the
@ -333,17 +320,16 @@ once already applied:
`deployed/0` on `main` once. Non-destructive — it doesn't touch live
containers, state dirs, or claude creds.
- **Agent files**: rewrites each `applied/<n>/flake.nix` to the
module-only boilerplate, wires the `applied` remote in each proposed
repo, and refreshes the files that follow the agent set
module-only boilerplate and refreshes the files that follow the agent set
(`agent_set::refresh`) from the current agent list. Set
`HIVE_SKIP_META_MIGRATION=1` on the service to defer this phase.
- **Legacy meta repo**: deletes the leftover `.git` in
`/var/lib/hyperhive/meta/`, the `meta` remote in each proposed repo and the
`/var/lib/hyperhive/meta/` and the
unread `/var/lib/hyperhive/forge-core-token`. The files beside the `.git`
stay. The forge-side `core/meta` repo and `core` account aren't touched.
No state loss in either migration: claude creds, `/state/` notes, the
events DB, and both proposed + applied history all survive. The root
events DB, and the applied history all survive. The root
agent keeps its session; sub-agents stay logged in.
## The root/bootstrap container
@ -352,8 +338,7 @@ The root agent container runs through the **same lifecycle as
sub-agents**. Nothing creates it at hive boot: you create ruth from the
swarm dashboard like any agent, and an existing ruth container starts with
the hive like every other. The root agent's flake lives at
`/var/lib/hyperhive/applied/ruth/`; its proposed config at
`/var/lib/hyperhive/agents/ruth/config/`. The root agent can edit its own
`/var/lib/hyperhive/applied/ruth/`. The root agent can read its own
`agent.nix` (visible inside the container at `/agents/ruth/config/`)
and open a config PR on `agent-configs/ruth` for operator review,
same as any other agent.
@ -368,8 +353,7 @@ Differences from sub-agents:
FNV-1a hash as every other agent (8100..8999 range).
- 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,
`/var/lib/hyperhive/agents` → `/agents` (RW) for every agent's state,
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

@ -254,11 +254,9 @@ than an accident of storage.
Under `/var/lib/hyperhive/agents/<name>/`:
- `config/` — the proposed nix repo (root-agent-editable). Bind-mounted
**read-only** to `/agents/<name>/config` inside the sub-agent's own
container so the agent can inspect what defines it and request
precise changes from the root agent; RW into the root agent via the
`/agents` tree bind.
- `config/` — unused. Older hives kept a proposed nix repo here; nothing
reads it any more, and you can delete it. The agent's config mount at
`/agents/<name>/config` is the applied repo, read-only.
- `claude/` — claude OAuth credentials, bind-mounted RW to
`/home/<name>/.claude` inside the container.
- `state/` — durable notes and `hyperhive-harness.json`. Bind-mounted
@ -487,7 +485,7 @@ boundary a convention rather than a permission.
<!-- vale write-good.Passive = NO -->
⚠️ Don't confuse it with the config-repo seeding hive-c0re does at
spawn (`lifecycle::setup_proposed`): that writes the agent's initial
spawn (`lifecycle::setup_applied`): that writes the agent's initial
config repo as **hive-c0re, against the host path**, and `read_only` on a bind
constrains writers *inside* a container only. The two are unrelated —
conflating them can lead you to reason your way into thinking this