@whiskeysockets/baileys 7.0.0-rc.9 (pinned; the WhatsApp Web protocol), not the Chat SDK bridge. For Meta’s official Cloud API instead, use /add-whatsapp-cloud — see the channels overview.
You can run it in two modes:
- Shared number — the agent lives on your own WhatsApp account. Its replies are prefixed with the agent name (
Andy: …) so they’re distinguishable from yours. - Dedicated number — a separate phone/SIM for the agent. Setting
ASSISTANT_HAS_OWN_NUMBER=truedrops the name prefix on outbound messages and switches bot-echo detection from prefix matching to sender identity.
Prerequisites
- A phone with WhatsApp installed and online — you’ll link NanoClaw under Settings → Linked Devices
- A working NanoClaw install (quickstart)
- For pairing-code auth: the account’s phone number, digits only with country code (e.g.
14155551234)
Install
WhatsApp is offered in the first-run setup wizard, or add it later by running/add-whatsapp in Claude Code. Both flows do the same thing:
1
Choose your mode
The skill starts with a number safety check: will the agent live on your personal number (shared mode — messages land in your “You” self-chat) or on a separate SIM it owns (dedicated mode)? Dedicated mode writes
ASSISTANT_HAS_OWN_NUMBER=true to .env (and data/env/env for containers).2
Adapter install
The skill copies
src/channels/whatsapp.ts and the whatsapp-formatting container skill from the channels branch, wires the adapter into the channel barrel, and installs the pinned Baileys, qrcode, and pino packages.3
Pick an auth method
QR code (scan with your phone’s camera) or pairing code (enter an 8-character code on your phone — no camera needed). The pairing-code flow asks for your phone number first.
4
Link your phone
A QR code renders (terminal, or a local browser page via the skill) and rotates every ~60 seconds until scanned. Pairing codes also expire in ~60 seconds — enter them immediately under Linked Devices → Link a Device → Link with phone number instead. Credentials land in
store/auth/, and the wizard restarts the service so the adapter picks them up.5
Name the agent and get the welcome DM
The wizard asks for an agent name (default
Nano), wires your DM to the first agent group, and sends a welcome message./manage-channels.
Platform notes
- Auth persistence — credentials live in
store/auth/(multi-file auth state). Restarts reuse the saved session; you only re-pair if WhatsApp logs the device out. On a server-side logout the adapter wipesstore/auth/so the next start prompts a fresh pair. - Activation — the adapter only starts when
store/auth/creds.jsonexists,WHATSAPP_PHONE_NUMBERis set (pairing-code mode), orWHATSAPP_ENABLED=true(QR mode). Otherwise it’s skipped at startup. - Reconnection — on disconnect the adapter reconnects immediately (with one retry after 5s if that attempt throws) unless it was logged out. Messages sent while disconnected are queued in memory and flushed when the connection reopens.
- No threads — the adapter sets
supportsThreads: false; every inbound message has a null thread ID. Wirings withper-threadsession mode behave likesharedhere — see the entity model. - DMs vs groups — DMs always count as addressed to the agent, in both modes. Group behavior (
…@g.usJIDs) depends on the mode. Shared number: an @-tag of the number addresses you, the human — it never engages the agent; instead the agent triggers when its name appears as a whole word in the message, and unknown senders fall under thestrictpolicy so strangers DMing you never spawn agent state. Dedicated number: groups engage on an explicit @-mention of the bot’s number, and unknown senders get therequest_approvalpolicy. Group names sync from WhatsApp every 24 hours. - Media — inbound images, video, audio, and documents are downloaded to
data/attachments/and passed to the agent (unsafe attacker-controlled filenames are replaced). If the direct download fails — typically an expired media URL around a reconnect — the adapter asks WhatsApp to re-upload the media and retries; if it still can’t be fetched, the message reaches the agent with a visible[<type> could not be downloaded]note instead of silently dropping the attachment. Outbound files are sent as native WhatsApp media by extension, with the reply text as the first file’s caption. - Formatting — the agent’s markdown is converted to WhatsApp formatting (
**bold**→*bold*, headings → bold, links →text (url)); code blocks pass through untouched.@<phone>in replies becomes a real tappable mention. - Interactive questions —
ask_user_questionrenders as text with slash-command answers (/approve,/reject); the adapter matches your reply to the pending question. Editing and deleting sent messages isn’t supported (linked-device limitation). - Self-chat — in shared mode you can message the agent in your own “You” chat. The adapter tells your typed messages apart from its own echoes via a sent-message cache.
Troubleshooting
- Logged out / re-pair loop — if logs show
WhatsApp logged outfollowed byWhatsApp auth cleared, the account was unlinked server-side (often a 401). The adapter already wipedstore/auth/; setWHATSAPP_ENABLED=trueand restart (or re-run/add-whatsapp) to scan a fresh QR. Could not fetch current WhatsApp Web version— Baileys’ hardcoded protocol version goes stale and WhatsApp rejects it (405), so the adapter fetches the current version at startup from wppconnect.io with web.whatsapp.com as fallback. This error means both fetches failed: check outbound network access to those hosts.- Agent silent, messages arrive late in a burst — the connection dropped; outbound messages were queued (
WA disconnected, message queuedin logs) and flushed on reconnect. Confirm the lastConnected to WhatsApplog line and that only one NanoClaw process holds these credentials — a second instance causes “conflict” disconnect loops. - QR or pairing code expired — both rotate/expire in ~60 seconds. Re-run the auth step for a fresh code; for pairing codes, the number must be digits only with country code, no
+. If pairing codes keep getting rejected, switch to the QR method — it’s more reliable.