?

The Transport interface

Every transport implements one small interface (internal/transport/transport.go):

type Transport interface {
    Name() string
    Start(ctx context.Context, handler Handler) error
    Stop() error
}

Above the transport sits the Router, which handles per-sender session lookup, allowlist enforcement, and dispatch to the Agent. Below sits the transport-specific wire code.

None of the shipped transports expose a public HTTP surface by default. This is a deliberate posture choice — rousseau daemons should be safe to run behind NAT with no port-forwarding rules.

Supported transports

Transport Inbound Outbound Backing library / protocol Auth One-line setup
WhatsApp yes yes go.mau.fi/whatsmeow Device pair (QR) rousseau whatsapp --allow <jid>
Signal yes yes signal-cli JSON-RPC Pre-registered account rousseau signal --account +447900123456
Telegram yes yes Bot API long-polling BotFather token rousseau telegram --token <token>
Matrix yes yes Client-server API /sync Access token rousseau matrix --homeserver-url … --access-token …
Slack yes yes Socket Mode + Web API xapp-* + xoxb-* rousseau slack --app-token … --bot-token …
Discord yes yes Gateway v10 + REST Bot token rousseau discord --token <token>
iMessage yes yes BlueBubbles HTTP polling Server password rousseau imessage --base-url … --password …
Email yes yes IMAP + SMTP Username + password rousseau email --imap-addr … --smtp-addr …
SMS no yes Twilio or Vonage REST Account SID / API key rousseau sms --provider twilio --account-sid … --auth-token …

Why no public HTTP surface

Two design choices keep every listed transport away from a public webhook:

  • WebSocket-based inbound. Slack Socket Mode and Discord Gateway are outbound-only from the daemon's perspective — the daemon dials the vendor over TLS and messages arrive on the same connection.
  • Polling. WhatsApp, Telegram, Matrix, iMessage, and email pull for updates on their own cadence. There is no webhook the vendor calls into.

SMS is the exception, and rousseau resolves it by making SMS send-only. Inbound SMS would require a Twilio / Vonage webhook, which is exactly the surface this project refuses to introduce.

Router behaviour

The router (internal/transport/router.go) sits between every transport and the Agent:

  • Session isolation. Every distinct From value gets its own Session, so parallel conversations do not cross-contaminate. WhatsApp LID identities are normalised to phone JIDs first (see internal/transport/whatsapp/resolve.go).
  • Allowlist. Every transport that supports inbound has an Allowlist []string in its config. Empty means "accept every sender" — for daemons you always want at least one entry.
  • Dispatch. The router serialises turns per session so a user cannot stack two concurrent inbound messages.

Adding a tenth transport

Implement transport.Transport (three methods). Add a Config type mirroring the block layout under internal/config/. Wire a CLI command in internal/cli/. That is the surface — the agent core stays untouched.

Per-transport pages

Type to search 150+ pages. Ranking: BM25 with title/description boost.