Files
nanoclaw/.claude/skills/add-whatsapp-v2/SKILL.md
Gabi Simons 192a5a7569 docs(v2): add /add-whatsapp-v2 setup skill
Separate from the v1 /add-whatsapp skill — v1 remains untouched.
Follows the v2 skill pattern (flat sections, defers to /manage-channels
for wiring). Covers Baileys auth, pairing code, QR code, and
documents the native adapter's features and limitations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 12:02:27 +00:00

6.0 KiB

name, description
name description
add-whatsapp-v2 Add WhatsApp channel to NanoClaw v2 using native Baileys adapter. Direct connection — no Chat SDK bridge. Uses QR code or pairing code for authentication.

Add WhatsApp Channel

Adds WhatsApp support to NanoClaw v2 using the native Baileys adapter (no Chat SDK bridge).

Pre-flight

Check if src/channels/whatsapp.ts exists and the import is uncommented in src/channels/index.ts. If both are in place, skip to Credentials.

Install

Install the adapter packages

npm install @whiskeysockets/baileys@^6.7.21 pino@^9.6.0 qrcode@^1.5.4 @types/qrcode@^1.5.6

Enable the channel

If src/channels/whatsapp.ts is missing, fetch it from upstream:

git remote -v | grep -q upstream || git remote add upstream https://github.com/qwibitai/nanoclaw.git
git fetch upstream v2
git checkout upstream/v2 -- src/channels/whatsapp.ts

Uncomment or add the WhatsApp import in src/channels/index.ts:

// whatsapp (native, no Chat SDK)
import './whatsapp.js';

Build

npm run build

Credentials

WhatsApp uses linked-device authentication — no API key, just a one-time pairing from your phone.

Detect environment

[[ -z "$DISPLAY" && -z "$WAYLAND_DISPLAY" && "$OSTYPE" != darwin* ]] && echo "IS_HEADLESS=true" || echo "IS_HEADLESS=false"

Ask the user

AskUserQuestion: How do you want to authenticate WhatsApp?

  • Pairing code (Recommended for headless/VM) — enter a numeric code on your phone, requires phone number
  • QR code in terminal — displays QR code in the terminal

If pairing code:

AskUserQuestion: What is your phone number? (Digits only — country code + number, no + prefix, spaces, or dashes. Example: 14155551234 where 1 is the US country code and 4155551234 is the phone number.)

Configure auth method

For pairing code, set the phone number in .env:

grep -q WHATSAPP_PHONE_NUMBER .env 2>/dev/null || echo "WHATSAPP_PHONE_NUMBER=<their-number>" >> .env

For QR code, ensure WHATSAPP_PHONE_NUMBER is NOT set (comment it out if present).

Authenticate

The adapter authenticates on first startup. Restart the service:

# Linux
systemctl --user restart nanoclaw

# macOS
launchctl kickstart -k gui/$(id -u)/com.nanoclaw

Pairing code flow — poll for the code:

for i in $(seq 1 30); do [ -f data/whatsapp-pairing-code.txt ] && cat data/whatsapp-pairing-code.txt && break; sleep 1; done

Tell the user:

Enter this code now — it expires in ~60 seconds.

  1. Open WhatsApp > Settings > Linked Devices > Link a Device
  2. Tap Link with phone number instead
  3. Enter the code immediately

QR code flow — watch logs:

tail -f logs/nanoclaw.log | grep -A 30 "WhatsApp QR code"

Tell the user:

  1. Open WhatsApp > Settings > Linked Devices > Link a Device
  2. Scan the QR code displayed in the logs

Verify authentication

test -f data/whatsapp-auth/creds.json && echo "Authentication successful" || echo "Authentication failed"
grep "Connected to WhatsApp" logs/nanoclaw.log | tail -1

Shared vs dedicated number

AskUserQuestion: Is this a shared phone number (personal WhatsApp) or a dedicated number?

  • Shared number — your personal WhatsApp (bot prefixes messages with its name)
  • Dedicated number — a separate phone/SIM for the assistant

If dedicated, add to .env:

ASSISTANT_HAS_OWN_NUMBER=true

Next Steps

If you're in the middle of /setup, return to the setup flow now.

Otherwise, run /manage-channels to wire this channel to an agent group.

Channel Info

  • type: whatsapp
  • terminology: WhatsApp calls them "groups" and "chats." A "chat" is a 1:1 DM; a "group" has multiple members.
  • how-to-find-id: DMs use <phone>@s.whatsapp.net (e.g. 14155551234@s.whatsapp.net). Groups use <id>@g.us. To find your number: node -e "const c=JSON.parse(require('fs').readFileSync('data/whatsapp-auth/creds.json','utf-8'));console.log(c.me?.id?.split(':')[0]+'@s.whatsapp.net')". Groups are auto-discovered — check sqlite3 data/v2.db "SELECT platform_id, name FROM messaging_groups WHERE channel_type='whatsapp' AND is_group=1".
  • supports-threads: no
  • typical-use: Interactive chat — direct messages or small groups
  • default-isolation: Same agent group if you're the only participant across multiple chats. Separate agent group if different people are in different groups.

Features

  • Markdown formatting — **bold***bold*, *italic*_italic_, headings→bold, code blocks preserved
  • Approval questions — ask_user_question renders with /approve, /reject slash commands
  • File attachments — send and receive images, video, audio, documents
  • Reactions — send emoji reactions on messages
  • Typing indicators — composing presence updates
  • Credential requests — text fallback (WhatsApp has no modal support)

Not supported (WhatsApp linked device limitation): edit messages, delete messages.

Troubleshooting

Pairing code not working

Codes expire in ~60 seconds. Delete auth and retry:

rm -rf data/whatsapp-auth/ && systemctl --user restart nanoclaw

Ensure: digits only (no +), phone has internet, WhatsApp is updated.

"waiting for this message" on reactions

Signal sessions corrupted from rapid restarts. Clear sessions:

systemctl --user stop nanoclaw
rm data/whatsapp-auth/session-*.json
systemctl --user start nanoclaw

Bot not responding

  1. Auth exists: test -f data/whatsapp-auth/creds.json
  2. Connected: grep "Connected to WhatsApp" logs/nanoclaw.log | tail -1
  3. Channel wired: sqlite3 data/v2.db "SELECT mg.platform_id, mg.name FROM messaging_groups mg JOIN messaging_group_agents mga ON mg.id=mga.messaging_group_id WHERE mg.channel_type='whatsapp'"
  4. Service running: systemctl --user status nanoclaw

"conflict" disconnection

Two instances connected with same credentials. Ensure only one NanoClaw process is running.