Skip to content

feat(whatsapp): opt-in outbound-to-any-number (outboundOpen)#2

Merged
pallaoro merged 4 commits into
whatsapp-ondemand-historyfrom
whatsapp-outbound-open
Jul 16, 2026
Merged

feat(whatsapp): opt-in outbound-to-any-number (outboundOpen)#2
pallaoro merged 4 commits into
whatsapp-ondemand-historyfrom
whatsapp-outbound-open

Conversation

@pallaoro

Copy link
Copy Markdown
Member

What

Adds an opt-in gate so a WhatsApp agent can send messages to any number, while dmPolicy/allowFrom still restrict who can trigger a reply (inbound stays gated). Default off.

Why

allowFrom is an inbound sender allowlist on every channel — Telegram, Discord, Google Chat, and the core default all let the agent send outbound to any target. WhatsApp is the only channel that also blocks outbound to non-allowlisted numbers (resolveWhatsAppOutboundTarget → "not listed in the configured WhatsApp allowFrom policy"), which breaks the common "send to anyone, only accept from a list" model. This restores it, opt-in.

How

  • resolveWhatsAppOutboundTarget gains an outboundPolicy param. "open" skips the allowFrom check for plain numbers; group/newsletter JIDs are always allowed (unchanged).
  • channel-outbound.ts reads the effective policy from plugins.entries.whatsapp.config.outboundOpen.

Why plugins.entries config, not channels.whatsapp.outboundPolicy

channels.whatsapp is validated with .strict() and rejects unknown keys. plugins.entries.<id>.config is a z.record(z.unknown()) passthrough, so the flag validates without a channel-schema change and is read from the resolved config in the outbound resolver.

Tests

  • resolve-outbound-target.test.ts: open allows a non-allowlisted number; allowlist/unset still blocks.
  • channel-outbound.test.ts: end-to-end via resolveTarget with a cfg — blocks by default, opens on outboundOpen: true, blocks on false.

pallaoro added 4 commits July 15, 2026 15:05
WhatsApp is the only channel whose outbound resolver blocks sends to
numbers not in `allowFrom`. Telegram, Discord, Google Chat and the core
default treat `allowFrom` as inbound-only and send to any target. This
adds an opt-in gate so the agent can message any number, while
`dmPolicy`/`allowFrom` still gate who can trigger a reply.

Gate: `plugins.entries.whatsapp.config.outboundOpen` (default false).
`channels.whatsapp` is validated with `.strict()` (unknown keys rejected),
but `plugins.entries.<id>.config` is a `z.record(z.unknown())` passthrough,
so the flag lives there and is read from the resolved config in the
outbound resolver.

`resolveWhatsAppOutboundTarget` gains an `outboundPolicy` param: "open"
skips the `allowFrom` check for plain numbers; group/newsletter JIDs are
always allowed. Tests cover the resolver and the end-to-end resolveTarget path.
… release notes

Regenerate clawnify-patches/whatsapp-clawnify-tools.patch against upstream
v2026.6.5 to include the opt-in outbound-to-any-number change
(plugins.entries.whatsapp.config.outboundOpen). Verified: applies cleanly
onto a fresh v2026.6.5 checkout, builds, and 36 tests pass.

Also make the GitHub Release name/body stop hardcoding a specific feature
list (it had gone stale — still said "RAM only, never persisted" after
persistence + on-demand history + profile tools shipped). The release now
points to the patch as the authoritative source of the current feature set.
…ns.entries config

The previous approach stored the flag under plugins.entries.whatsapp.config,
which the plugin's manifest configSchema (additionalProperties:false, pluginHooks
only) rejects — writing it made the gateway config invalid. Move it to a
first-class `channels.whatsapp.outboundOpen` (boolean, per-account override),
alongside dmPolicy/groupPolicy/allowFrom.

- Declare `outboundOpen` in the WhatsApp config schema (buildWhatsAppCommonShape)
  + type, and regenerate bundled-channel-config-metadata so the plugin's
  generated channelConfigs schema validates it.
- resolveTarget reads `channels.whatsapp.outboundOpen` (+ account override).
- Tests updated to the channel field.

Verified end to end on a live gateway: config validates, gateway restarts
healthy, no schema rejection.
@pallaoro
pallaoro merged commit 8454793 into whatsapp-ondemand-history Jul 16, 2026
3 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant