async-matrix
An async-native Matrix Application Service SDK for Ruby. Built on the Socketry ecosystem (async, async-http, Falcon) — no threads, no callbacks, just fibers.
async-matrix implements the Matrix Application Service API: the server side of a bridge or bot. Your homeserver PUTs transactions of events at your service; async-matrix authenticates them, deduplicates them, and dispatches each event to the handlers you register. The whole stack runs on fibers, so thousands of concurrent HTTP calls back to the homeserver cost you connection-pool slots, not threads.
Quick start
# config.ru
require "async/matrix"
config = Async::Matrix::ApplicationService::Config.load("config/appservice.yml")
client = Async::Matrix::Client.new(config)
bot = Async::Matrix::ApplicationService::Bot.new(client) do
on "m.room.member" do |event|
join_room(event.room_id) if event.content.membership == "invite"
end
on "m.room.message", msgtype: "m.text", not_from: :self do |event|
send_notice event.room_id, "Echo: #{event.content.body}"
end
end
app = Async::Matrix::ApplicationService::Server.new(
hs_token: config.appservice.hs_token,
client: client
) do
dispatch bot
end
run app
falcon serve --bind http://0.0.0.0:9292
That’s a complete echo bot. The Server wraps a Grape API with the Matrix wire-protocol routes mixed in; dispatch registers a bot or plain handler; Falcon serves it. Head to Getting Started for a full walkthrough with a homeserver.
What’s here
- Core Features — the Application Service server and event flow, bots and handlers (the
dispatchDSL and the handler duck-type), the Client and its schema-validated API chain, and events and schema validation. - Advanced — configuration with JSON-Schema validation, end-to-end encryption (Olm/Megolm via a native binding), media upload/download, and the Discord bridge.
- Examples — runnable bots and bridges, each with a Docker Compose + Synapse stack.
Design principles
- Async all the way down. Every HTTP call is a fiber operation on
Async::HTTP::Internetwith fiber-safe connection pooling. No thread pools, no callback soup. - The homeserver is untrusted input. Transactions are authenticated with a constant-time token compare and deduplicated by transaction ID before any handler runs. One handler raising never takes down the rest.
- Specs are the source of truth. The API chain validates against the official Matrix Client-Server OpenAPI documents, and events validate against the upstream event JSON schemas — both bundled into the gem.