Greenapi Client Python
green-api/whatsapp-api-client-python
Write correct Python code with the official GREEN-API SDK whatsapp-api-client-python (package whatsappapiclientpython).
Adds a WhatsApp channel to a NanoClaw install through the native Baileys adapter, with QR code or pairing code login and a safety check about which phone number to use.
$ npx skills add nanocoai/nanoclaw --skill add-whatsapp -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install nanocoai/nanoclaw add-whatsapp --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/nanocoai/nanoclaw.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/add-whatsapp .claude/skills/add-whatsapp && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "add-whatsapp" agent skill from https://github.com/nanocoai/nanoclaw/tree/main/.claude/skills/add-whatsapp into .claude/skills/add-whatsapp/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-whatsapp", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/nanocoai/nanoclaw/tree/main/.claude/skills/add-whatsappType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add nanocoai/nanoclaw --skill add-whatsapp -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install nanocoai/nanoclaw add-whatsapp --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/nanocoai/nanoclaw.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/add-whatsapp .agents/skills/add-whatsapp && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "add-whatsapp" agent skill from https://github.com/nanocoai/nanoclaw/tree/main/.claude/skills/add-whatsapp into .agents/skills/add-whatsapp/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-whatsapp", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add nanocoai/nanoclaw --skill add-whatsapp -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install nanocoai/nanoclaw add-whatsapp --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/nanocoai/nanoclaw.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/add-whatsapp .cursor/skills/add-whatsapp && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "add-whatsapp" agent skill from https://github.com/nanocoai/nanoclaw/tree/main/.claude/skills/add-whatsapp into .cursor/skills/add-whatsapp/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-whatsapp", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/nanocoai/nanoclaw.git --path .claude/skills/add-whatsapp--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add nanocoai/nanoclaw --skill add-whatsapp -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install nanocoai/nanoclaw add-whatsapp --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/nanocoai/nanoclaw.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/add-whatsapp .gemini/skills/add-whatsapp && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "add-whatsapp" agent skill from https://github.com/nanocoai/nanoclaw/tree/main/.claude/skills/add-whatsapp into .gemini/skills/add-whatsapp/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-whatsapp", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install nanocoai/nanoclaw add-whatsappInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add nanocoai/nanoclaw --skill add-whatsapp -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/nanocoai/nanoclaw.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/add-whatsapp .github/skills/add-whatsapp && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "add-whatsapp" agent skill from https://github.com/nanocoai/nanoclaw/tree/main/.claude/skills/add-whatsapp into .github/skills/add-whatsapp/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-whatsapp", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add nanocoai/nanoclaw --skill add-whatsapp -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install nanocoai/nanoclaw add-whatsapp --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/nanocoai/nanoclaw.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/add-whatsapp .opencode/skills/add-whatsapp && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "add-whatsapp" agent skill from https://github.com/nanocoai/nanoclaw/tree/main/.claude/skills/add-whatsapp into .opencode/skills/add-whatsapp/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "add-whatsapp", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
add-whatsappAdds a WhatsApp channel to a NanoClaw install through the native Baileys adapter, with QR code or pairing code login and a safety check about which phone number to use.
This skill adds WhatsApp to NanoClaw, which does not ship its channels in the main branch. The agent copies the WhatsApp adapter and its registration test in from the `channels` branch. The adapter is a direct WhatsApp Web connection built on Baileys, with no Chat SDK bridge, and you sign in with either a QR code or a pairing code.
Before any install or login command, the agent runs a required number check. It asks whether NanoClaw will use a dedicated number (a spare SIM, eSIM or old phone) or a shared personal one. A shared number triggers a warning that WhatsApp could suspend or ban it, and the install continues only if you explicitly accept that risk. The steps are written as idempotent directives, so the skill can be re-run safely. The folder also holds a REMOVE.md, a fixtures file and a browser QR script.
4 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit af699e7. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships 1 file in scripts/ (TypeScript), which the agent can run.
Shell commands in SKILL.md call:
pnpmnodeFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use pnpm, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Add WhatsApp Channel loads about 6.3k tokens when it runs. Until then it costs about 38 tokens; SKILL.md has 2,524 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
was recorded — in particular make sure `.env` ends up with`ASSISTANT_HAS_OWN_NUMBER` in `.env`, read by the adapter itself at startup.Write the answer to `.env` **explicitly in both cases** (don't rely on thegrep -q '^ASSISTANT_HAS_OWN_NUMBER=' .env && sed -i.bak 's/^ASSISTANT_HAS_OWN_NUMBER=.*/ASSISTANT_HAS_OWN_NUMBER=true/'grep -q '^ASSISTANT_HAS_OWN_NUMBER=' .env && sed -i.bak 's/^ASSISTANT_HAS_OWN_NUMBER=.*/ASSISTANT_HAS_OWN_NUMBER=false/'Persist it to `.env` as `ASSISTANT_NAME`, replacing any existingtouch .env && grep -v '^ASSISTANT_NAME=' .env > .env.tmp; printf 'ASSISTANT_NAME=%s\n' '{{agent_name}}' >> .env.tmp && ms (`store/auth/creds.json` present) but `.env` has no `ASSISTANT_HAS_OWN_NUMBER` line, the install predates the explicit_OWN_NUMBER` / `ASSISTANT_NAME` land in `.env` — the adapter- `.env` says `ASSISTANT_HAS_OWN_NUMBER=false` (or unset) but strangers' DMs still raise approval cardsAutomated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.
The full file from nanocoai/nanoclaw at commit af699e7, republished under its MIT licence (© nanocoai). 2,524 words, ~6,317 tokens.
.claude/skills/add-whatsapp/SKILL.md (or your agent's skills folder). This skill also uses 3 other files; get the full folder from GitHub.Adds WhatsApp support via the native Baileys adapter — a direct WhatsApp Web
connection, no Chat SDK bridge. NanoClaw doesn't ship channels in trunk — this
skill copies the WhatsApp adapter in from the channels branch.
The mechanical steps under Apply carry nc: directive fences: an agent
reads the prose and applies them, and a parser can apply them deterministically
from the same document. Every directive is idempotent, so the whole skill is
safe to re-run; anything a parser can't apply falls back to the prose beside it.
Complete this check before running any install or authentication command. If the user already said they want to use their shared, personal, main, existing, or everyday WhatsApp number, treat it as a shared number and show the warning immediately. Do not ask the number-type question again.
Otherwise, ask which WhatsApp number NanoClaw will use:
Which WhatsApp number will NanoClaw use? `dedicated` (recommended) — a separate number used only for NanoClaw (spare SIM, eSIM, or old phone). `shared` — your existing everyday / personal WhatsApp number.If the answer is shared, show this warning — tell the user:
⚠️ Risk to your WhatsApp account
Connecting your shared or personal number could cause WhatsApp to temporarily suspend or permanently ban that number. You could lose access to the WhatsApp account, chats, and groups you rely on.
We strongly recommend using a separate, dedicated number for NanoClaw.
On your personal number, the agent lives only in your "You" / self-chat. Messages other people send you are ignored entirely — never read, never answered, never flagged for approval. Nobody else can talk to the agent.
If you want the agent reachable as its own contact, consider:
• Telegram — a bot takes ~2 minutes to set up
• a dedicated WhatsApp number — spare SIM, eSIM, or old phone
• /add-whatsapp-cloud — the official Meta Business APIThen confirm how to proceed. Do not continue with installation or authentication unless the user explicitly selects the second option:
How would you like to proceed? `dedicated` (recommended) — go back and use a dedicated number. `continue` — I understand the risk, continue with my shared number.Remember the effective mode for the rest of this workflow: it is shared only
when the user explicitly acknowledged the risk and continued; anyone who chose
a dedicated number — up front or at the warning — continues as a
dedicated-number install without seeing the warning again:
echo dedicatedecho sharedecho dedicatedFetch the channels branch and copy the WhatsApp adapter, its registration
test, and the whatsapp-formatting container skill (overwrite — the branch is
canonical). The whatsapp-auth setup step is maintained in trunk, so it is not
copied here:
src/channels/whatsapp.ts
src/channels/whatsapp-registration.test.ts
container/skills/whatsapp-formatting/SKILL.md
container/skills/whatsapp-formatting/instructions.mdThe whatsapp-formatting container skill is part of the channel payload: its
instructions.md is inlined as a section of every group's composed project
document (see src/project-doc-compose.ts), teaching agents WhatsApp's
formatting syntax. Trunk does not ship it — without this copy step
agents format WhatsApp messages with generic markdown that renders literally.
Append the self-registration import to the channel barrel (skipped if the line is already present). This one line is the skill's only reach-in into core:
import './whatsapp.js';Pinned to exact versions — the supply-chain policy rejects ranges and latest.
Baileys is the WhatsApp Web client; qrcode renders the device-link QR in the
terminal; pino is Baileys' logger:
@whiskeysockets/baileys@7.0.0-rc14
qrcode@1.5.4
@types/qrcode@1.5.6
pino@9.6.0Build first: it typechecks the adapter against core and proves the dependencies are installed. Then run the one integration test.
pnpm run buildpnpm exec vitest run src/channels/whatsapp-registration.test.tswhatsapp-registration.test.ts imports the real channel barrel and asserts the
registry contains whatsapp. It goes red if the import './whatsapp.js'; line
is deleted or drifts, if the barrel fails to evaluate, or if
@whiskeysockets/baileys isn't installed (the import throws) — so it also covers
the dependency from step 3. End-to-end delivery against a real WhatsApp number is
verified manually once the service runs.
WhatsApp uses linked-device authentication — no API key, just a one-time pairing
from your phone. The adapter is installed and registered, but its factory returns
null (and the channel stays dark) until store/auth/creds.json exists.
The number safety check above is still required even when credentials already
exist. If store/auth/creds.json exists, skip ahead to "Dedicated vs personal
number" after completing the safety check — the link step below reports the
already-linked number and moves on.
Pick how to link the device. qr shows a rotating QR you scan with your phone's
camera; pairing-code shows an 8-character code you type into WhatsApp (no camera
needed, but it needs your phone number):
How do you want to link WhatsApp? Type `qr` to scan a QR code in this terminal, or `pairing-code` to enter a code on your phone (no camera needed).The pairing-code method needs the number you're linking, the way WhatsApp expects
it — digits only, country code first, no +, spaces, or dashes (the QR method
skips this entirely):
Your WhatsApp phone number — digits only, country code first (e.g. 14155551234 for +1 415-555-1234).Point the user at the right screen before the code appears. For the QR method, tell the user:
Link WhatsApp by QR:
1. On your phone, open WhatsApp → Settings → Linked Devices → Link a Device.
2. A QR code will appear in this terminal below and refresh every ~20 seconds. Point your phone's camera at it to scan.For the pairing-code method, tell the user:
Link WhatsApp by pairing code:
1. On your phone, open WhatsApp → Settings → Linked Devices → Link a Device → tap "Link with phone number instead".
2. An 8-character code will appear in this terminal below. Enter it on your phone immediately — it expires in about 60 seconds.Now run the linked-device handshake. It streams the live QR (or the pairing-code
card) to this terminal and, on success, reports the linked WhatsApp number. Run
the command for the method chosen above — qr or pairing-code:
pnpm exec tsx setup/index.ts --step whatsapp-auth -- --method qrpnpm exec tsx setup/index.ts --step whatsapp-auth -- --method pairing-code --phone {{phone}}If the handshake fails (logged_out or a timeout), the code expired — clear
store/auth/ and run the step again for a fresh one. See Troubleshooting.
A successful link reports the number back as bot_phone. If it came back empty,
the device never confirmed (an expired QR or pairing code), so don't restart or
wire against a blank number — clear store/auth/ and re-run the link step first:
[ -n "{{bot_phone}}" ]On a dedicated number, the agent owns the linked line and you chat with it from your own, different number. Collect that number — it is required, and it is not the number you just linked. Tell the user:
The agent is signed in as +{{bot_phone}}.
Now, your personal number — the one you'll chat with the agent from. It'll show up as a normal two-way conversation with the agent's contact.Your personal number, where you'll chat from — digits only, country code first (e.g. 14155551234). Required — this must be YOUR number, not the agent's linked one.Chatting from the bot's own number IS the shared-number setup — if the number
given equals the linked number, stop and route through the same interception
screen as the up-front pick: show the account-risk warning from the number
safety check again and get explicit acknowledgement before treating this
install as shared (or collect a genuinely different personal number and stay
dedicated). If the install does become shared, correct the mode everywhere it
was recorded — in particular make sure .env ends up with
ASSISTANT_HAS_OWN_NUMBER=false, rewriting a true that may already have been
written; a stale true on a personal number makes the bot claim messages
addressed to the human:
[ "{{chat_phone}}" != "{{bot_phone}}" ]The adapter behaves fundamentally differently depending on whether the linked
number is the assistant's own or the operator's personal one. The switch is
ASSISTANT_HAS_OWN_NUMBER in .env, read by the adapter itself at startup.
Inference rule: absent (or anything other than true) means shared/personal
— the safe default, since misreading a personal number as dedicated makes the
bot claim messages addressed to the human.
ASSISTANT_HAS_OWN_NUMBER unset or not true) — DMs to this number and group @-tags of it address the human, not the bot. The adapter never emits a mention signal (mentions: 'never' in its declared channel defaults), so: no stranger DM ever auto-creates a messaging group or raises an admin approval card; group wirings default to a name pattern (\b<AgentName>\b) instead of platform mentions; auto-created chats default to unknown_sender_policy: 'strict'; outbound messages are prefixed with the assistant's name.ASSISTANT_HAS_OWN_NUMBER=true) — everything sent to the number is for the bot. DMs and group mentions carry a real mention signal (mentions: 'platform'), unknown senders escalate via request_approval approval cards, and card-approved groups wire with engage_mode: 'mention'. No name prefix on outbound.Use the mode selected in the required safety check. If information discovered later contradicts that selection, ask again before changing modes; switching to shared requires the same warning and explicit acknowledgement.
Write the answer to .env explicitly in both cases (don't rely on the
inference rule for new installs), replacing any existing
ASSISTANT_HAS_OWN_NUMBER line. Written in both modes so a re-run that
switches dedicated → shared doesn't leave a stale true behind:
grep -q '^ASSISTANT_HAS_OWN_NUMBER=' .env && sed -i.bak 's/^ASSISTANT_HAS_OWN_NUMBER=.*/ASSISTANT_HAS_OWN_NUMBER=true/' .env && rm -f .env.bak || echo 'ASSISTANT_HAS_OWN_NUMBER=true' >> .envgrep -q '^ASSISTANT_HAS_OWN_NUMBER=' .env && sed -i.bak 's/^ASSISTANT_HAS_OWN_NUMBER=.*/ASSISTANT_HAS_OWN_NUMBER=false/' .env && rm -f .env.bak || echo 'ASSISTANT_HAS_OWN_NUMBER=false' >> .envBoth modes: keep the adapter's outbound prefix / mention normalization in sync
with the chosen agent name (the adapter's config default is Andy otherwise).
Use the assistant's already-chosen name if one was configured; otherwise ask:
What should your assistant be called? (e.g. `Nano` — used as the outbound name prefix on a shared number, and for @-name engagement)Persist it to .env as ASSISTANT_NAME, replacing any existing
ASSISTANT_NAME line (the value is written literally — no pattern expansion):
touch .env && grep -v '^ASSISTANT_NAME=' .env > .env.tmp; printf 'ASSISTANT_NAME=%s\n' '{{agent_name}}' >> .env.tmp && mv .env.tmp .envIf WhatsApp auth already exists (store/auth/creds.json present) but .env has no ASSISTANT_HAS_OWN_NUMBER line, the install predates the explicit switch. Use the mode established by the required safety check and write it explicitly.
Suggest a default by comparing the authed number against the wired DM chat:
# The number this install is authenticated as
node -e "const c=JSON.parse(require('fs').readFileSync('store/auth/creds.json','utf-8'));console.log(c.me?.id?.split(':')[0])"
# The wired WhatsApp DM chats
pnpm exec tsx scripts/q.ts data/v2.db "SELECT mg.platform_id FROM messaging_groups mg JOIN messaging_group_agents mga ON mg.id=mga.messaging_group_id WHERE mg.channel_type='whatsapp' AND mg.is_group=0"If the wired DM's phone equals the authed number, the operator is talking to the bot in their own self-chat — that's a personal number: suggest Shared. If they differ, the operator messages the bot from a different number: suggest Dedicated. Confirm with the operator either way, then write the flag and restart the service.
Before the shared-number fix, group chats approved via the channel-registration card were wired engage_mode='pattern' with pattern . — respond-to-everything — because the card flow couldn't tell groups from DMs on non-threaded platforms. On a personal number this shows up as the bot answering every message in family/work groups after someone once tapped Connect on a spam-triggered card.
List the suspect wirings (host service running — ncl is socket-only):
ncl wirings list --engage-mode pattern --engage-pattern "." --jsonCross-reference against WhatsApp group chats (ncl messaging-groups list --channel-type whatsapp --is-group 1). For each wiring with pattern . on a WhatsApp group that is not the operator's deliberate always-on chat (e.g. their self-chat), offer:
ncl wirings update <wiring-id> --engage-mode pattern --engage-pattern '\b<AgentName>\b' (or --engage-mode mention on a dedicated number)ncl wirings delete <wiring-id>Stale approval cards from that era can also linger. Clear pending channel approvals for chats the operator doesn't want wired:
pnpm exec tsx scripts/q.ts data/v2.db "DELETE FROM pending_channel_approvals WHERE messaging_group_id IN (SELECT id FROM messaging_groups WHERE channel_type='whatsapp')"On a shared number the agent lives in your "You" / self-chat. Choose whether it responds to every message you write there, or only to messages addressed to it by name:
Respond to every self-chat message, or only messages starting with @<agent name>? `all` — every message (the self-chat becomes the agent's inbox). `mention` — only messages starting with @<agent name> (keep the self-chat for your own notes too).For mention, the engage pattern is @ plus the regex-escaped agent name,
anchored to the start of the message, with a trailing \b word-boundary guard.
\b only terminates a match after a word character — skip it for names ending
in punctuation, where it would never match:
node -e 'const n=process.argv[1];const e=n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");console.log(/\w$/.test(n)?"^@"+e+"\\b":"^@"+e)' '{{agent_name}}'engage_pattern is what the self-chat wiring uses: when wiring this channel
with scripts/init-first-agent.ts, pass it as --engage-pattern. Choosing
all leaves it unset — the wiring falls back to the respond-to-everything
default for a DM.
Restart NanoClaw so it loads the WhatsApp adapter and sees your credentials and
settings, and wait for its CLI socket before resolving. Restart only after
ASSISTANT_HAS_OWN_NUMBER / ASSISTANT_NAME land in .env — the adapter
computes its shared/dedicated mode and name once at module load, so restarting
earlier would leave it running with defaults:
bash setup/lib/restart.shResolve the conversation address as the WhatsApp JID for the number you chat from — the linked number itself for a shared account (your self-chat), or the personal number you gave for a dedicated one. Run the one matching the mode:
echo "{{bot_phone}}@s.whatsapp.net"echo "{{chat_phone}}@s.whatsapp.net"For WhatsApp, your owner handle is that same JID:
echo "{{platform_id}}"owner_handle and platform_id are what the owner-wiring step needs. The
greeting goes out over your WhatsApp chat as soon as the service reconnects with
the linked credentials.
For a shared number, set expectations — tell the user:
Self-chat mode: only your "You" / self-chat is connected. Messages other people send to your number are ignored — never seen, never asked about. The welcome message will land in your "You" chat on WhatsApp.
Wire a specific chat later with /manage-channels.If you're in the middle of /setup, return to the setup flow now. Otherwise wire
this channel with /init-first-agent (or /manage-channels) — in shared
mention mode, pass the engage pattern above via --engage-pattern.
whatsapp<phone>@s.whatsapp.net (e.g. 14155551234@s.whatsapp.net). Groups use <id>@g.us. Native adapter — the JID is the platform ID as-is, no whatsapp: prefix.node -e "const c=JSON.parse(require('fs').readFileSync('store/auth/creds.json','utf-8'));console.log(c.me?.id?.split(':')[0].split('@')[0]+'@s.whatsapp.net')". Groups are auto-discovered — check pnpm exec tsx scripts/q.ts data/v2.db "SELECT platform_id, name FROM messaging_groups WHERE channel_type='whatsapp' AND is_group=1".**bold**→*bold*, *italic*→_italic_, headings→bold, code blocks preservedask_user_question renders with /approve, /reject slash commandsNot supported (WhatsApp linked-device limitation): edit messages, delete messages.
Besides the in-terminal QR and the pairing code the Apply flow uses, this skill
ships a helper that renders the rotating QR as a PNG in your default browser —
handy when the terminal QR is too small to scan reliably. It spawns the same
whatsapp-auth step, parses each rotating QR from its WHATSAPP_AUTH_QR status
blocks, and serves the current one on a local HTTP server (default port 8765,
falls back to a free port):
pnpm exec tsx .claude/skills/add-whatsapp/scripts/wa-qr-browser.tsFlags: --clean wipes store/auth/ before spawning, --port N pins the port.
A browser window opens with a QR code. On your phone, open WhatsApp → Settings → Linked Devices → Link a Device, scan the QR, and the page shows "Authenticated!" when done.
On a headless host (no display server — no $DISPLAY/$WAYLAND_DISPLAY, not
macOS), the browser method can't open a window. Detect it and fall back to the
pairing-code method (no camera needed):
[[ -z "$DISPLAY" && -z "$WAYLAND_DISPLAY" && "$OSTYPE" != darwin* ]] && echo "IS_HEADLESS=true" || echo "IS_HEADLESS=false"If the assistant runs on a dedicated number (its own phone/SIM, not your personal WhatsApp), tell the adapter so it doesn't prefix outbound replies with its name:
ASSISTANT_HAS_OWN_NUMBER=trueThe Apply flow writes this key for you in both modes — true for a
dedicated number, false for a shared (personal) one — so a re-run that
switches modes never leaves a stale value behind. Absent (or anything other
than true) is read as shared/personal, the safe default.
Codes expire after ~60 seconds. The QR rotates automatically while the auth step is running; if the step exited, clear the auth state and re-run it:
rm -rf store/auth/ && pnpm exec tsx setup/index.ts --step whatsapp-auth -- --method qrFor pairing code, ensure digits only (no +), the phone has internet, and
WhatsApp is updated:
rm -rf store/auth/ && pnpm exec tsx setup/index.ts --step whatsapp-auth -- --method pairing-code --phone <phone>WhatsApp's pairing-code flow occasionally rejects valid codes with "Couldn't link device." This is a server-side rejection unrelated to the code itself. If you hit it more than once, switch to the QR method — it has a noticeably higher success rate.
Codes expire in ~60 seconds. Delete auth and retry:
rm -rf store/auth/ && pnpm exec tsx setup/index.ts --step whatsapp-auth -- --method pairing-code --phone <phone>Ensure: digits only (no +), phone has internet, WhatsApp is updated.
WhatsApp's pairing-code flow occasionally rejects valid codes with "Couldn't link device — An error happened. Please try again." This is a server-side rejection unrelated to the code itself; we've seen it happen twice in a row on fresh dedicated numbers. If you hit it more than once, switch to QR-browser auth — it has a noticeably higher success rate:
pnpm exec tsx .claude/skills/add-whatsapp/scripts/wa-qr-browser.ts --cleanWhatsApp sessions corrupted from rapid restarts. Clear sessions, then restart the service. Run from your NanoClaw project root:
source setup/lib/install-slug.sh
systemctl --user stop $(systemd_unit)
rm store/auth/session-*.json
systemctl --user start $(systemd_unit)test -f store/auth/creds.jsongrep "Connected to WhatsApp" logs/nanoclaw.log | tail -1pnpm exec tsx scripts/q.ts 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'"systemctl --user status "$(. setup/lib/install-slug.sh && systemd_unit)"Two instances connected with the same credentials. Ensure only one NanoClaw process is running.
The shared-number behavior (no stranger approval cards, name-pattern group defaults) lives in the adapter copy at src/channels/whatsapp.ts, installed from the channels branch — not in trunk. If you updated trunk via /update-nanoclaw but skipped the skill-update step, the old adapter copy neither reads ASSISTANT_HAS_OWN_NUMBER itself nor declares channel defaults, so trunk falls back to the legacy behavior: approval cards still fire on a personal number, and new wirings get the channel-blind defaults. Symptoms of the skew:
.env says ASSISTANT_HAS_OWN_NUMBER=false (or unset) but strangers' DMs still raise approval cardsncl wirings create on a WhatsApp group defaults to mention instead of a name patternFix: re-run /add-whatsapp (or /update-skills) to pull the current adapter from the channels branch, then restart the service. The reverse skew (new adapter, old trunk) can't happen — the adapter's defaults field is optional and old trunk ignores it.
© nanocoai, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 3 other files (scripts) in .claude/skills/add-whatsapp of nanocoai/nanoclaw.
Open the folder on GitHubat commit af699e7
Add WhatsApp Channel next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Add WhatsApp Channel this skillnanocoai/nanoclaw | 31k | — | ~6.3k | Automated safety check: Notes | MIT | |
| Greenapi Client Pythongreen-api/whatsapp-api-client-python | 209 | — | ~3.3k | Automated safety check: Pass | MIT | |
| Traul Message Searchdandaka/traul | 112 | — | ~3.9k | Automated safety check: Notes | AGPL-3.0 | |
| WhatsApp Messaging via KapsoEnriquefft/openclaw-kapso-whatsapp | 210 | — | ~188 | Automated safety check: Pass | MIT | |
| Communication Assistantappleweiping/WEIPING_WIKI | 119 | — | ~1.1k | Automated safety check: Pass | MIT | |
| SetupRich627/whatsapp-claude-plugin | 103 | — | ~1.4k | Automated safety check: Notes | Apache-2.0 |
green-api/whatsapp-api-client-python
Write correct Python code with the official GREEN-API SDK whatsapp-api-client-python (package whatsappapiclientpython).
dandaka/traul
Drives the traul CLI to sync, search and monitor messages from Slack, Telegram, Discord, Linear, Gmail, WhatsApp, Claude Code sessions and Markdown files.
Enriquefft/openclaw-kapso-whatsapp
Send WhatsApp messages via Kapso (outbound to third parties on owner instruction)
appleweiping/WEIPING_WIKI
Unified lazy-mode communication assistant for Vipin across WhatsApp, WeChat, QQ, Feishu/Lark, and email.
Rich627/whatsapp-claude-plugin
Interactive WhatsApp channel onboarding — guides through device linking, phone number config, and access control setup
yaalalabs/agent-kernel
Step-by-step guide for adding a new messaging platform integration to Agent Kernel.
nanocoai/nanoclaw
Installs or refreshes Iron Proxy and its Iron Control web console for NanoClaw, with a local Docker setup, database, credentials and a human approval bridge.
nanocoai/nanoclaw
Installs or refreshes OneCLI as the gateway provider for NanoClaw, copying the adapter files, registering the provider and running the setup script.
nanocoai/nanoclaw
Drives a web browser from the shell with the agent-browser CLI: open pages, read an element snapshot, click and fill by reference, grab text and screenshots.
nanocoai/nanoclaw
Installs the `dial` CLI and a credential in NanoClaw agent containers so chosen agents can send SMS, place AI voice calls and receive verification codes.
nanocoai/nanoclaw
Guides a conversational migration from an OpenClaw install to NanoClaw v2, carrying over identity, channel credentials, scheduled tasks and workspace files.
nanocoai/nanoclaw
Wires up an additional phone number onto an already-installed Dial channel, so one NanoClaw install answers SMS and AI voice calls on more than one line.
Works with
Categories
Adds a WhatsApp channel to a NanoClaw install through the native Baileys adapter, with QR code or pairing code login and a safety check about which phone number to use. This skill adds WhatsApp to NanoClaw, which does not ship its channels in the main branch. The agent copies the WhatsApp adapter and its registration test in from the `channels` branch.
Add WhatsApp Channel fits situations like: connecting a NanoClaw assistant to WhatsApp; linking a spare number to the agent by QR code or pairing code; re-running the WhatsApp setup after a failed or partial install.
Run `npx skills add nanocoai/nanoclaw --skill add-whatsapp -a claude-code`. Or copy the skill folder (.claude/skills/add-whatsapp in nanocoai/nanoclaw) into .claude/skills/add-whatsapp in your project. Claude Code loads it when a task matches its description.
Run `npx skills add nanocoai/nanoclaw --skill add-whatsapp -a codex`. Or copy the skill folder (.claude/skills/add-whatsapp in nanocoai/nanoclaw) into .agents/skills/add-whatsapp in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add nanocoai/nanoclaw --skill add-whatsapp -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/add-whatsapp, .gemini/skills/add-whatsapp, .github/skills/add-whatsapp and .opencode/skills/add-whatsapp in your project.
Going by SKILL.md and its folder, Add WhatsApp Channel needs TypeScript for the scripts in its folder and the command-line tools its instructions call (pnpm and node). Our summary lists: A NanoClaw installation; A WhatsApp number to link (a dedicated one is recommended); Access to the `channels` branch of the repository.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.
Add WhatsApp Channel is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 6.3k tokens (SKILL.md is roughly 25k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Add WhatsApp Channel: Greenapi Client Python (green-api/whatsapp-api-client-python, 209 stars), Traul Message Search (dandaka/traul, 112 stars), WhatsApp Messaging via Kapso (Enriquefft/openclaw-kapso-whatsapp, 210 stars) and Communication Assistant (appleweiping/WEIPING_WIKI, 119 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
nanocoai (a GitHub organization) maintains it in nanocoai/nanoclaw, which has 30,906 GitHub stars. The repository holds 59 skills in this directory. The repository was last updated on October 9, 2026.
Source: nanocoai/nanoclaw on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.