From 97fb76ce99802fd12454a17bc9f184246fffc166 Mon Sep 17 00:00:00 2001 From: atlas Date: Thu, 1 Oct 2026 17:41:20 +0200 Subject: [PATCH] matrix: the agent's daemon pulls its linked accounts from bao itself hive-matrix-daemon now learns which external matrix accounts it has from the swarm secret store, under the agent's own certificate, and the hive push chain for matrix is gone. The daemon lists swarm/agents//matrix/ (the `list` its policy grants on its own metadata subtree), reads each account's homeserver from its credential, and brings the accounts up with their tokens from the store. Every two minutes it lists again and exits with 75 when the set of linked accounts changed; the unit restarts on 75 without counting a failure. A listed name whose credential reads as absent is skipped and logged once. At start it removes the matrix-token- / matrix-account-.json pairs a hive delivered (a sidecar marks a pair as delivered; a declared tokenFile keeps its token). Removed: CredentialNotice and the $SWARM.credential.* subject and NATS grant, the controller's publish and its queue precondition on the PUT route, hive-c0re's credential subscription arm and workers/credential.rs, priv_client::write_agent_matrix_token, hive-priv's WriteAgentMatrixToken and its helpers, and the daemon's state-dir account discovery. Kept: WriteAgentGithubToken and the external-forge path (WriteAgentExtraForgeAccount, extra_forges.rs) are untouched, and a declared matrixAccounts tokenFile is still read when the store has no token for that account. Refs #4348 --- docs/agent-lifecycle/persistence.md | 8 +- docs/tools/matrix.md | 9 +- docs/trust-boundary/security.md | 3 +- .../src/pages/LinkMatrixAccountForm.tsx | 10 +- hive-c0re/src/lifecycle/agent_identity.rs | 4 +- hive-c0re/src/matrix.rs | 2 +- hive-c0re/src/priv_client.rs | 26 -- hive-c0re/src/swarm_status.rs | 56 +-- hive-c0re/src/workers/credential.rs | 116 ------- hive-c0re/src/workers/mod.rs | 1 - hive-matrix-mcp/src/accounts.rs | 324 ++++++++++-------- hive-matrix-mcp/src/credential.rs | 129 +++++-- hive-matrix-mcp/src/main.rs | 170 +++++++-- hive-priv-sock/src/lib.rs | 47 +-- hive-priv/src/main.rs | 134 +------- nix/agent-modules/matrix.nix | 22 +- nix/host-modules/hive-c0re/environment.nix | 2 +- swarm-controller/src/matrix_account.rs | 210 +++--------- swarm-nats-auth/src/policy.rs | 41 --- swarm-queue-client/src/lib.rs | 36 -- swarm-secret-client/src/client.rs | 26 ++ swarm-secret-client/src/matrix.rs | 20 +- 22 files changed, 568 insertions(+), 828 deletions(-) delete mode 100644 hive-c0re/src/workers/credential.rs diff --git a/docs/agent-lifecycle/persistence.md b/docs/agent-lifecycle/persistence.md index 08eb802f..c28f7b15 100644 --- a/docs/agent-lifecycle/persistence.md +++ b/docs/agent-lifecycle/persistence.md @@ -578,18 +578,20 @@ agent has one; a `null` URL with no operator-declared account is the "this agent has no matrix" state. **First-boot ordering**: a token can arrive after the container comes -up — a file the hive delivers, or a token the swarm mints into the store. +up — a declared token file, or a token the swarm mints into the store. Without the path-trigger sibling (`systemd.paths.hive-matrix-daemon`, `PathExistsGlob = /matrix-token*` — the trailing `*` also catches -a secondary multi-account token like `matrix-token-ccc`), the daemon +a declared secondary token file like `matrix-token-ccc`), the daemon would exit 0 quietly the first time it ran and the MCP would have no daemon until the next restart. The `.path` unit makes the appearance of the token re-fire the service so the daemon comes alive in the same boot cycle as provisioning. A token in the store changes no file, so a store-backed agent also gets a timer that restarts the daemon five minutes after it last -exited. The same token watcher also drives avatar setting: on a +exited. A running daemon re-lists its linked accounts in the store +every two minutes and, when the set changed, exits with status +75, which the unit's `RestartForceExitStatus` restarts. The same token watcher also drives avatar setting: on a restart the daemon re-runs each account's bring-up, which sets the avatar (see below). diff --git a/docs/tools/matrix.md b/docs/tools/matrix.md index 14f5236d..5cd8eeeb 100644 --- a/docs/tools/matrix.md +++ b/docs/tools/matrix.md @@ -104,8 +104,15 @@ evaluation with a message saying so. Declaring an external account with its own `homeserver` is enough on its own; a hive homeserver isn't required. +An account linked from the swarm UI needs no entry in this map. +`swarm-controller` stores it at `swarm/agents//matrix/`. +The daemon lists that directory under the agent's own certificate at +start and every two minutes, and restarts itself when the set of linked +accounts changes. A declared entry of the same name wins. + Every matrix tool above takes an optional `account` parameter (a name -from this map) to act as that identity instead of the primary one. +from this map, or a linked account's) to act as that identity instead +of the primary one. Declaring an extra account also changes what the agent *receives*: wake bodies and invite todos gain an `[acct:]` prefix — see diff --git a/docs/trust-boundary/security.md b/docs/trust-boundary/security.md index cf843b05..b14bdc62 100644 --- a/docs/trust-boundary/security.md +++ b/docs/trust-boundary/security.md @@ -295,11 +295,10 @@ known operations; there is no arbitrary command pass-through: | `RemoveServiceDropin` | remove `container@.service.d/` drop-in on destroy | | `DaemonReload` | `systemctl daemon-reload` | | `RunForgeAdmin` | `nixos-container run hive-forge -- runuser -u forgejo -- forgejo admin ` | -| `WriteAgentMatrixToken` | write `0600` credential file into agent state dir | | `ControlInfraContainer` | `systemctl container@.service` — the `InfraContainer` enum is the allowlist, and serde rejects unknown names at the wire boundary (`hive-c0re` has no variant, so no request can name it) | | `SyncAgentTmpfiles` | legacy: unlink `/etc/tmpfiles.d/hyperhive-agents.conf` and return `Ok`; kept one release for an older hive-c0re | | `SetAgentPaused` | create / remove the `//harness/paused` marker that parks an agent's turn loop | -| `WriteAgentGithubToken` | write `0600` `github-token` into agent state dir (same semantics as the forge/matrix token writes) | +| `WriteAgentGithubToken` | write `0600` `github-token` into agent state dir (same semantics as the extra-forge account writes) | | `WriteAgentExtraForgeAccount` / `DeleteAgentExtraForgeAccount` | write / remove `forge-