All notable changes to raxol_gateway are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[0.2.0] - 2026-11-13
First release. One supervised daemon fronting many chat platforms behind a single adapter contract.
Added
Raxol.Gateway.Adapter: the behaviour every platform implements (connect/1,disconnect/1,platform/0,normalize_event/2,send_message/3).Adapter.InMemoryis the reference adapter tests drive.Raxol.Gateway.Route: the routing tuple and the unified session keyagent:main:{platform}:{chat_type}:{chat_id}, so one chat maps to one session regardless of which adapter delivered the event.Raxol.Gateway.Session/Raxol.Gateway.SessionRouter: one process per chat with an idle timeout, started and routed byRoute.key/1, under per-chat cooldown and a max-session limit.Raxol.Gateway.Handler: the per-chat behaviour a session runs (init/2,handle_event/2, optionalterminate/2on clean stops).Raxol.Gateway.SessionRouter, and soRaxol.Gateway.Supervisor, does not start when the:handlermodule cannot be loaded: the start fails with{:handler_not_available, module}.Raxol.Gateway.Handler.Lifecycle: a full TEA app per chat underenvironment: :gateway. That environment starts no driver and no plugin manager and leaves processes unnamed, which is what lets one app module serve many chats in one VM.Raxol.Gateway.Pairing: DM pairing codes, allowlists, and a fixed authorization order. Inbound events are gated on it, so an unpaired chat cannot reach a handler.Raxol.Gateway.Delivery: the four outbound destinations, direct, home, cross-platform, and an explicit target string.Raxol.Gateway.Pipeline.Transcribe: a feed-loop stage that turns a%{media: %{kind: :voice}}event into%{text: transcript}before routing. Fetch, convert, and recognize are injectable; the defaults are ffmpeg plus the optionalraxol_speechrecognizer. A failure drops that one event and logs it rather than stalling the loop.Raxol.Gateway.Adapter.Discord: gateway-socket adapter with its own protocol codec and a Mint WebSocket transport.Raxol.Gateway.Adapter.Email: outbound overgen_smtpplus an inbound inbox and thread store, with a UTF-8 guard on inbound bodies and telemetry on drops.- Durable poller offsets, so a restarted adapter resumes where it stopped rather than replaying or skipping updates.
- Optional per-turn conversation logging. A session records turns to any
:logimplementingappend(server, conversation_id, items)keyed by a stableconversation_id;SessionRouter.handoff/3rebinds a conversation to another platform's route and reuses that id, so the log resumes the same history across platforms. - A failed delivery neither crashes the chat session nor enters outbound
history.
Raxol.Gateway.Sessionhandles adapter{:error, reason}returns, exceptions, and exits, logs the failure, and emits[:raxol_gateway, :session, :delivery_failed].
Notes
raxol_coreis the only required Raxol dependency.raxol(forHandler.Lifecycle),raxol_speech(forPipeline.Transcribe),gen_smtp(for the email adapter), andmint_web_socketandreq(for the Discord adapter) are optional; each entry point checks for its dependency before use.Raxol.Gateway.Handler.Agent, an agent-backed handler, ships inraxol_console, which requiresraxol_gateway ~> 0.2.- Pre-alpha. The public API may change inside 0.x.