Sentinel’s channel architecture was designed to be transport-agnostic from the start. Each channel — Telegram, email, webhook — implements the same interface: receive messages, send responses, handle attachments. The orchestrator doesn’t care how a message arrived. This made adding a new channel straightforward in principle. The question was which one.
The requirements were specific. It had to be self-hosted — no reliance on a third-party service that could change terms, rate-limit, or shut down. It had to support rich messaging — text, attachments, formatting. It had to have a mature client ecosystem so users could connect from phones, desktops, and browsers. And it had to be lightweight enough to run on minimal infrastructure.
Matrix fits all of these. It’s an open, federated messaging protocol with a strong ecosystem of clients — Element on desktop and mobile, plus several alternatives. Federation can be disabled for a fully isolated deployment, which is what Sentinel needs — there’s no reason to federate with the wider Matrix network when the homeserver exists solely as a Sentinel interface.
The homeserver is Tuwunel, a Rust-based Matrix server (formerly known as Conduwuit). It’s a single binary, lightweight on resources, and designed for small deployments. Compared to the reference implementation Synapse (Python, heavy on memory and dependencies), Tuwunel runs comfortably on constrained hardware. It handles the Matrix server-side protocol — room management, message storage, user authentication, client-server API.
Sentinel connects as a Matrix client using the matrix-nio Python library, which provides an async Matrix client implementation. This fits cleanly into the existing channel pattern. The Matrix channel adapter listens for messages in designated rooms, extracts text and attachments, wraps them in the standard IncomingMessage format, and passes them to the orchestrator. Responses flow back the same way — the adapter formats the orchestrator’s output and sends it as Matrix messages.
The result is a messaging channel that’s entirely self-hosted and under full control. No API quotas, no terms of service changes, no dependency on external infrastructure. Users connect with any standard Matrix client. Attachments flow through the existing attachment pipeline. The planner doesn’t know or care that the message came from Matrix rather than any other channel.
It’s another transport, slotted into an architecture that was designed for exactly this kind of addition.