WhatsApp (Web channel)
Section titled “WhatsApp (Web channel)”Status: production-ready via WhatsApp Web (Baileys). Gateway owns linked session(s).
Quick setup
Section titled “Quick setup”{ channels: { whatsapp: { dmPolicy: "pairing", allowFrom: ["+15551234567"], groupPolicy: "allowlist", groupAllowFrom: ["+15551234567"], }, },}coderclaw channels login --channel whatsappFor a specific account:coderclaw channels login --channel whatsapp --account workcoderclaw gatewaycoderclaw pairing list whatsappcoderclaw pairing approve whatsapp <CODE>Pairing requests expire after 1 hour. Pending requests are capped at 3 per channel.Deployment patterns
Section titled “Deployment patterns”- separate WhatsApp identity for CoderClaw- clearer DM allowlists and routing boundaries- lower chance of self-chat confusion
Minimal policy pattern:
```json5{ channels: { whatsapp: { dmPolicy: "allowlist", allowFrom: ["+15551234567"], }, },}```- `dmPolicy: "allowlist"`- `allowFrom` includes your personal number- `selfChatMode: true`
In runtime, self-chat protections key off the linked self number and `allowFrom`.There is no separate Twilio WhatsApp messaging channel in the built-in chat-channel registry.Runtime model
Section titled “Runtime model”- Gateway owns the WhatsApp socket and reconnect loop.
- Outbound sends require an active WhatsApp listener for the target account.
- Status and broadcast chats are ignored (
@status,@broadcast). - Direct chats use DM session rules (
session.dmScope; defaultmaincollapses DMs to the agent main session). - Group sessions are isolated (
agent:<agentId>:whatsapp:group:<jid>).
Access control and activation
Section titled “Access control and activation”- `pairing` (default)- `allowlist`- `open` (requires `allowFrom` to include `"*"`)- `disabled`
`allowFrom` accepts E.164-style numbers (normalized internally).
Multi-account override: `channels.whatsapp.accounts.<id>.dmPolicy` (and `allowFrom`) take precedence over channel-level defaults for that account.
Runtime behavior details:
- pairings are persisted in channel allow-store and merged with configured `allowFrom`- if no allowlist is configured, the linked self number is allowed by default- outbound `fromMe` DMs are never auto-paired1. **Group membership allowlist** (`channels.whatsapp.groups`) - if `groups` is omitted, all groups are eligible - if `groups` is present, it acts as a group allowlist (`"*"` allowed)
2. **Group sender policy** (`channels.whatsapp.groupPolicy` + `groupAllowFrom`) - `open`: sender allowlist bypassed - `allowlist`: sender must match `groupAllowFrom` (or `*`) - `disabled`: block all group inbound
Sender allowlist fallback:
- if `groupAllowFrom` is unset, runtime falls back to `allowFrom` when available
Note: if no `channels.whatsapp` block exists at all, runtime group-policy fallback is effectively `open`.Mention detection includes:
- explicit WhatsApp mentions of the bot identity- configured mention regex patterns (`agents.list[].groupChat.mentionPatterns`, fallback `messages.groupChat.mentionPatterns`)- implicit reply-to-bot detection (reply sender matches bot identity)
Session-level activation command:
- `/activation mention`- `/activation always`
`activation` updates session state (not global config). It is owner-gated.Personal-number and self-chat behavior
Section titled “Personal-number and self-chat behavior”When the linked self number is also present in allowFrom, WhatsApp self-chat safeguards activate:
- skip read receipts for self-chat turns
- ignore mention-JID auto-trigger behavior that would otherwise ping yourself
- if
messages.responsePrefixis unset, self-chat replies default to[{identity.name}]or[coderclaw]
Message normalization and context
Section titled “Message normalization and context”If a quoted reply exists, context is appended in this form:
```text[Replying to <sender> id:<stanzaId>]<quoted body or media placeholder>[/Replying]```
Reply metadata fields are also populated when available (`ReplyToId`, `ReplyToBody`, `ReplyToSender`, sender JID/E.164).- `<media:image>`- `<media:video>`- `<media:audio>`- `<media:document>`- `<media:sticker>`
Location and contact payloads are normalized into textual context before routing.- default limit: `50`- config: `channels.whatsapp.historyLimit`- fallback: `messages.groupChat.historyLimit`- `0` disables
Injection markers:
- `[Chat messages since your last reply - for context]`- `[Current message - respond to this]`Disable globally:
```json5{ channels: { whatsapp: { sendReadReceipts: false, }, },}```
Per-account override:
```json5{ channels: { whatsapp: { accounts: { work: { sendReadReceipts: false, }, }, }, },}```
Self-chat turns skip read receipts even when globally enabled.Delivery, chunking, and media
Section titled “Delivery, chunking, and media”Acknowledgment reactions
Section titled “Acknowledgment reactions”WhatsApp supports immediate ack reactions on inbound receipt via channels.whatsapp.ackReaction.
{ channels: { whatsapp: { ackReaction: { emoji: "👀", direct: true, group: "mentions", // always | mentions | never }, }, },}Behavior notes:
- sent immediately after inbound is accepted (pre-reply)
- failures are logged but do not block normal reply delivery
- group mode
mentionsreacts on mention-triggered turns; group activationalwaysacts as bypass for this check - WhatsApp uses
channels.whatsapp.ackReaction(legacymessages.ackReactionis not used here)
Multi-account and credentials
Section titled “Multi-account and credentials”In legacy auth directories, `oauth.json` is preserved while Baileys auth files are removed.Tools, actions, and config writes
Section titled “Tools, actions, and config writes”- Agent tool support includes WhatsApp reaction action (
react). - Action gates:
channels.whatsapp.actions.reactionschannels.whatsapp.actions.polls
- Channel-initiated config writes are enabled by default (disable via
channels.whatsapp.configWrites=false).
Troubleshooting
Section titled “Troubleshooting”Fix:
```bashcoderclaw channels login --channel whatsappcoderclaw channels status```Fix:
```bashcoderclaw doctorcoderclaw logs --follow```
If needed, re-link with `channels login`.Make sure gateway is running and the account is linked.- `groupPolicy`- `groupAllowFrom` / `allowFrom`- `groups` allowlist entries- mention gating (`requireMention` + mention patterns)Configuration reference pointers
Section titled “Configuration reference pointers”Primary reference:
High-signal WhatsApp fields:
- access:
dmPolicy,allowFrom,groupPolicy,groupAllowFrom,groups - delivery:
textChunkLimit,chunkMode,mediaMaxMb,sendReadReceipts,ackReaction - multi-account:
accounts.<id>.enabled,accounts.<id>.authDir, account-level overrides - operations:
configWrites,debounceMs,web.enabled,web.heartbeatSeconds,web.reconnect.* - session behavior:
session.dmScope,historyLimit,dmHistoryLimit,dms.<id>.historyLimit