Watch
0
0
Fork
You've already forked hyperhive
0
Commit graph

5,312 commits

Author SHA1 Message Date
damocles
99bd912ae0 deps: bump hive-claude to 0.1.2 2026-10-04 23:35:49 +02:00
atlas
2505008b83 swarm-secret-client: hives no longer read swarm/services/*
The hive policy rendered by policy::render granted every hive cert read
on secret/data/swarm/services/*, which holds each swarm service's OIDC
client secret. No reader of that tree authenticates with a hive cert:
grafana, the otel collector and the store forwarder each read with
their own leaf, and the bao UI's secret is read by the store's granter.

render() now emits two stanzas: swarm/agents/* and the hive's own
swarm/hives/<hive>/*. Kind::Service had no other caller and is removed.
Docs and comments that described the grant as a decision are rewritten
to the current state.

Closes #4960
2026-10-04 23:11:11 +02:00
iris
3bfdf0dfe0 swarm-ui: each route sets its own document title ('<page> · <swarm name>') 2026-10-04 22:43:07 +02:00
atlas
27b03e622e swarm-controller: the term and state stream 404/500 text describes a per-agent stream
The handlers read the agent's status only to learn whether it has ever reported; no hive is used to build the stream. The 404 and 500 messages and their OpenAPI descriptions now say that.
2026-10-04 22:24:51 +02:00
atlas
8a7733b3f5 swarm-controller: drop the relay subscription to the refused hive-scoped agent subject 2026-10-04 22:24:51 +02:00
atlas
91fdf96a67 docs: drop harness systemd settings; swarm-nats-auth: refuse the hive's shared agent client
Docs (review on #4948): the harness's restart settings are not useful to
a reader, so the `Restart`/`RestartSec` bullet in docs/turn-loop and the
"30 seconds later, no start limit" wording in docs/swarm are removed.
What stays is the behaviour: the harness exits and comes back until the
queue accepts it.

Grant: with the harness's shared-client fallback gone, nothing presents
the hive's shared agent client (`hive-<hive>-agent`) to the queue;
swarm-logs uses that OIDC client over HTTP only. swarm-nats-auth now
refuses it outright instead of granting the configured
`$SWARM.term.{hive}.>` / `$SWARM.agent-state.{hive}.>` publish and its
`_INBOX.client.<id>.>` subscribe, so an agent holding it can no longer
publish as a sibling. The agent arm still runs before the hive arm, so
that id never falls through to its hive's grant.

Removed with it: the `--agent-publish-subject` flag and its two uses in
swarm-nats.nix, `Policy`'s agent subject list, and
swarm-queue-client's `client_inbox_prefix`. The module-eval now asserts
the flag is absent; the policy tests assert the refusal and that the
hive itself is still admitted.
2026-10-04 22:24:51 +02:00
atlas
235bc481b3 hive-agent: the swarm queue connection is required; retry, then exit
An agent's harness connects to the swarm queue with the agent's own
credential or not at all. The first connect retries after 5s, doubling
(7 attempts, about five minutes), with a warning per failed attempt;
when every attempt fails the harness logs an error and exits 1. Missing
coordinates (HIVE_AGENT_NATS_URL, or the secret store's BAO_ADDR /
HIVE_AGENT_NAME / certificate) fail the boot outright.

Previously the first connect's outcome was memoized for the life of the
process: a store 403 or queue refusal at boot left the agent on the
hive's shared client, or disconnected, until someone restarted it, and
an agent with no queue coordinates ran on without one. Both paths are
gone, with the hive-scoped subjects that only the shared client used.

The harness unit now restarts after 30s instead of 2s, so a swarm-wide
outage doesn't restart every agent every 2s, and has no start limit, so
it keeps coming back however long the outage lasts.

The hive's shared client credential is still imported into the harness
unit for swarm-logs; the two HIVE_AGENT_OIDC_*_FILE variables that
pointed the harness at it are dropped, as is the unset
HIVE_AGENT_OIDC_CA_FILE override.

With the fallback gone, the pieces #4944 added only for it go too:
swarm_input's skip-on-shared-client branch and swarm-queue-client's
connect_with_inbox_prefix. swarm-nats-auth's grant for the hive's shared
agent client is unchanged.

Closes #4909
2026-10-04 22:24:51 +02:00
damocles
147b9e0a23 scripts: prefer the forge remote over alphabetical order when picking check-attribution-trailers.sh's base ref 2026-10-04 22:12:01 +02:00
atlas
b4a2aeb5ba docs: scheduled prompts are swarm-level; the hive page is a read-only list
Drops docs/tools/scheduling.md and every description of hive-level
schedule creation, the worker, the removed MCP tools, the scheduling tool
group and the removed endpoints/events, pointing at docs/swarm/schedules.md.
2026-10-04 21:23:31 +02:00
atlas
a4a3f81d5c dashboard: SCH3DUL3S is a read-only list with a removal banner
The tab lists the rows left in the hive's store so the operator can
recreate them with `swarmctl schedule add`: no create row, edit form,
fire/pause/cancel buttons or schedules_changed subscription. The next
column shows the stored next fire time as an absolute UTC timestamp (the
value for --at) instead of a countdown. A warning banner says the page is
slated for removal and points at swarmctl. The approvals view drops the
schedule_prompt card and the approval_added subscription.
2026-10-04 21:23:30 +02:00
atlas
c3a54bbdd0 hive-c0re stops owning scheduled prompts; agents lose the schedule tools
Scheduled prompts are swarm-level now (swarmctl schedule, #4936). The hive
keeps the rows it has only so the operator can copy them over.

- hive-c0re no longer fires anything: the scheduled-prompts worker is gone,
  and with it every create/edit/cancel/pause/resume/fire path (dashboard
  endpoints, agent-socket verbs, the SchedulePrompt approval kind and its
  approve handler). The store keeps open + list; GET /api/schedules stays.
- A v6 approvals migration drops schedule_prompt rows.
- Nothing submits approvals any more, so the submit path goes too:
  Approvals::submit_kind (now a test fixture), the ApprovalAdded dashboard
  event and its emitter.
- Coordinator::push_todo, whose only caller was the worker, goes, and with
  it hive_host_sock::agent_todo_socket and hive-c0re's hive-agent-sock /
  hive-sock-client deps.
- The schedules_changed dashboard event goes; nothing mutates the rows.
- Agents lose request_schedule_prompt, cancel_schedule, fire_schedule_now,
  edit_schedule and list_schedules, the `scheduling` tool group, their
  system-prompt line and their transcript formatters. `remind` is unchanged.
2026-10-04 21:23:30 +02:00
damocles
7d80f5146d hive-c0re: fix two more comments with the same stale repo-created-after-spawn premise 2026-10-04 21:04:18 +02:00
damocles
e5a9703e00 hive-c0re: fix a doc comment still naming the deleted forge_after_first_spawn 2026-10-04 20:59:15 +02:00
atlas
eaa26d7e1e docs(forge): drop the core-token migration note 2026-10-04 20:50:50 +02:00
atlas
1de8a01936 hive-c0re: drop the spawn-time forge user-email, repo-creation and config-repo passes
sync_agent no longer runs ensure_user_email, ensure_repo_creation_disabled
or ensure_config_repo. swarm-controller does all three before any deploy:
CreateForgeUser sets the account email and max_repo_creation = 0 (and the
agent_token backfill re-runs CreateForgeUser), CreateRepo creates and
protects agent-configs/<agent>, AddRepoMember grants the agent write on it,
and InitAgentConfigRepo seeds it.

What goes with them: the email-aligned and repo-creation-disabled marker
paths and the legacy email-marker relocate, sparse_edit_user_option,
is_forbidden and its tests, and ensure_org_repo. A config repo deleted by
hand is no longer recreated on the next spawn; the operator recreates the
agent at swarm level. Comments in swarm-controller that described the
removed hive passes now state only the current behaviour.

Closes #4848
2026-10-04 20:50:50 +02:00
damocles
d2c6f1a967 hive-matrix-mcp: fix list_rooms/list_invites docs to say room_id, not id 2026-10-04 20:40:15 +02:00
damocles
8b6b735a20 hive-matrix-mcp: surface the inviter and topic in list_invites 2026-10-04 20:40:15 +02:00
atlas
d81fb2236f swarm: grant the controller STREAM.MSG.GET; list subagents concurrently
GET /api/agents/{name}/subagents reads each subagent's newest row with
get_last_raw_message_by_subject, which publishes
$JS.API.STREAM.MSG.GET.term-sub-<agent>. The controller's NATS grant had
no STREAM.MSG.GET, so every lookup was refused and waited the 10s request
timeout, one subagent after another; six subagents passed nginx's 60s.

Grant `$JS.API.STREAM.MSG.GET.*`. A wildcard matches a whole subject
token only, so a `term-sub-*` spelling would name one stream literally;
`*` is the narrowest grant that covers the per-agent streams, the same
width as the controller's STREAM.INFO.* grant.

The lookups now run concurrently (16 at a time) with a 2s timeout each.
A lookup that fails or times out lists its subagent with a null
last_row_unix, and one warn per request names how many failed and the
first error.
2026-10-04 20:03:08 +02:00
damocles
6ce01ff38d hive-matrix-mcp: vary the UTD sentinel by event id so it re-arms the wake 2026-10-04 19:53:00 +02:00
damocles
be61059f15 hive-matrix-mcp: decrypt timeline events in the wake path, same as read_room 2026-10-04 19:53:00 +02:00
atlas
01ec29da48 hive-gateway: no hive-domain vhost on a host without a hive
The hive-domain vhost renders only where a hive runs. On a host without
one the only certificate is the swarm-services leaf, which does not name
the hive domain, so a homeserver host without a hive serves matrix on the
homeserver's own name only; apex matrix discovery is #4878.

Comments and test names describe the code's current behaviour.

Refs #4588
2026-10-04 19:45:14 +02:00
atlas
3e1ac4e678 hive-gateway: keep matrix discovery on the hive domain of a homeserver host without a hive
The hive-domain vhost renders where a hive or the homeserver runs. Its
matrix .well-known JSON and /matrix/ redirect are served wherever the
homeserver runs; the dashboard, swagger UI, agent routes and the
agents.conf include only where a hive runs, since they proxy to hive-c0re.

The gateway doc's vhost map says which rows exist without a hive, and the
trust-bundle text describes ca.pem by what it is rather than as retired.

Refs #4588
2026-10-04 19:45:14 +02:00
atlas
60268b70b0 hive-tls: a store-only host without a hive starts its gateway with the store sealed
A gateway host without a hive whose only swarm name is the store's UI no
longer waits for swarm-services-cert: its nginx carries the stream
passthrough to the store and must come up while the store is sealed. Until
the services leaf lands, hive-gateway-self-signed-cert installs a throwaway
self-signed pair on the default and swarm-services paths there; on a host
without a hive it never references the hive leaf.

A host without a hive also no longer mints the hive-leaf identity or
defaults the options pointing at it, and does not render the hive-domain
vhost, whose upstream is hive-c0re.

Refs #4588
2026-10-04 19:45:14 +02:00
atlas
75a7dccee6 hive-tls: no hive leaf or hive identity on a gateway host without a hive
A self-signed gateway on a host with deploy.hive-controller.enable off
(a dedicated swarm-services host) needed the hive leaf for its catch-all,
and that leaf now comes only from hive-tls-resign with a per-hive store
identity. hive-tls-resign and its timer are now defined only where a hive
runs; elsewhere hive-gateway-self-signed-cert installs the swarm-services
leaf as the default cert, and the gateway waits for swarm-services-cert.
Also corrects the hive-gateway comments and option text that still said
the leaf is hive-CA-signed.

Refs #4588
2026-10-04 19:45:14 +02:00
atlas
fc33a62bf8 hive-tls: keep ca-key.pem on disk, and re-issue a leaf that does not match its key
hive-tls-ca no longer deletes a ca-key.pem an earlier generation left:
nothing reads it, and leaving it means a rollback finds the old key instead
of minting a new anchor. Deleting it moves to PR 3, beside dropping ca.pem
from the trust bundle.

hive-tls-resign now also re-issues when the leaf's public key differs from
the key file's. The leaf and key are moved into place by two renames, and an
interrupted pair left a certificate beside the wrong key that the validity
check accepted.

Refs #4588
2026-10-04 19:45:14 +02:00
atlas
5d26908c6f hive-tls: correct two comments that still describe a runtime-generated hive CA
swarm-controller.nix said the gateway leaf is signed by a hive CA generated
at runtime; lib/hive-ca-trust.nix said hive-tls-ca generates the CA and that
containers bind ca.pem, while the code binds trust-bundle.pem.

Refs #4588
2026-10-04 19:45:14 +02:00
atlas
5526daab97 hive-tls: issue the gateway leaf from bao with a per-hive identity
Every hive gets its own store identity (CN
<deploy.bao.hiveLeafCommonNamePrefix>-<hive>) and its own role on the
existing pki mount (<deploy.bao.hiveLeafPkiRolePrefix>-<hive>), whose
allowed_domains is the hive's domain and *.<domain>. The policy grants
update on that one issue path. swarm-bao-hive-leaf-policy writes role,
policy and cert-auth role for every hive in swarm.hives; the store's host
mints its own hive's identity in glue-bao-tls.nix and a new glue file
points deploy.hive-controller.tls.baoHiveIdentity{Cert,Key}File at it.
Hives on other hosts place it by hand. swarm.nix reserves the composed CN.

hive-tls-ca no longer generates a hive CA or signs a leaf: caGenScript,
signLeafScript/signHiveLeaf and the adoption block are gone, ca-key.pem
is deleted where it exists, and the unit only assembles trust-bundle.pem.
The retired ca.pem/ca-previous.pem stay in the bundle so leaves they
signed keep verifying.

hive-tls-resign becomes the bao issuance: at boot, on deploy and from a
daily timer it re-issues when the leaf is missing, past half the role's
lifetime, missing a name, or not chained to the store's pki root. Nothing
orders the gateway after it, so a valid leaf on disk never waits on the
store; a failed renewal leaves the leaf in place. A missing identity
fails the unit naming both options, as does the root fetch on a hive
fronting no swarm name, which now presents this identity instead of the
reader cert.

caValidityDays and leafValidityDays are removed (both spellings), since
nothing reads them.

Refs #4588
2026-10-04 19:45:14 +02:00
atlas
52037133e2 swarm-nats-auth: limit agent subscribe to its own inbox and input
An agent's queue credential could subscribe to every subject in the swarm
account, so any agent could read every other agent's terminal, turn state,
operator input and request replies. Agents are the least trusted clients
on the queue (mara's ruling on #4901), so their grants now carry a
subscribe allow-list:

- an agent's own credential (the harness and its subagent daemon):
  `_INBOX.agent.<agent>.>` and `$SWARM.input.<agent>`
- the hive's shared agent client: `_INBOX.client.<client-id>.>`

Hive and swarm-controller grants are unchanged (no `sub` claim, so still
every subject).

The clients connect with the matching inbox prefix, so the replies they
rely on still arrive: the icon write's JetStream ack and the schedule
DIRECT.GET. `connect_with_token` takes the agent name and sets the prefix
itself; the hive-shared fallback uses the new
`connect_with_inbox_prefix`.

The harness no longer subscribes to its input subject when it fell back
to the hive's shared client: that identity names no agent, so it cannot
be granted one agent's input without all of them. It logs that and
skips, the same as the schedule reader on that path.

Refs #4901
2026-10-04 19:22:41 +02:00
damocles
bc11b85e07 hive-agent: only wake the boot-announce todo when it actually changed 2026-10-04 19:16:59 +02:00
damocles
f33a1ed660 hive-agent: key the boot-announce todo so it dedups across boots 2026-10-04 19:16:59 +02:00
damocles
cd61ea4a37 hive-agent: self-announce boot instead of host-side kick_agent 2026-10-04 19:16:59 +02:00
atlas
55a67e38fa matrix apiUrl: default to https on the gateway vhost
hive-c0re logs in with the hive's matrix sender token and creates the
Space and rooms over swarm.matrix.apiUrl. On a hive that does not run
the homeserver that crosses the network, so the default is now
https://<gatewayHost>. hive-c0re already verifies against the hive trust
bundle (SSL_CERT_FILE: system CAs, swarm root and the store's services
root), which covers the gateway's leaf for that name.

Also drops the remaining loopback-default wording in hive-c0re's matrix
module and the openFirewall description, and pins the https default on a
hive host without the homeserver in module-eval-matrix-core.
2026-10-04 18:31:24 +02:00
atlas
bed4358e19 swarm options: no swarm.* value depends on a deploy option or this host's hive
- swarm.serviceDomains lists every swarm service name on every host. The
  store's issuing role is built from it, so the store now admits a leaf
  for grafana, metrics, otel, logs, the bao UI and the apex whichever host
  runs the store. Each gateway's own leaf stays narrowed by
  localServiceDomains.
- swarm.matrix.apiUrl defaults to http://<swarm.matrix.gatewayHost>
  (null when gatewayHost is null) instead of loopback on the matrix host.
- The authelia vhost proxies /bridge/ to swarm-authelia-bridge with the
  prefix stripped, and deploy.swarm-controller.authBridgeUrl defaults to
  ${swarm.authelia.url}/bridge on every host. swarm.authelia.bridgeUrl is
  removed.
- swarm-authelia-bridge admits only swarm-controller's OIDC client on
  every request (403 for any other active token), configured by
  SWARM_AUTHELIA_BRIDGE_CONTROLLER_CLIENT_ID (renamed from
  ..._OPERATOR_READER_CLIENT_ID, which gated ListOperators alone).
- swarm.peerHives is removed; swarm-wireguard.nix filters this host's own
  hive out of swarm.hives itself.

Closes #4933
2026-10-04 18:13:47 +02:00
iris
207b089498 swarm-ui: format the schedules page with treefmt 2026-10-04 17:49:42 +02:00
iris
8a9e199bad docs: schedules page section passes the prose lint 2026-10-04 17:49:42 +02:00
iris
0af7f53e88 swarm-ui: schedules page says what a past start does, no longer claims a one-shot fired
A start in the past fires the latest missed time once, right away, so the
form says that instead of 'already passed'. A one-shot past its time reads
'past' / 'time passed' (the controller's clock, not a record of firing) and
keeps its pause button. The edit form compares against what it opened with,
so a schedule changing under it is not reverted on save.
2026-10-04 17:49:42 +02:00
iris
63ee6d12be swarm-ui: a schedules page, one card per scheduled prompt
/schedules lists the controller's scheduled prompts as cards: name as the
title, the agents it fires for, the message, its cadence and next fire.
Edit turns a card into its own form; pause, resume and remove act in place,
and + schedule opens an empty form. The form sends only what changed, so a
rename never moves the fire times, and warns when the start or the repeat
does. Filters reuse the shared card filter bar.

Adds a TextAreaField to the ui kit, and an upcoming mode on RelativeTime so
a next-fire time reads "in 5m". Needs the controller's /api/schedules
routes.
2026-10-04 17:49:42 +02:00
iris
7f597f5c43 swarm-ui: size every preview badge like the expand trigger, make room for two rows
All badges in the floating row take the interactive 2.75em height so the
state badges match live and expand. The embedded preview wraps them onto a
second row in the narrow details panel, so its top padding now fits two
rows (and the preview cap grows to match); the full tab keeps one row.
2026-10-04 17:29:48 +02:00
iris
51da879db6 swarm-ui: expand trigger on the right, connection badge as tall as it
The floating row over the terminal now spans its top edge: the state
badges (connection first, then the turn-state ones, which move over from
the top-right corner) on the left, the expand trigger on the right.
The connection badge takes the trigger's height. The row passes pointer
events through its empty middle.
2026-10-04 17:29:48 +02:00
iris
9064d8fbd2 swarm-ui: connection badge and expand trigger float inside the terminal preview
They sat in a toolbar row above the terminal box. They now float in
its top-left corner, next to the turn-state badges in the top-right,
and the toolbar row is gone. The full-tab mount keeps the connection
badge and, being the destination already, has no expand trigger.
2026-10-04 17:29:48 +02:00
atlas
a0b1846006 swarm: named scheduled prompts for one or more agents, fired in each agent
swarm-controller keeps every scheduled prompt (id, name, agents, body,
anchor, interval, paused) as one document under one key of a new
`schedule-definitions` KV bucket, so each change is a single
compare-and-set and a prompt exists for all of its agents or none. It
writes each agent's key of a new `agent-schedules` bucket as the prompts
naming that agent, without names or other agents, after every change and
on a one-minute reconcile pass. It is the only writer of both, behind
GET/POST /api/schedules and PATCH/DELETE /api/schedules/{id}.
`swarmctl schedule add|list|edit|pause|resume|rm` drives those routes over
the controller socket.

An agent's own queue credential is granted one more subject, the direct
get of its own key in `agent-schedules`. A KV watch is not granted: its
consumer create subject carries no key, so it would cover every agent's.

hive-agent's new schedule ticker reads that key every 10 seconds and fires
due slots as the same `schedule:<id>` todo hive-c0re's worker pushes. Fire
times are anchor + k*interval; the last fired slot per schedule id is kept
in the state db, so a body edit or list refresh never moves or refires a
slot, downtime fires the latest missed slot once, a restart refires
nothing, a one-shot fires once, and paused slots are skipped.

Refs #4914
2026-10-04 17:24:57 +02:00
iris
84c89de71c swarm-ui: show how recent each subagent is in the details panel
The subagent list endpoint now returns {name, last_row_unix} per
subagent, the publish time of its newest terminal row, read from the
queue controller-side so agents publish nothing new. The panel sorts
newest first, shows a ticking age beside each name, and dims one quiet
for 15 minutes.

Closes #4928
2026-10-04 17:24:25 +02:00
atlas
4356dc82a4 swarm-bao: let the controller list linked-account dirs
OpenBao checks a LIST against the directory with a trailing slash, so
the controller's LIST on secret/metadata/swarm/agents/<a>/matrix is
checked as .../matrix/. Its empty last segment matches the `+` in the
delete stanza .../agents/+/matrix/+ (added by bbf93120), which then is
the only non-exact rule matching, and its ["delete"] denies the LIST
before acl.go's trimmed-path fallback reaches .../+/matrix ["list"].
The forge directory fails the same way against .../+/forge/+.

Writing the list stanzas as .../+/matrix/ and .../+/forge/ makes them
match the slashed request too, and with one `+` segment against two
they outrank the delete stanzas. Deletes on .../matrix/<id> still
resolve to .../+/matrix/+, which the slashed list path does not match.

Reproduced by iris against a local bao server -dev with a non-root
token: list stanza alone allowed, plus the delete stanza denied, list
stanza with trailing slash plus the delete stanza allowed.

Closes #4919
2026-10-04 17:23:36 +02:00
iris
08e67520ed docs: disable write-good.TooWordy -- 100% dictionary mismatch on this corpus
Checked all 114 hits on the full docs/ tree by hand, not sampled: every
single one flags a precise, normal technical/formal word from
write-good's default corporate-bloat wordlist (validate, monitor,
therefore, however, multiple, additional, previously, subsequent,
equivalent, sufficient, exclusively, finalize, terminate, enumerate,
minimize, consolidate, eliminate, acquire, evaluate, satisfy,
implement, "it IS"/"it is"/"it was", "all of", "is responsible for",
"in addition"), not an actual verbose phrase. None of the genuinely
wordy multi-word bloat this rule exists to catch (due to the fact
that, in order to, at the present time, for the purpose of) appears
even once. Rewriting 114 instances of precise vocabulary into vaguer
prose to satisfy a dictionary mismatch would make the docs worse, not
better -- same shape as the Microsoft.Percentages/Microsoft.Dashes/
Microsoft.HeadingColons entries already in this file's "ruled on, not
wave 2" section.

Full evidence (the actual word/phrase breakdown, and why the 13
closest hits -- "it is"/"it was"/"all of"/"is responsible for"/"in
addition" -- were manually read in context and still don't count) was
already posted on hyperhive#4042; this just applies the conclusion.

Verified: nix shell nixpkgs#vale --command sh -c 'vale sync && vale
docs' before/after -- 908 -> 794 warnings (-114, exactly the disabled
rule's own hit count), 49 errors unchanged (all Microsoft.Avoid/
Contractions, unrelated to this rule), zero remaining TooWordy hits.
2026-10-04 17:09:58 +02:00
atlas
cf88fbba9d operator admin sync: cap the grant at one send, split out response verdicts
The admin-room command stays in #admins' history, so a grant tuwunel
ignores must not be re-sent every five minutes. The controller now
sends `make-user-admin` at most once per operator per process; an
operator still missing from the room on a later pass is logged as
"make-user-admin for an operator failed to take" and left alone until
the controller restarts. The cap lives in the pure `plan()`.

swarm-matrix-client's `user_exists` and `joined_members` read their
responses through pure `profile_verdict` / `joined_verdict`, the shape
`whoami` / `whoami_verdict` already has, with every branch tested: only
M_NOT_FOUND is "no account", and a 403 or a list without `joined` is an
error rather than an answer.

The bridge's handling after authentication moves into `respond()`,
which takes the config and write lock instead of the whole AppState, so
a test can drive ListOperators through the real request path and see
the 403 without an HTTP client or an authelia.

docs/integrations/matrix.md no longer says @swarm is the only homeserver
admin.
2026-10-04 16:45:08 +02:00
atlas
9e7fdb55ae swarm-controller: make authelia's operators matrix homeserver admins
swarm-authelia-bridge gains ListOperators, the usernames in authelia's
operator group (`operatorGroup = "admins"`, passed in from
swarm-authelia.nix). Unlike the two agent verbs, which admit any active
token, it answers only the client named by
SWARM_AUTHELIA_BRIDGE_OPERATOR_READER_CLIENT_ID (swarm-controller's
queueClientId) and returns 403 to every other active token: authelia
issues machine tokens to every hive and its agents as well. The bridge's
introspection now models `client_id` to make that check, the same way
swarm-nats-auth's does.

swarm-controller runs a grant-only pass at start and every five minutes:
read the group, map each username to the account an SSO login lands on
(tuwunel lowercases `preferred_username`), skip anyone already joined to
`#admins:<server>` (tuwunel's definition of admin) or without a matrix
account, and send `!admin users make-user-admin <user>` there as @swarm
with the swarm appservice token. Nothing is ever revoked: tuwunel has no
command for it (#4799).

The admin-room calls (alias, joined members, profile, send) go into
swarm-matrix-client next to whoami, keeping its no-body-in-errors rule.

Closes #4585
2026-10-04 16:45:08 +02:00
iris
2c1a9fa488 swarm-ui: one link-account menu, and no subagents section without subagents
The three link-account badges were wider than the agent detail panel and
spilled out of it; they are now a single badge opening a dropdown of the
three kinds. The subagents row, heading included, is not rendered for an
agent that has none.
2026-10-04 16:35:06 +02:00
iris
66df552f68 swarm-ui: terminal tab fills the viewport below the header
The agent terminal tab now takes the whole window except the header bar,
full width and height, instead of sitting in the padded content column.
The connection badge floats inside the terminal's top-left corner and the
toolbar row above it is gone on this route.
2026-10-04 16:15:06 +02:00
iris
78e9f2ca67 use a neutral forge name in link-form placeholders, schema examples and tests
Codeberg does not accept AI-assisted contributions, so it should not be
the example we put in front of operators. The placeholders now read
myforge / forge.example.org; the tests use the same neutral names.
2026-10-04 15:51:20 +02:00
damocles
aaf3f147fb disk_watch: drop bare tracker tag from test doc-comment 2026-10-04 15:18:32 +02:00