Three handbook pages carried sections an operator never reads, named after source paths and build internals. They move to pages under 4-implementation, and each handbook page keeps a short pointer. - forge.md: the notification poller (what it polls, how it formats, de-duplicates and marks notifications read) is now agent-tools/forge-notify.md. The forge page keeps a short Notifications section. - matrix.md: the retired hive-side matrix code, the evaluation assertions and the fluffychat-web build fixes are now networking/matrix-homeserver.md. - github.md: the Implementation section (how `gh` and `git push` authenticate, and the GitHub poller) is now agent-tools/github.md. docs/README.md and the agent-tools README list the new pages, and AGENTS.md's note on mixed operator and implementation docs now says to move the detail and leave a pointer.
133 lines
7.4 KiB
Markdown
133 lines
7.4 KiB
Markdown
# Swarm forge (Forgejo)
|
|
|
|
Private Forgejo instance running in a nixos-container (`hive-forge`, the
|
|
container and CLI name), used as the
|
|
swarm's persistent code-collaboration surface (issues, PRs, reviews,
|
|
attachments). Configured via `services.hyperhive.swarm.forge.*` (what the
|
|
forge IS to every hive — names, ports, URLs) plus
|
|
`services.hyperhive.deploy.forgejo.*` (what the host running it decides —
|
|
which build it runs, how it's served, what it mirrors, where its
|
|
host-local secrets sit).
|
|
Container
|
|
shape, ROOT_URL / sub-domain routing, and operator-vs-in-cluster URL
|
|
handling live in [`docs/4-implementation/networking/gateway.md`](../../4-implementation/networking/gateway.md); this file owns the
|
|
per-agent integration story and the notification pump that wakes
|
|
each agent on relevant activity.
|
|
|
|
## Token scopes
|
|
|
|
Two scope sets:
|
|
|
|
**`AGENT_TOKEN_SCOPES`** (swarm-controller's `forge::agent_token`, pinned
|
|
by a test). swarm-controller mints every agent token with it:
|
|
|
|
| Scope | Why |
|
|
| -------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
| `write:repository` | Create, clone, push, delete repos; merge PRs. |
|
|
| `write:issue` | Open / comment / review issues **and** pull requests (Forgejo namespaces PR conversation under issues). |
|
|
| `write:user` | Edit own profile, create repos under own user. |
|
|
| `write:organization` | Create + manage orgs (lets agents share a forge namespace). |
|
|
| `read:user` | Token-owner endpoint used for self-identification at harness startup. |
|
|
| `write:misc` | Hooks, attachments, the rest of the long tail. |
|
|
| `read:notification` | Poll `GET /notifications` for unread events. |
|
|
| `write:notification` | Mark notifications read via `PATCH /notifications/threads/{id}`. |
|
|
|
|
**`HIVE_TOKEN_SCOPES`** (swarm-controller's `forge::hive_token`, pinned by a
|
|
test): `read:repository` alone, for each hive's read-only account (next
|
|
section).
|
|
|
|
---
|
|
|
|
## How a hive reads the forge
|
|
|
|
Each hive in swarm-controller's hive directory has its own forge account,
|
|
`hive-<hive>`. swarm-controller creates it, makes it a member of the `hives`
|
|
team in `agent-configs`, and mints one token named `swarm-hive` into the
|
|
swarm secret store at `swarm/hives/<hive>/forge/token`. The team has read
|
|
permission on `repo.code` and `repo.pulls` of every repo in the org,
|
|
including repos created later. A pass at start and every five minutes
|
|
creates what's missing and re-mints a token that's missing or no longer
|
|
matches the forge. A pass whose store or forge reads fail queues nothing, so
|
|
an outage never rotates every hive's token.
|
|
|
|
swarm-controller refuses to create an agent whose name starts with `hive-`:
|
|
these accounts own that prefix. An agent that already had such a
|
|
name keeps it, so the accounts are also told apart by email. swarm-controller
|
|
creates the hive's account with the email `hive-<hive>@hives.hyperhive.local`
|
|
and refuses an account by that name with any other email: it never adds an
|
|
agent's account to the team or mints a token for it. An agent's own forge
|
|
account setup refuses the hive's account the same way.
|
|
|
|
hive-c0re reads the token with `forge::reader_token()`, under the hive's own
|
|
store certificate, every time it reads the forge. A hive whose store holds
|
|
none reads nothing. These reads go through it, and none of them needs a local
|
|
forge container:
|
|
|
|
- cloning and pulling `/knowledge`
|
|
|
|
The hive builds nothing, so no nix process reads the forge as the hive's
|
|
account. hive-c0re hands the token to each `git` command it runs
|
|
(`http.extraHeader`) and keeps no copy on disk. A hive whose store holds no token
|
|
reads nothing private from the forge. This also holds on a hive with no forge
|
|
container.
|
|
|
|
Roll a change to any of this out store host first (its granter writes the
|
|
controller's grant on `swarm/hives/+/forge/token`), then the controller host,
|
|
then the hives. A hive that starts before its token exists reads nothing, and
|
|
builds nothing, until the controller's next pass.
|
|
|
|
---
|
|
|
|
## Per-agent forge accounts
|
|
|
|
Each agent gets its own Forgejo user and access token. swarm-controller
|
|
creates the user when it creates the agent, and mints one token named
|
|
`swarm-agent` with the admin API into the swarm secret store at
|
|
`swarm/agents/<agent>/forge-token`. A pass at start and every five minutes
|
|
covers every agent with a store identity: it creates a missing forge user and
|
|
re-mints any token that's missing or no longer matches the forge;
|
|
a rotation deletes the old `swarm-agent` token first, so each agent holds at
|
|
most one. The agent fetches the token under its own store certificate into
|
|
`/run/hive-agent-forge-token/token` (`nix/agent-modules/forge-token.nix`),
|
|
and `hive-forge`, the git credential helper, the `forge_notify` poller and
|
|
the avatar sync read it from there, falling back to `<state>/forge-token`,
|
|
the file hive-c0re wrote before. hive-c0re no longer creates agent users or
|
|
mints agent tokens. swarm-controller deletes the `hyperhive-<unix-seconds>`
|
|
tokens it left behind, for each agent whose current `swarm-agent` token is
|
|
live; tokens of other names are never touched.
|
|
|
|
Two things live in the `agent-configs` Forgejo organization:
|
|
|
|
- A config repo per agent (`agent-configs/<name>`). The
|
|
agent is a **write collaborator on its own** repo — it can push
|
|
config-change branches and open config PRs — but `main` is
|
|
branch-protected by swarm-controller: the merge and approval
|
|
allowlists are the `operators` team, and the agent can neither push
|
|
`main` directly nor self-merge. An operator's merge in the Forgejo UI
|
|
deploys the merged commit (see
|
|
[config-changes.md § Config changes](../agents/config-changes.md#config-changes)).
|
|
hive-c0re pushes nothing to this org and reads nothing from it.
|
|
Repos stay private, so an agent can't read another
|
|
agent's config. The agent's **persistent meta flake input** is this repo's `main` head,
|
|
pinned by sha in `internal/meta` (`agent-<n>.url =
|
|
git+<forge>/agent-configs/<n>.git?rev=<sha>`; see
|
|
[config-changes.md § Meta flake](../agents/config-changes.md#meta-flake)).
|
|
|
|
The `hive-forge` CLI (separate workspace crate, see
|
|
[`README.md`](../../README.md) file map) wraps the Forgejo REST API
|
|
with the per-agent token; agents call it for issue / PR / comment
|
|
ops as if it were a peer. All REST calls across the workspace
|
|
(`hive-forge` verbs, hive-c0re provisioning, this poller) go through
|
|
the typed `forgejo-api` crate; only non-`/api/v1` web-router routes
|
|
(attachment / artifact downloads, log streaming) and the poller's
|
|
enrichment fetches of server-provided subject URLs stay on raw
|
|
reqwest.
|
|
|
|
## Notifications
|
|
|
|
Each agent runs a small daemon that polls its forge account for unread
|
|
notifications every 30 seconds and hands each one to the agent as a todo, so
|
|
an assignment, a review or a comment wakes the agent. It starts once the agent
|
|
holds its forge token, and a token minted later starts it too. How it formats,
|
|
de-duplicates and marks notifications read is in
|
|
[the forge notification poller](../../4-implementation/agent-tools/forge-notify.md).
|