Add WhatsApp transport via openclaw/wacli + wp-admin pairing UI#6
Merged
Add WhatsApp transport via openclaw/wacli + wp-admin pairing UI#6
Conversation
Connects openclaWP to WhatsApp by treating an inbound webhook from openclaw/wacli (whatsmeow-based linked-device CLI) as the entry point into the openclawp/chat ability. Each incoming message is HMAC-verified, forwarded to a configured agent, and the reply is posted back through wacli send. ## What's in it - OpenclaWP_Wacli_Channel — extends AgentsAPI\AI\Channels\WP_Agent_Channel (introduced in agents-api PR #99). The base class owns the agent loop; this concrete channel only fills in wacli-specific I/O (payload parsing, allowlist, loop-prevention via `silent_skip`, `wacli send text` shell-out). - OpenclaWP_Wacli_Transport — REST endpoint `/openclawp/v1/wacli/webhook` that verifies the HMAC signature wacli signs each event with, then hands the payload to the channel. Also owns the proc_open to wacli for outbound replies. - OpenclaWP_Wacli_Process — long-running wacli process manager. Spawns `wacli auth --follow --qr-format text --events` detached via nohup, reads the NDJSON event stream, exposes a state machine to wp-admin for the QR pairing flow. - OpenclaWP_Wacli_Admin + assets — wp-admin → openclaWP → WhatsApp page that pairs the device by rendering a live QR in the browser. Polls `/openclawp/v1/wacli/state` every 2s, refreshes the QR as wacli rotates it, switches to "Connected" once paired. Settings card under the state widget for agent slug, allowed-chat JID list, and an optional binary path override. - WP-CLI helpers: `wp openclawp wacli setup` prints the wacli sync command to copy (with the auto-generated HMAC secret); `wp openclawp wacli ping <jid> <text>` exercises the outbound path without a webhook in the loop. - 23 PHPUnit tests covering HMAC verification (8), settings normalizer (4), and the wacli process state machine (6). Plus 5 more for misc internals. ## Setup ``` brew install steipete/tap/wacli wp option update openclawp_wacli_agent <slug-of-registered-agent> ``` Then **wp-admin → openclaWP → WhatsApp → Connect WhatsApp**, scan the QR. Configure the allowlist + agent in the same page. ## Architecture The channel is the portable piece — anyone can write a Telegram or Email or Slack channel by extending the same base class, and the agent loop behaves identically. See agents-api PR #99 for the base class contract. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This was referenced May 7, 2026
Merged
4 tasks
Per the agents-api canonical contract landed in agents-api PR #105, register openclaWP as the runtime that handles the stable `agents/chat` ability. Channels and bridges that target `agents/chat` get routed through openclaWP's existing `openclawp/chat` runner — no caller has to know which plugin owns the runtime. The mapping is intentionally a thin pass-through: the canonical input (`agent`, `message`, `session_id`, `attachments`, `client_context`) is a superset of what `openclawp/chat` accepts, and the ability already ignores fields it doesn't read. When the runner starts using attachments / client_context in a future change, no caller has to update. `openclawp/chat` stays registered for backwards compatibility — direct callers and the existing block continue working. Wacli webhook surface widens its short-lived permission grant to also cover `agents_chat_permission`, since channels now reach the runner through the canonical dispatcher. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Automattic/agents-api#105 merged, bringing WP_Agent_Channel and the agents/chat dispatcher into main. The branch alias is no longer needed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Connects openclaWP to WhatsApp by treating an inbound webhook from
openclaw/wacli(whatsmeow-based linked-device CLI,brew install steipete/tap/wacli) as the entry point into theopenclawp/chatability. Each incoming message is HMAC-verified, forwarded to a configured agent, and the reply is posted back throughwacli send.This is the first public consumer of
AgentsAPI\AI\Channels\WP_Agent_Channel. The portable agent-loop plumbing (validate, extract, dispatch, deliver, lifecycle hooks, session continuity) lives in agents-api; this PR only fills in wacli-specific I/O.What's in it
Channel + transport
OpenclaWP_Wacli_ChannelextendsWP_Agent_Channel. The base class owns the agent loop; this concrete channel does payload parsing, allowlist,silent_skipfor own-bot echoes / disallowed chats, and thewacli send textshell-out.OpenclaWP_Wacli_Transport— REST endpoint/openclawp/v1/wacli/webhook. Verifies theX-Wacli-Signature: sha256=…HMAC, parses the wacli payload, constructs the channel, scopes a single-requestadd_filter('openclawp_chat_ability_permission', '__return_true')while running the chat ability, and returns 200/4xx/5xx based on the channel result.Pair from wp-admin
OpenclaWP_Wacli_Process— process manager that spawnswacli auth --follow --qr-format text --eventsdetached vianohup, reads the NDJSON event stream, exposes a state machine to wp-admin.OpenclaWP_Wacli_Admin+assets/wacli-admin.{js,css}+assets/qrcode.min.js— wp-admin → openclaWP → WhatsApp page. Polls/openclawp/v1/wacli/stateevery 2s, renders a live QR in the browser as wacli rotates it, switches to a "Connected ✅" panel once paired. Settings card below for target agent (dropdown of registered agents), allowed chats (JID textarea), and wacli binary (auto-detected, overridable).OpenclaWP_Wacli_Rest— admin REST routes (manage_options):GET /wacli/state,POST /wacli/connect,POST /wacli/disconnect,GET|POST /wacli/settings.WP-CLI
wp openclawp wacli setup [--rotate]— prints thewacli sync --follow --webhook … --webhook-secret …command with an auto-generated HMAC secret.wp openclawp wacli ping <jid> <text>— exercise the outbound path without a webhook in the loop.Setup
Then wp-admin → openclaWP → WhatsApp → Connect WhatsApp, scan the QR with WhatsApp → Settings → Linked Devices. Configure the allowlist and agent in the Settings card on the same page.
The webhook URL and HMAC secret are exposed via
wp openclawp wacli setupfor users who'd rather configure wacli from the CLI.Loop prevention + safety
from_me: trueare dropped viasilent_skip, so the agent never reacts to its own outgoing replies appearing on the next sync event.openclawp_wacli_allowed_jidsis a comma/newline-separated allowlist of chat JIDs. Empty allowlist = allow every inbound chat (called out as risky in the UI).error_loginstead of replying to the user's WhatsApp — the agent's failures don't bleed into the personal thread.Test plan
WacliTransportTest, 7 cases), settings normalizer (WacliSettingsTest, 4 cases), wacli process state machine (WacliProcessTest, 6 cases), plus 6 misc.POST /wacli/webhookwith valid HMAC →200 {ok: true, note: "replied"}.POSTwith bad signature →401 {error: "bad_signature"}.POSTwithfrom_me: true→200 {ok: true, note: "self_message"}(silent_skip path).Dependency
composer.jsonpinned toautomattic/agents-api: dev-add/agent-channel as dev-mainso the PR can be installed against the open agents-api PR. Once Automattic/agents-api#99 merges, this can flip back todev-main.Architecture
The channel is the portable piece — anyone can write a Telegram, Email, or Slack channel by extending
WP_Agent_Channel, and the agent loop behaves identically. See Automattic/agents-api#99 for the base class contract.🤖 Generated with Claude Code