Connect OpenCrabs to WhatsApp via QR code pairing.
Setup
Configure via the Onboarding Wizard
Run /onboard:channels (or /onboard and navigate to the Channels step):
- Use
↑/↓to focus WhatsApp - Press
Spaceto toggle it on - Press
Enterto open the WhatsApp setup screen - The setup screen has two fields:
- Connection — shows the QR code or connection status
- Phone Allowlist — comma-separated phone numbers in E.164 format (e.g.
+15551234567). Leave empty to accept all messages.
- When not yet paired, a QR code appears in the terminal:
- Open WhatsApp on your phone → Settings → Linked Devices → Link a Device
- Scan the QR code
- The status updates to “Connected” automatically
- When already paired, press
Ron the Connection field to reset and re-pair - Press
Enterto save
The pairing session persists across restarts — no need to re-scan.
Manual Configuration (advanced)
# config.toml
[channels.whatsapp]
enabled = true
allowed_phones = ["+15551234567"]
Configuration
WhatsApp options live under [channels.whatsapp] in ~/.opencrabs/config.toml:
[channels.whatsapp]
enabled = true
allowed_phones = ["+15551234567"] # E.164 format
session_idle_hours = 24.0 # idle timeout for non-owner sessions
| Field | Default | Description |
|---|---|---|
enabled | false | Enable the WhatsApp channel |
allowed_phones | [] (open replies under auto, but never owner rights) | E.164 phone numbers. Since v0.5.1 an empty list no longer makes every sender the bot owner — owner commands (/evolve, /rebuild, /exit, /cd) and approval answers need the self-chat, bot_owner, or the resolver over bot_owner + allowed_phones |
session_idle_hours | None (no timeout) | Idle timeout for non-owner sessions. Owner sessions never expire |
response_policy | "auto" | Who the bot responds to. auto: reply to all while there is at most one active sender, then switch to mention-only once a second unique sender appears. owner_only: only the bot owner. allowlist: only allowed phones. open: everyone |
bot_owner | None (auto-seeded from allowed_phones[0]) | Phone number of the bot owner in E.164 format. The owner gets access that other allowlisted users do not. Commands that expose personal data or the host system are owner-only |
How it works
One account per instance. Each OpenCrabs instance supports one WhatsApp account (one companion device). You run the bot AS whatever account you scan: your own number (talk via “Message Yourself”), or any other number you own, including a WhatsApp Business account.
The bot talks to itself. If you message the bot’s own paired number, the bot replies to you. This is by design. The paired account’s self-chat is always allowed, regardless of response_policy or allowed_phones.
Allowlist behavior. Anyone messaging the paired number who is on the allowed_phones
list gets a reply. The response_policy controls who else can interact beyond the allowlist.
Ownership (v0.5.1, deny-by-default). Before v0.5.1 an empty allowed_phones under
response_policy = "auto" answered every contact and elevated them all to owner — one
forgotten allowlist away from handing strangers /evolve and /cd. That elevation is gone:
being answered no longer means being in charge. Owner status comes from the paired
account’s self-chat, a configured bot_owner, or ownership resolution over
allowed_phones + bot_owner — never from an empty list. Tool-approval replies
(Yes/Always/No/YOLO) resolve only for the owner on all four channels.
- Personal and group chats — Works in DMs and group conversations
- Image support — Send and receive images
- Voice messages — STT transcription + TTS response
- Plain text UI — No buttons (WhatsApp limitation), uses text-based menus
- Slash commands — All built-in and custom commands work
Outbound rate limiting
WhatsApp is the channel with the heaviest ban consequences, so every outbound send goes through a budget (since v0.5.1):
[channels.whatsapp.rate_limit]
messages_per_minute = 30 # token bucket: sustained sends per minute
daily_cap = 800 # rolling 24h hard cap
| Mechanism | Behavior |
|---|---|
| Per-minute pacing | A token bucket sized to messages_per_minute (default 30) refills continuously. An over-budget send is paced, not dropped: the caller sleeps for the refill gap and then sends. Set 0 to disable pacing. |
| Rolling daily cap | The 24h window allows daily_cap sends (default 800). On saturation further sends park in a FIFO queue; a background drainer flushes them as the window slides. A queued quote-reply loses its quote context — the text still arrives. Set 0 to disable the cap. |
| Owner alert | The first send queued in a saturation episode alerts the bot owner exactly once (through the WhatsApp session), and the alert re-arms when traffic drops back under the cap. |
| Owner bypass | Messages addressed to the owner skip budget consumption entirely, so you always get fast replies; the saturation alert itself is also exempt. |
Streaming answers used to post every chunk as its own message — exactly the volume pattern Meta’s heuristics hunt. Outbound replies now edit one message in place (since v0.5.1), which keeps chunked turns well inside the budget; the limiter is the safety net underneath.
Formatting Notes
- No markdown tables — use bullet lists
- No headers — use bold or CAPS for emphasis
- Links render natively
Voice Message Handling
When receiving a voice message:
- Agent downloads and transcribes via STT
- Sends text response first (searchable)
- Optionally generates TTS audio response
Features
- Personal and group chats — Works in DMs and group conversations
- Image support — Send and receive images
- Voice messages — STT transcription + TTS response
- Plain text UI — No buttons (WhatsApp limitation), uses text-based menus
- Slash commands — All built-in and custom commands work
Troubleshooting
Wrong number replying
Each OpenCrabs instance supports one WhatsApp account (one companion device). If you connected multiple numbers or the wrong number is replying, you need a full reset. The bot always uses the last number you connected.
Critical: Always reset the connection before connecting a new number. OpenCrabs only keeps the last paired number.
Full reset steps:
- Remove ALL linked devices from WhatsApp. Open WhatsApp on your phone, go to Settings > Linked Devices, and remove every device in the list. Don’t bother hunting for the
opencrabsone. A stale device left over from an earlier pairing is the usual reason the old number keeps replying, so the reliable fix is to clear them all and start fresh. - Reset the connection in OpenCrabs — in the TUI or from a channel, go to
/onboard:channelsand press R to reset the WhatsApp connection. Wait for confirmation that the reset is complete. - Re-pair from scratch — after the reset is confirmed, go to WhatsApp > Settings > Linked Devices > Link a Device and scan the new QR code shown by OpenCrabs.
If the bot still shows the old number after resetting, make sure you completed step 1 (removing the device from WhatsApp) before step 2.
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Old number still replying | A stale linked device is still paired | Remove ALL linked devices from WhatsApp > Settings > Linked Devices, then press R in /onboard:channels and re-pair |
| QR code doesn’t appear | Agent is still connected (no restart triggered) | Press R in /onboard:channels to force a restart, then wait for the new QR |
| Bot doesn’t reply to anyone | response_policy is too restrictive | Set response_policy = "allowlist" and add phone numbers to allowed_phones in config.toml |
| Bot replies to everyone | response_policy is open | Set response_policy = "allowlist" or "owner_only" in config.toml |
| Bot doesn’t reply to self-chat | allowed_phones doesn’t include the paired number | The paired number’s self-chat is always allowed, regardless of allowed_phones. If it’s not working, check that response_policy isn’t too restrictive |