WhatsApp Channel

Calciforge embeds the zeroclawlabs::WhatsAppWebChannel transport directly. The WhatsApp Web session now lives inside the Calciforge process, so there is no ZeroClaw/OpenClaw webhook sidecar for this channel.

WhatsApp user  <->  WhatsApp Web session  <->  Calciforge  <->  agent

Prerequisites

Configure

[[channels]]
kind = "whatsapp"
enabled = true
whatsapp_session_path = "~/.config/calciforge/whatsapp/session.db"
allowed_numbers = ["+15555550001"]

# Optional pairing-code login. Use digits only.
# whatsapp_pair_phone = "15555550001"

# Optional personal-mode controls.
# whatsapp_mode = "personal"
# whatsapp_dm_policy = "allowlist"
# whatsapp_group_policy = "allowlist"
# whatsapp_mention_only = false
# whatsapp_self_chat_mode = false
# whatsapp_group_mention_patterns = ["@Calciforge", "calciforge"]

# Optional security scan for inbound messages.
# scan_messages = true

# Optional: force plain text choice rendering. Default "auto".
# The current embedded WhatsApp backend is text-first either way.
# ui_mode = "text"
[[identities]]
id = "operator"
display_name = "Operator"
role = "owner"
aliases = [
  { channel = "whatsapp", id = "+15555550001" },
]

Pair

Start Calciforge with the channel enabled. On first run, the embedded transport creates or opens the configured session database and starts WhatsApp Web pairing. Keep whatsapp_session_path on durable storage so restarts reuse the same linked session. If that file disappears, WhatsApp treats the castle door as a new device and you will need to pair again.

Verify

calciforge doctor
calciforge

Send !ping from an allowed WhatsApp number. Replies go to the transport reply_target, so direct chats and group chats reply to the original conversation.

Channel UI

The embedded WhatsApp Web channel is text/media-first today. Agent choices, model choices, session lists, and approval decisions all render through the shared choice model, but the embedded channel sends the text fallback because zeroclawlabs::Channel::SendMessage exposes text, recipient, threading, cancellation, and attachments, but not WhatsApp interactive messages. If a future WhatsApp Business API or provider-backed channel supports lists or reply buttons, Calciforge can render the same choices natively while preserving text fallback. Set ui_mode = "text" to keep this channel text-only for bridged or constrained clients.

Operators can use Telegram as the Calciforge control surface for buttons while continuing the main chat in WhatsApp. Active agent/model selections are keyed by Calciforge identity, so choices made through Telegram apply to the same operator’s WhatsApp route.

WhatsApp native selection target requiring a compatible backend
Native WhatsApp lists/buttons are a backend-dependent target, not the embedded channel behavior today.

Migration

The legacy webhook fields are rejected for kind = "whatsapp":

zeroclaw_endpoint = "http://127.0.0.1:18789"
zeroclaw_auth_token = "..."
webhook_listen = "0.0.0.0:18795"
webhook_path = "/webhooks/whatsapp"
webhook_secret = "..."

Move the session into Calciforge with whatsapp_session_path and remove the sidecar webhook settings.