with one click
// WhatsApp messages, contacts, groups (not generic text/message). Requires whatsapp daemon.
// WhatsApp messages, contacts, groups (not generic text/message). Requires whatsapp daemon.
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | |
| description | WhatsApp messages, contacts, groups (not generic text/message). Requires whatsapp daemon. |
whatsappSetup / first-time auth / re-auth: see SETUP.md.
Start daemon: screen -dmS whatsapp whatsapp serve --notifications-dir ~/agent/notifications
whatsapp <subcommand> [positionals] [--flag value ...]. Subcommand goes first, before any flags.whatsapp send 'Alice' 'Hi' is identical to whatsapp send --to 'Alice' --message 'Hi'). You can always use the flag form.whatsapp <subcommand> --help. The top-level whatsapp with no args prints the command list.--to / --chat-id / --group: contact name, phone (+E.164), group name, or JID - the CLI resolves them.send-message, prefer --message-file <path> (or --message-file - / --message - to read from stdin) when the body contains apostrophes, quotes, or multiple lines: this avoids shell-escaping issues that break --message 'text'.whatsapp send --to 'Name' --message 'reply text' --reply-to '<message_id>'
The --reply-to flag quotes the referenced message in WhatsApp's native reply UI. The message ID can be found in incoming notification payloads (message_id field) or list-messages output.
Aliases in parentheses. Positional signature shown after : for commands that take positionals.
Sending
send-message (send) : <to> <message>send-file (file) : <to> <file-path>send-audio - voice note; use --help for flagssend-reaction (react) : <to> <message-id> <emoji>revoke-message - unsend; --to <to> --message-id <id>download-media - --to <to> --message-id <id>; saves to ~/.whatsapp/downloads/Reading
list-chats (chats)list-messages (messages) : <to> - local DB onlylist-contacts (contacts, search-contacts)list-groups (groups)list-received-contacts - contact cards (vCards) received from otherscheck-delivery (delivery) : <message-id>backfill : <to> - asks the phone for older historyContacts
add-contact : <name> <phone>remove-contact : <identifier> (name or phone)Groups
create-group - --help for flagsleave-group : <group>rename-group (rename) : <group> <name>set-group-description : <group> <description>set-group-photo - --help for flagsget-group-invite-link - --help for flagsupdate-group-participants - add/remove members; --help for flagsChat management
archive-chat : <to>archive-all-chatsdelete-chat : <to>clear-all-chats - destructive; wipes local message DBAuth / daemon (see SETUP.md for details)
serve - starts the background daemon; requires --notifications-dirauthenticate - QR-code pairingpair-phone - phone-number pairing; --phone <+E.164>Send messages one tool call at a time. Never batch WhatsApp sends in a single parallel tool-call block. Why: If one parallel call fails while another succeeds, you can't tell which went through. Retrying "the failed one" sends a duplicate that the recipient sees.
whatsapp serve requires --notifications-dir.
Why: Without it the daemon exits silently (no stderr), and every subsequent command reports "daemon not running."
Do not restart the daemon once the user is authenticated, unless the user explicitly confirms a full re-auth is acceptable. Why: Restarting mid-session can invalidate the WhatsApp pairing and force the user to rescan the QR.
Never kill whatsapp processes with signals (pkill, killall, kill, os.kill, SIGTERM). Use screen -S whatsapp -X quit only, then sleep briefly, then start a new screen session.
Why: Sending SIGTERM to whatsapp serve propagates too broadly and crashes the entire container (exit code 143/144). Screen quit is always sufficient.
Before sending to an unknown phone number, save it first with add-contact.
Why: Sending to a raw JID with no saved contact row triggers the requireManualContact guard and blocks the send.
Right after first-pair auth, database is locked can occur transiently during history backfill.
Why: WhatsApp pushes up to 2 years of history; each conversation is persisted in a short transaction that can briefly exceed the 5s busy-timeout on large chats. If a write fails with "database is locked" within the first minute or two after authentication, wait 10-20 seconds and retry; do not treat it as a real failure. This does not occur on subsequent runs.
+ (e.g. +12025551234).@s.whatsapp.net, groups in @g.us. Only pass JIDs where a flag explicitly asks for one (e.g. --chat-id).~/.whatsapp/ (or ~/.whatsapp/{instance}/ for named instances).The WhatsApp CLI runs as a daemon via screen. One-shot commands (send, list, etc.) connect to the daemon over a Unix socket. This means:
cd ~/agent/skills/whatsapp/cli && CGO_ENABLED=1 go build -tags "fts5" -o ~/.local/bin/whatsapp .screen -S whatsapp -X quit
sleep 1
screen -dmS whatsapp whatsapp serve --notifications-dir ~/agent/notifications
Common mistake: rebuilding the binary and testing immediately without restarting the daemon. The CLI client just forwards commands to the daemon over the socket, so the daemon process must be running the new binary.
[How the user prefers to communicate with different contacts]