Pick your first transport
Every transport is a thin adapter behind the same transport.Transport interface — allowlisting, session routing, and cron delivery are identical across all of them. The differences are pairing UX and the per-transport identifier format (JID, user ID, room ID). Pick whichever you can pair fastest:
WhatsApp is the reference — hardest to pair, easiest to test (you already have the app on your phone).
Prerequisites: your phone with WhatsApp, your E.164 JID (e.g. 447900123456@s.whatsapp.net).
rousseau whatsapp --allow 447900123456@s.whatsapp.net
Scan the QR from WhatsApp > Settings > Linked devices > Link a device. Send hello to yourself; rousseau replies via WhatsApp. See below for the full walkthrough.
Prerequisites: admin on a Slack workspace, an app created at api.slack.com/apps, Socket Mode enabled.
- Create a Slack app, enable Socket Mode under Settings > Socket Mode.
- Create an App-Level Token with
connections:write— this is thexapp-…token. - Under OAuth & Permissions, add bot scopes
chat:write,im:history,im:read,im:write,mpim:history,mpim:read. Install to the workspace to get thexoxb-…bot token. - Under Event Subscriptions, subscribe to
message.im(DMs) and any channel event you want.
rousseau slack --app-token xapp-... --bot-token xoxb-... --allow U01234567
DM the bot in Slack; rousseau replies in the same DM. See Transports: Slack for the full walkthrough with OAuth scope rationale.
Prerequisites: a Discord application at discord.com/developers/applications, a bot user, the Message Content Intent enabled under Bot.
- Create an application, add a bot, copy the bot token.
- Under Bot > Privileged Gateway Intents, enable Message Content Intent. Without this, message text arrives empty.
- Invite the bot via OAuth2 > URL Generator — scope
bot, permissionsSend Messages,Read Message History.
rousseau discord --token <bot-token> --allow 234567890123456789
DM the bot; rousseau replies. See Transports: Discord for permissions and intents deep dive.
Prerequisites: a Telegram bot from @BotFather.
- Message
@BotFather,/newbot, follow prompts. Copy the token. - Talk to your bot at least once so Telegram creates a chat.
rousseau telegram --token 1234567890:AA... --allow 987654321
The --allow value is the Telegram numeric user ID (not username). Get it by messaging @userinfobot.
Prerequisites: signal-cli installed and linked to a Signal account. See the signal-cli docs for the pairing flow.
rousseau signal --account +447900123456 --allow +447900654321
Rousseau spawns signal-cli as a subprocess (see internal/cli/signal.go) and communicates with it via JSON-RPC. See Transports: Signal.
Why the WhatsApp walkthrough
The rest of this page uses WhatsApp as the canonical example — if you get the pattern here, every other transport is a variation on it (allowlist a stable ID, run a pairing UX once, send a test, verify the reply). Skip to the sibling transport page if you already have a token in hand:
- Slack — Socket Mode tokens and event subscriptions.
- Discord — bot token, intents, permission integers.
- Telegram — BotFather token.
- Signal — signal-cli subprocess.
- Matrix — homeserver URL + access token.
Prerequisites
rousseauon$PATH(see Installation).- A working provider —
claudecliinheriting Claude Code auth is the default; anything else needs its config filled in first (Configuration). - Your phone with WhatsApp installed. Your E.164 phone JID (e.g.
447900123456@s.whatsapp.net).
Step 1 — Choose the JID that will drive the daemon
Rousseau uses an allowlist to restrict inbound handling to a fixed set of JIDs. Every other sender is silently dropped. This is load-bearing: without an allowlist, anyone who knows the number could drive the agent.
Your E.164 JID is your phone number, digits only, followed by @s.whatsapp.net:
447900123456@s.whatsapp.net
Group JIDs end in @g.us; the daemon supports those too, but start with a personal JID.
Step 2 — First launch and pairing
rousseau whatsapp --allow 447900123456@s.whatsapp.net
On first launch, a QR code is printed to stdout. Open WhatsApp on your phone, go to Settings → Linked devices → Link a device, and scan the QR.
The daemon prints something like:
whatsapp.starting store=file:/home/you/.local/share/rousseau/whatsapp.db?_pragma=... allowlist=1
Once you scan, whatsmeow persists device credentials to whatsapp.db. Subsequent launches connect silently — no more QR.
Step 3 — Send a test message
From your phone, send hello to yourself. The daemon logs the inbound event, dispatches to the agent, and delivers the reply back through WhatsApp with the configured header:
💎 *Rousseau Agent*
Hello — what would you like to work on?
The reply header is configurable via whatsapp.reply_header. Set it to a single space to disable the prefix.
Step 4 — Set up a config.yaml so you don't need long flags
Create ~/.config/rousseau/config.yaml:
provider: claudecli
claudecli:
binary: claude
permission_mode: bypassPermissions
whatsapp:
reply_header: "💎 *Rousseau Agent*\n\n"
Now rousseau whatsapp --allow 447900123456@s.whatsapp.net picks up the header automatically. Every transport reads its stanza from the same file — see Configuration for the full list.
bypassPermissions is the default for unattended daemons because there is no human on the other end of the terminal to approve tool calls interactively. Set up an approval policy (User Guide: Approval Policies) before you point the daemon at anything you care about.
Step 5 — Confirm end-to-end
Send a coding question from your phone:
Read the file at /workspace/README.md and summarise it in 3 bullets.
The daemon runs a read tool call, feeds the file to the model, and messages you back with the summary. You have just closed the loop:
- Phone → WhatsApp → whatsmeow WebSocket
- rousseau-agent → agent loop → tool call → provider call
- reply → whatsmeow → WhatsApp → phone
Nothing crossed your network perimeter except the provider call — and if the provider was claudecli on your local Claude Code install, not even that.
Verifying with rousseau doctor
rousseau doctor
Every check for the WhatsApp path is covered:
provider.claudecli.binary,provider.claudecli.version— the LLM path.state.path,state.db_size,state.sessions— SQLite session store.whatsapp.store,whatsapp.paired— device credentials.whatsapp.voice— voice-note transcription posture.
A fail row is a hard stop; a warn row is worth investigating before rolling out.
Troubleshooting
QR code prints but the phone rejects it
Three common causes. First, a partially-completed prior pairing left whatsapp.db in a state whatsmeow cannot reuse — delete ~/.local/share/rousseau/whatsapp.db and re-scan. Second, the clock is skewed by more than 30 seconds (common in containers without a working NTP client) — WhatsApp's handshake is time-sensitive. Third, an older whatsmeow version can miss a Meta protocol update; upgrade rousseau.
I sent a message but the daemon logs router.transport.rejected
Your JID does not match the allowlist. The value passed to --allow must be the sender's JID exactly as WhatsApp reports it (447900123456@s.whatsapp.net, no +, no spaces). Note that self-chat testing works because rousseau substitutes the account's own JID for the LID privacy hash (see internal/transport/whatsapp/resolve.go).
No QR code prints and the daemon exits with no rows
The whatsmeow store was never initialised. Ensure the parent directory (~/.local/share/rousseau/) exists and is writable. rousseau doctor reports this under whatsapp.store.
Rousseau replies but the model output is empty
Check provider.claudecli.binary and provider.claudecli.version in rousseau doctor. The most common empty-reply cause is a claudecli invocation returning is_error: true — the daemon logs the truncated error at warn level. Switch provider to anthropic or bedrock to isolate the subprocess.
Slack/Discord: "invalid_auth" or "401 Unauthorized"
For Slack, xapp-… (app token) and xoxb-… (bot token) are different — mixing them up produces invalid_auth. For Discord, the token displayed on Bot > Reset Token is one-shot; if you copied it once and lost it, you must reset again.
Related pages
- Transports — every transport, its wire protocol, and its allowlist format.
- User Guide: CLI — every command and flag.
- User Guide: Approval Policies — the primary safety lever.
- Deployment — hand off from foreground
rousseau whatsappto a systemd unit. - Voice mode — turn WhatsApp voice notes into agent turns.
Further reading
internal/transport/whatsapp/client.go— connect, QR, event pump.internal/transport/whatsapp/resolve.go— LID/JID normalisation and self-chat handling.internal/cli/whatsapp.go— CLI wiring, store DSN, transcriber selection.internal/cli/slack.go,internal/cli/discord.go— sibling transport CLIs.internal/transport/router.go— allowlist enforcement.