feat: hyperhive.matrixAccounts nix option (matrix multi-account layer 2)

This commit is contained in:
damocles 2026-06-15 20:48:11 +02:00 committed by mara
commit dcc059b4b8

View file

@ -299,6 +299,75 @@ in
'';
};
options.hyperhive.matrixAccounts = lib.mkOption {
type = lib.types.listOf (
lib.types.submodule {
options = {
name = lib.mkOption {
type = lib.types.str;
example = "ccc";
description = ''
Logical account name the agent addresses this account by
(the `account` argument on the matrix MCP tools). Must be
unique within the agent. The FIRST account in the list is
the agent's primary account --- the one selected when a
tool call omits `account`.
'';
};
tokenFile = lib.mkOption {
type = lib.types.str;
example = "/agents/dmatrix/state/matrix-token-ccc";
description = ''
Path to this account's bearer-token file. The daemon reads
the token from here to restore the matrix session; how the
file gets populated is the provisioner's concern (hive-c0re
for in-hive accounts, an operator-supplied secret for an
external account). The daemon skips an account whose token
file is absent (the primary account being absent makes the
daemon exit cleanly until it appears).
'';
};
sessionDir = lib.mkOption {
type = lib.types.str;
example = "/agents/dmatrix/state/matrix-sdk-state-ccc";
description = ''
Per-account matrix-sdk sqlite store directory (crypto keys
+ event cache). Must differ between accounts so their
sessions do not collide.
'';
};
homeserver = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "https://matrix.example.org";
description = ''
Homeserver URL for this account. When null (the default),
the account falls back to `hyperhive.matrix.url`. Set it for
an account on a different homeserver than the agent's
default (e.g. an external public-matrix account).
'';
};
};
}
);
default = [ ];
description = ''
Declare multiple matrix accounts served by a single
`hive-matrix-daemon` (one matrix-sdk Client + sync loop each),
replacing the wasteful "one MCP server + daemon per account"
pattern. Each entry becomes a routable account the matrix MCP
tools can target via their `account` argument; omitting `account`
on a tool call selects the first (primary) entry.
Leave empty (the default) for the common single-account case: the
daemon then synthesizes one account from `hyperhive.matrix.url` +
`<state>/matrix-token` + `<state>/matrix-sdk-state`, so existing
agents need no change. When non-empty, this list is serialized to
the daemon's `HIVE_MATRIX_ACCOUNTS` environment variable and the
legacy single-account fallback is bypassed.
'';
};
options.hyperhive.frontend.dist = lib.mkOption {
type = lib.types.package;
default = pkgs.hyperhive-frontend;
@ -1239,6 +1308,26 @@ in
HIVE_MATRIX_URL = config.hyperhive.matrix.url;
HIVE_MATRIX_SOCKET = "/run/hive-matrix/socket";
RUST_LOG = "info";
}
# Multi-account: serialize the declared accounts to the JSON the
# daemon parses (`accounts::configured`). Only set when accounts
# are declared, so the single-account agents (the common case)
# keep hitting the daemon's legacy fallback (which is bypassed the
# moment HIVE_MATRIX_ACCOUNTS is present). Keys match the daemon's
# `AccountCfg` serde shape: name / token_file / state_dir /
# optional homeserver.
// lib.optionalAttrs (config.hyperhive.matrixAccounts != [ ]) {
HIVE_MATRIX_ACCOUNTS = builtins.toJSON (
map (
a:
{
inherit (a) name;
token_file = a.tokenFile;
state_dir = a.sessionDir;
}
// lib.optionalAttrs (a.homeserver != null) { inherit (a) homeserver; }
) config.hyperhive.matrixAccounts
);
};
serviceConfig = {
ExecStart = "${pkgs.hyperhive}/bin/hive-matrix-daemon";
@ -1318,9 +1407,12 @@ in
# would have no backend until next restart. See
# `docs/persistence.md` (same section as above).
systemd.paths.hive-matrix-daemon = lib.mkIf config.hyperhive.matrix.enable {
description = "trigger hive-matrix-daemon when matrix-token appears";
description = "trigger hive-matrix-daemon when a matrix token appears";
wantedBy = [ "multi-user.target" ];
pathConfig.PathExistsGlob = "/agents/*/state/matrix-token";
# `matrix-token*` (not just `matrix-token`) so a secondary
# multi-account token (e.g. `matrix-token-ccc`) landing also
# re-fires the daemon to pick up the freshly-provisioned account.
pathConfig.PathExistsGlob = "/agents/*/state/matrix-token*";
};
# Path-trigger sibling: re-fires matrix-avatar-sync the moment