sanjay3290/whatsapp
Send and receive WhatsApp messages via the unofficial linked-device client pywhats (pip install pywhats) — pair with QR, send text/images, group chat, read receipts, presence/typing, and a long-running JSON event stream. Use when the user wants to script WhatsApp as a linked companion device (like WhatsApp Web), pair a device, send a WhatsApp from Python, or listen for inbound messages. Triggers: 'whatsapp', 'send whatsapp', 'pair whatsapp', 'pywhats', 'linked device', 'whatsapp web client'. NOT the official WhatsApp Business/Cloud API.
npx skills add https://github.com/sanjay3290/ai-skills --skill whatsapp
Drive a WhatsApp account as a linked companion device (like WhatsApp Web)
from async Python via pywhats (pre-alpha,
text/image only). This is an unofficial multi-device client — not the
official WhatsApp Business / Cloud API.
CLI entrypoint: scripts/wa.py (auto-bootstraps a managed venv on first run).
wa.py pair shows an ASCII QR; scan it inWhatsApp → Linked Devices. Credentials persist to
$PYWHATS_HOME/<session>.session (+ .signal.db).
15550001234 → [email protected];groups use [email protected].
wa.py listen prints one JSON object per event.Event handlers run inline on the receive loop. Awaiting send_*,
mark_read, get_group_info, download_media, etc. inside a handler
deadlocks the connection. Always asyncio.create_task(...). The listen
subcommand already does this for --read.
scripts/wa.py pair # one-time QR pair
scripts/wa.py send-text 15550001234 "hello" # 1:1 text
scripts/wa.py send-image 15550001234 photo.jpg --caption hi # 1:1 image
scripts/wa.py group-info [email protected] # group metadata JSON
scripts/wa.py group-send [email protected] "hi all" # group text
scripts/wa.py mark-read 15550001234 MSGID [--sender JID] # blue ticks
scripts/wa.py presence available # global presence
scripts/wa.py typing 15550001234 composing [--media audio] # typing indicator
scripts/wa.py listen --read --events message,receipt # JSONL event stream
scripts/wa.py --session work send-text 15550001234 "hi" # named session
| Command | Behavior |
|---------|----------|
| pair | Fresh link via ASCII QR; idempotent if already paired |
| send-text <to> <text> | Send 1:1 text; print message id |
| send-image <to> <path> [--caption C] | Send image (jpg/png/webp, ≤16MB); print id |
| group-info <gid> | Print group JSON (subject, owner, participants, …) |
| group-send <gid> <text> | Resolve members then send group text; print id |
| mark-read <chat> <ids...> | Blue-tick; --sender for groups |
| presence <available\|unavailable> | Global presence |
| typing <to> <composing\|paused> | Chat presence; optional --media audio |
| listen | Long-running JSON lines; --read, --events, --subscribe JID (required for presence events) |
Global: --session NAME (default default, or env PYWHATS_SESSION) —
goes before the subcommand: wa.py --session work pair.
$PYWHATS_HOME/ # default: ~/.pywhats
venv/ # managed Python + pywhats
default.session # --session default
default.session.signal.db
work.session # --session work
Override home with PYWHATS_HOME. Unpaired / logged-out sessions print a clear
message to re-run wa.py --session <name> pair.
If pair reports the device was logged out right after scanning, that is
WhatsApp device-churn reaping, not a failure of the skill — the dead session is
deleted automatically; follow the recovery steps it prints (remove linked
devices, wait 15–20 min, pair once).
references/api.md — every Client method, every event
payload, JID construction, and the download_media note.
Take sanjay3290/whatsapp from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference pip.
Without those the skill loads but fails at the first command.