matrix: hive-matrix-mcp crate (daemon+stdio bridge) + harness wiring (#548 phase 3)

This commit is contained in:
damocles 2026-05-29 20:19:39 +02:00 committed by Mara
commit e6c53045ad
16 changed files with 3310 additions and 35 deletions

View file

@ -149,6 +149,52 @@
'';
};
options.hyperhive.matrix.enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Enable per-agent matrix integration via `hive-matrix-mcp`
(#548 phase 3). When true (the default), the harness:
- runs `hive-matrix-daemon` as a systemd unit that holds a
matrix-sdk Client + sync against the homeserver at
`HIVE_MATRIX_URL` (default `http://localhost:8008` the
in-host tuwunel from `nix/modules/hive-matrix.nix`). The
daemon auto-skips when `<state>/matrix-token` is missing,
and a `systemd.paths` watcher restarts it the moment
hive-c0re provisions the token (mirrors `matrix-avatar-sync`
shape from #571).
- exposes the matrix tool surface (send_message, send_dm,
send_reaction, send_reply, mark_read, list_rooms,
list_room_members, read_room) to claude via an auto-injected
`extraMcpServers.matrix` entry. Claude spawns the stdio
`hive-matrix-mcp` bridge per turn, which forwards each tool
call to the daemon over `/run/hive-matrix.sock`.
- wakes the agent on incoming room events via a short teaser
Wake signal (`[matrix] <sender> in <room>: <first 100c>`)
to the hyperhive control socket; the full event stays
unread server-side until `read_room` consumes it.
Set to `false` for agents that should NOT have matrix tools at
all (e.g. agents on a host without `hyperhive.matrix.enable` on
the meta side). When token file is absent the daemon and MCP
both no-op cleanly anyway, so `false` is rarely necessary.
'';
};
options.hyperhive.matrix.url = lib.mkOption {
type = lib.types.str;
default = "http://localhost:8008";
example = "https://matrix.darkest.space";
description = ''
Matrix homeserver URL the agent's `hive-matrix-daemon` connects
to. Default points at the in-host tuwunel (shared netns).
Override per-agent when an agent should talk to an external
homeserver instead (e.g. a federation-only setup or a remote
hive's tuwunel reached via a vpn).
'';
};
options.hyperhive.frontend.dist = lib.mkOption {
type = lib.types.package;
default = pkgs.hyperhive-frontend;
@ -483,6 +529,19 @@
}
];
# Auto-inject the matrix MCP entry when matrix is enabled (#548
# phase 3). Operator can override or disable by setting their own
# `extraMcpServers.matrix` (nix submodule merge takes the operator's
# value) or by flipping `hyperhive.matrix.enable = false`.
hyperhive.extraMcpServers = lib.mkIf config.hyperhive.matrix.enable {
matrix = lib.mkDefault {
command = "${pkgs.hyperhive}/bin/hive-matrix-mcp";
args = [ ];
env = { };
allowedTools = [ "*" ];
};
};
environment.etc."hyperhive/extra-mcp.json".text = builtins.toJSON config.hyperhive.extraMcpServers;
# Operator-set per-agent icon (hyperhive.icon). When configured, the
@ -745,6 +804,48 @@
'';
};
# Long-running matrix-sdk Client + sync per agent (#548 phase 3).
# Holds the unix socket the stdio `hive-matrix-mcp` bridge talks
# to, and emits hyperhive wake signals on incoming room events
# via `/run/hive/mcp.sock`. Conditional on `hyperhive.matrix.enable`
# AND token-file presence (the daemon binary itself exits 0 on
# missing token, but the path watcher below restarts it the
# moment the token lands — same first-boot-ordering pattern as
# matrix-avatar-sync.path / #571).
systemd.services.hive-matrix-daemon = lib.mkIf config.hyperhive.matrix.enable {
description = "long-running matrix-sdk Client + MCP daemon socket";
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
environment = {
HIVE_MATRIX_URL = config.hyperhive.matrix.url;
RUST_LOG = "info";
};
serviceConfig = {
ExecStart = "${pkgs.hyperhive}/bin/hive-matrix-daemon";
Restart = "on-failure";
RestartSec = 5;
# /run/hive-matrix.sock + the matrix-sdk-state sqlite dir
# don't need a StateDirectory= — the socket is on tmpfs (gone
# on restart, which is correct) and the sqlite dir lives in
# the bind-mounted agent state, mode-managed by the harness.
};
};
# Path-trigger sibling so hive-matrix-daemon fires the moment
# `<state>/matrix-token` appears (#548 phase 3, mirrors the
# matrix-avatar-sync.path pattern from #571). On clean boot
# hive-c0re provisions the token AFTER agent containers come up;
# without the trigger the daemon would exit 0 quietly and the
# MCP would have no backend until next restart. With the watcher
# the daemon comes alive in the same boot cycle as provisioning.
systemd.paths.hive-matrix-daemon = lib.mkIf config.hyperhive.matrix.enable {
description = "trigger hive-matrix-daemon when matrix-token appears";
wantedBy = [ "multi-user.target" ];
pathConfig.PathExists = "/state/matrix-token";
pathConfig.PathExistsGlob = "/agents/*/state/matrix-token";
};
# Path-trigger sibling so matrix-avatar-sync fires the moment
# `<state>/matrix-token` appears (#571 closes argus's first-boot
# ordering nag on #567). On a clean boot hive-c0re's matrix