The card and its detail showed the message alone, so a message from an hour
ago read like the current one. Both now add the age, (5m ago), which ticks
like the other relative times. An agent with no message still shows a dash.
- swarm-archive.nix, lib/archive-server.nix: deploy.archive.backend and
deploy.archive.s3.* options; the s3 server and the prune read the key from the
store into rclone's environment; the prune lists and addresses repositories
through rclone instead of a local directory
- swarm-bao.nix: the archive reads swarm/services/archive/s3/*
- docs: archive.md "External S3" section, two credentials-reference rows
- module-eval: builder.nix cases for local and s3, the missing-setting
assertion; bao-grants.nix gains the s3 read grant
- vm test: second node with a fake rclone serve s3 whose key is generated at
test time
The controller's status, queue, AGENTS.md and forge-webhook details move to
4-implementation/swarm/controller.md. The metrics, logs and OTEL detail moves to
4-implementation/swarm/telemetry.md. Each leaves a short operator blurb with the
options to touch, and links into the moved text are updated.
The directory covered GitHub and GitLab only; the forge and matrix account
kinds an operator can link were described under the swarm UI page. Two new
pages (forgejo.md, matrix.md) cover linking, what the agent gets and
deleting in operator terms, the directory README lists them, and the UI page
keeps a pointer for each kind.
The card header carried a fresh/stale badge with the report's age. It now
sits in the status row of the opened card, which already showed it, and the
card header keeps the name, the message and the controls.
Removes the model pill and the ctx chip from the hive dashboard's container
rows, with their styles and the page's fingerprint field. The agent's own
status already carries context and cost in the swarm UI.
The board gained a Runner filter and one series per runner; the CI runner
section now says what the board shows and how it differs from the forge's CI
runs tab.
The panels took the max or sum over the one swarm runner. A runner variable
(the series' service.instance.id) filters every panel, and uptime, job slots
and slot use show one series per runner, so a runner registered by hand shows
up beside the swarm's once its metrics reach the store.
A client chooses a snapshot's time, so snapshots dated ahead could fill
--keep-last and push the real ones out of a prune. The prune now forgets
snapshots dated more than an hour after now first, and logs their ids. The
VM test forges one and checks the real snapshot stays. The bao-grants case
that read a + path as a glob now names the literal path, and two cases that
pinned 'nothing else' list the archive grants. The ciRunner stanza is back
at its original indent.
The archive host creates a ready marker in the store and swarm-controller
writes no credentials before it exists, so a swarm without an archive, and a
mixed-version swarm, leave every hive backup a logged no-op. A hive with no
declaration no longer counts as placing nothing: its copies and its agents'
user lines stay. The restic password is pinned by tests across a revoke, a
re-placement and a move.
swarm-archive serves restic repositories with rclone, append-only, one login
and one repository per agent. swarm-controller writes each placed agent's
login and restic password to the store, replaces them on a move and removes
them when the agent is destroyed. Every hive backs its agents up hourly under
its own store identity. The archive host prunes by retention.
the harness writes the reason into the pause marker when it pauses itself and reports it as paused_by_hive in its turn-state header. swarm-controller declares such an agent paused (only if declared up) and shows the reason on the agents status row and the swarm ui card.
The jq filter used contains(), which matches substrings per element, so an agent named spawn-two satisfied spawn. It now counts the exact names iris and spawn among the fresh agents that need a login.
On a timed-out wait, diagnose() prints systemctl --failed for the machine
or container and the last 50 journal lines of the units waited on. It no
longer prints `systemctl status` for them. Only the failure path changes.
A last subtest polls GET /api/agents/status on the controller socket until
iris and spawn are fresh with needs_login true, through settle() with up to
40 minutes. The header's green condition is now this check, and its note on
what is not scripted yet drops the agents' deploy.
mara chose on the PR to test a reviewer-archetype agent named spawn first
and leave a custom root agent (ruth) for later. So the test creates spawn
with the archetype's default permissions and drops manage_root_agent, which
only ruth carried.
- hive-meta-flake/testdata/meta-flake-swarm.nix.in: the agent is spawn, and
its web port is 8316, the port the name hashes to (ruth's was 8232).
- hive-meta-flake/src/lib.rs: the unit test that compares this fixture with
the rendered flake renders spawn instead of ruth.
- nix/vm-tests/full-setup.nix: the agents list and step 8 use spawn.
- The `swarmctl setup status` expectation keeps its "9 ruth created and up"
row: that is the product's fixed step text (swarmctl/src/setup.rs), not the
test's agent. The test creates no root agent, so step 9 is expected to be
not done, and the subtest's comment says so.
A delete removes the leaf's metadata, so the KV number restarts at 1. A login
made right after a delete, before the next poll, was version 1 again and
looked no newer than the recorded 1, so it never installed. The version file
now records the store's write time next to the number and a later write
installs whatever its number. A record from before the time was kept falls
back to the number and gets its time when the same number is read again.
With the harness poll, an agent that holds a session logs out within 5
minutes of its stored login being deleted. The confirmation and the
claude-login page said the agent keeps its session.
wait_for_login read the store leaf only while the agent waited for a login.
A logged-in agent now reads it every 5 minutes, and a paused one once before
it resumes, so a login made or deleted in the swarm UI reaches an agent that
never failed. A newer version is installed; a store that answers nothing
stored after a version was installed means the stored login was deleted, and
the agent is logged out as /api/logout does it, with the recorded version
forgotten so the next login installs. A read that fails changes nothing.
The report had an approvals column (1/2) and a separate approved column.
They are one fact, so approvals now carries the filter, complete or missing,
and the approved column is gone.
The dialog only said the agent has to log in again, which reads as a logout.
It now says the agent is not logged out and keeps its current session, and a
delete that succeeded shows the empty row at once instead of waiting on the
re-read.
The agent's settings get a claude login row: when the swarm stored the
login, read by the minter from the leaf's metadata, or that none is, with a
delete that removes every version after a confirmation. New minter steps
(status, delete), controller routes (GET claude-login, DELETE
claude-login/stored) and a read and delete grant on the leaf's metadata,
pinned in the module-eval check.
The first-run page opened with ten hand-run steps and a pointer to the
interactive tool. It now opens with swarmctl setup, a sample session and a
sample of setup status, and the by-hand steps follow as a reference.
The services intro claimed singleHostSwarm runs every service with no further
setting. The CI runner is never derived, and the builder and cache need their
store identities on the host. The overview table is also formatted the way
treefmt wants it.
A short blurb per service with its enable option and a link to its section
or page, so an operator on a single host can see what each one is and which
two (builder, CI runner) are worth a look before switching on.
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.
Squid logs a tunnel's bytes once, when it closes, so a large download was
one point in a small bucket and read as instantaneous. The panel now has a
5 minute minimum interval and bars, so that point is a visible bar. The
module-eval check pins both.
hivectl-cli.md is generated from the clap doc comment, so the example name
moves into cli.rs; the swarmctl README's create and schedule examples use
agent1/agent2 like the handbook pages.