?

Overview

rousseau whatsapp runs the WhatsApp bridge in the foreground. It embeds go.mau.fi/whatsmeow (unofficial WhatsApp Web protocol) and speaks directly to Meta's servers. On first launch a QR code is printed to stdout; scan it from your phone under WhatsApp > Settings > Linked devices. Device credentials are cached to a SQLite store separate from the session database.

Source: internal/cli/whatsapp.go. Transport implementation: internal/transport/whatsapp/.

Synopsis

rousseau whatsapp [--store <path>] [--allow <jid>...] [--config <path>]

Flags

Flag Type Default Effect
--store string $XDG_DATA_HOME/rousseau/whatsapp.db Path to the whatsmeow device store (SQLite with WAL, busy_timeout=15000, synchronous=NORMAL).
--allow []string empty Restrict inbound to these JIDs. Repeatable. Empty allows anyone — never do this on a public number.
--config string inherits from root Path to the YAML config file.

Config keys respected

Read from internal/config/config.go WhatsAppConfig:

Key Type Default Effect
whatsapp.reply_header string "💎 *Rousseau Agent*\n\n" Prefix prepended to every outbound message. Set to " " to disable.
whatsapp.voice.enabled bool false Enable whisper-based transcription for inbound voice notes.
whatsapp.voice.binary string whisper Whisper CLI to invoke.
whatsapp.voice.model string empty Passed to --model (e.g. base.en).
whatsapp.voice.model_path string empty Explicit .bin path; takes precedence over model.
whatsapp.voice.language string empty Passed to --language; empty auto-detects.
whatsapp.voice.extra_args []string empty Appended to every whisper invocation.

Allowlist syntax

Every allowlist entry is a WhatsApp JID (Jabber ID). The two forms in use:

447900123456@s.whatsapp.net

E.164 without a leading + followed by @s.whatsapp.net. This is the JID that identifies a single phone number.

The router (internal/transport/router.go) checks the sender's normalised JID against the allowlist. Non-matching senders are dropped with a router.transport.rejected log event.

Environment variables

Variable Effect
ROUSSEAU_WHATSAPP_REPLY_HEADER Overrides the reply header.
XDG_DATA_HOME Base directory for the device store.
ROUSSEAU_LOG_LEVEL Also translated into whatsmeow's log level (DEBUG, INFO, WARN, ERROR).

Plus every provider variable — see rousseau chat.

Startup sequence

  1. setUnattendedPermissionDefault(opts, "whatsapp") — flips claudecli.permission_mode to bypassPermissions if empty, because unattended daemons cannot answer permission prompts interactively.
  2. assembleDaemon — opens the session store, builds the provider, tool registry, approver, compressor.
  3. resolveWhatsAppDSN — computes the SQLite DSN with WAL pragmas.
  4. whatsapp.New — creates the whatsmeow client and (optionally) the whisper transcriber.
  5. wiring.startCron — starts the cron scheduler with the whatsapp Deliver as the delivery callback, so rousseau cron add jobs land on the configured target JIDs.
  6. client.Start — blocks until the context is cancelled (Ctrl+C, SIGTERM).

Log events

Event Attributes Emitted by
whatsapp.qr_ready none first-pairing QR code rendered to stdout
whatsapp.paired jid phone accepted the QR
whatsapp.connected none websocket handshake completed
whatsapp.starting store, allowlist pre-connect
whatsapp.voice_enabled binary, model when voice transcription is enabled
router.transport.rejected sender, reason inbound sender not on the allowlist

Exit codes

Code Meaning
0 Clean context cancellation (SIGTERM).
1 Provider, store, whatsmeow, or DSN error before or during startup.
130 SIGINT interrupt.

Worked examples

# Personal chat with a single allowed number
rousseau whatsapp --allow 447900123456@s.whatsapp.net

# Multiple numbers plus a team group
rousseau whatsapp \
  --allow 447900123456@s.whatsapp.net \
  --allow 447900222222@s.whatsapp.net \
  --allow 447900123456-1567890123@g.us

# Explicit store path (useful in Podman with a bind-mounted volume)
rousseau whatsapp --store /var/lib/rousseau/whatsapp.db

# Voice notes with a local whisper.cpp binary
cat >> ~/.config/rousseau/config.yaml <<'EOF'
whatsapp:
  voice:
    enabled: true
    binary: /usr/local/bin/whisper
    model: base.en
EOF
rousseau whatsapp --allow 447900123456@s.whatsapp.net

Common failure modes

  • QR displayed but never accepted — clock drift, stale whatsapp.db, or Meta-invalidated number. Delete whatsapp.db and re-pair; check timedatectl status.
  • store: locked — another rousseau whatsapp process is holding the WAL lock. WAL allows readers but only one writer.
  • Voice notes not transcribedwhatsapp.voice.enabled: false, or the whisper binary is not on $PATH. rousseau doctor surfaces both.
  • Silent inbound drops — the sender is not on the allowlist. Check router.transport.rejected in the logs.

Related pages

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