---
name: manage-whatsapp-config
description: Guide the user through viewing and editing WhatsApp settings — DM messaging policy, operational limits, and acknowledgement behaviour. Conversational, not a raw form dump.
---

# Manage WhatsApp Config

Invoked from `specialists:personal-assistant`.

Conversational editing of WhatsApp settings. Every field is presented with its description, current value, and what the default means — the user makes informed decisions without needing backend knowledge.

## When to activate

User asks to change, view, edit, or manage WhatsApp settings, policies, or limits. Also activate when the user asks about read receipts, message batching, media limits, or the DM policy. If the user asks how to make the agent respond in a group, see "Group posture" below — the answer is that it cannot, by design.

## Prerequisites

Call `whatsapp-status` first — if no WhatsApp account is connected, direct the user to the connect-whatsapp skill instead.

## Presenting settings

Call `whatsapp-config action: schema` to get field definitions with descriptions, and `whatsapp-config action: get-config` to get current values. Use the Description column from the schema output as the `description` field on each form field — do not improvise descriptions.

### Form fields

Present the settings to the operator as a numbered checklist in plain chat. For each field show the schema name, its label, the current value (from `get-config`) or the schema default, and the description from the schema output. For selects, list the available options. The operator replies with the changes they want, and the agent applies them via `whatsapp-config action: update-config`.

**Admin phones:**

Call `whatsapp-config action: list-admin-phones` and present the current list. Ask the operator which phones to add (`+44…` format) and which to remove. Apply each change via `whatsapp-config action: add-admin-phone` / `remove-admin-phone`. Confirm the resulting list to the operator after the writes land.

Each add/remove fires immediately — admin phones are managed per-action, independent of the form's batch submit.

Admin phones are authoritative only on the account that owns the WhatsApp paired socket (the house). Adding an admin phone always applies to that account; the write is refused on any other account, because a phone in a sub-account's admin list is never consulted. To route a person to a specific sub-account, bind them as an account manager with `add-account-manager` instead — do not read or edit a sub-account's admin list to answer "is this phone a manager?".

**Account managers:**

An account manager is a phone bound to a specific sub-account. Its WhatsApp messages spawn an admin session scoped to that sub-account's agent, not the house. Use this when a person who manages one client sub-account should reach that sub-account's agent over WhatsApp.

Call `whatsapp-config action: list-account-managers` to show the current phone-to-sub-account bindings. Bind a phone with `whatsapp-config action: add-account-manager`, passing `phone` (E.164) and `managesAccount` (the sub-account UUID). Clear a binding with `whatsapp-config action: remove-account-manager`, passing `phone`.

A phone is a house admin or a sub-account manager, never both. Binding a phone that is already on the admin list is refused, and vice versa. To move a house admin to a sub-account, remove it from the admin list first, then add it as an account manager.

Replies to an account manager go out over the house's paired WhatsApp device. That single paired line is the only WhatsApp transport, and it can deliver to any number: which account owns the socket never restricts which numbers a message can reach. Account-manager binding decides only which agent session answers an inbound or runs a scheduled turn, not deliverability.

To message a manager proactively or on a schedule, create a scheduled dispatch (`agentDispatch` on `schedule-event`) with the manager's phone as the `destination`. An account manager is a valid dispatch destination, and the turn's reply is delivered over the house's paired line. The one real limitation is that `whatsapp-send-admin` (the immediate proactive-push tool) accepts admin phones only, not managers — a narrow tool boundary, not a line-ownership problem.

Never tell the operator the line is "pointed at the wrong account", offer to point or flip the WhatsApp line at a sub-account, or describe an install-wide line flip: there is no such flip and no such restriction. Do not offer Telegram as a workaround here. Telegram is the right recommendation only for genuine Meta-policy limits (group sends, cold first-contact), never for reaching an account manager.

**Observe socket (account manager's WhatsApp):**

A sub-account can pair its own WhatsApp number as an observe socket. The agent reads that WhatsApp, but the phone's messages never spawn an agent turn. This is for an account manager's own phone: the agent watches the conversations and can reply into existing chats when told, but nothing on that phone drives the agent as instructions.

Turn an account into an observe socket with `whatsapp-config action: set-dispatch-inbound accountId: <the account> dispatchInbound: false`. Set `dispatchInbound: true` to restore normal agent dispatch. A sub-account may only set its own account; a house admin may set any. Confirm the result: `whatsapp-status` shows each account's mode as `dispatch` or `observe`.

This is different from an account manager binding. A binding routes a manager's messages sent to the house number into a sub-account session. An observe socket is the manager's own separate WhatsApp line, read in full, never dispatched. Use a binding when the manager messages the house number and should reach a sub-account agent; use an observe socket when the manager's own WhatsApp should be readable by the agent without driving it.

The agent's outbound on an observe socket is `whatsapp-reply`: reply into an existing conversation only, never a new chat. Cold first-contact stays unavailable, the same as every other WhatsApp surface.

**Public agent:**

Call `whatsapp-config action: list-public-agents` to get available agents, and `whatsapp-config action: get-public-agent` to get the current selection.

- `publicAgent` (`select`): label "Public agent for WhatsApp"
  - Options: one per agent from `list-public-agents` response — `value: slug`, `label: displayName`
  - `defaultValue`: the slug returned by `get-public-agent` (current selection)
  - `description`: from the schema's `.describe()` metadata for the `publicAgent` field
  - If `list-public-agents` returns an empty array, still include the field with no options and `description`: "No public agents available. Create one first using the public agent manager."

**Messaging policies:**

- `dmPolicy` (`select`): label "Who can message your agent (DMs)", options:
  - `open` — "Open — anyone can message"
  - `allowlist` — "Allowlist — only approved numbers"
  - `disabled` — "Disabled — no public DMs"

There is no group policy. Groups are observation-only — see "Group posture" below.

**Behaviour:**

- `sendReadReceipts` (`select`): label "Blue ticks (read receipts)", options:
  - `true` — "On — contacts see read receipts"
  - `false` — "Off — no read receipts"

**Operational limits:**

- `mediaMaxMb` (`number`): label "Media size limit (MB)"
- `textChunkLimit` (`number`): label "Message chunk limit (characters)"
- `debounceMs` (`number`): label "Message batching delay (ms)", defaultValue `2000`

### Submit

The form's `submitMessage` must map the field values back to `update-config` field names: `Save these WhatsApp settings: {{json}}` — where `{{json}}` produces the JSON object with field names as keys (e.g. `{ "dmPolicy": "open", "mediaMaxMb": 50, ... }`).

## Group posture

The agent is **observation-only in groups**: it sees and records every group message but never replies in a group. There is no per-group setting to turn responses on — the restriction is structural, not a toggle. `whatsapp-config action: list-groups` still lists the groups the connected phone is in, for reference.

This is a **Meta-policy constraint, not a Real Agent limitation.** WhatsApp penalises automated and business-style messaging sent from an unofficial linked device. Replying in groups and sending cold first-contact messages are both anti-automation triggers — they restricted a live operator account, which is why the agent is observe-only in groups and reply-only in DMs.

If the user wants an agent that actively messages in groups or initiates conversations, recommend **Telegram** instead. Telegram has no equivalent linked-device automation penalty, so the agent can send and respond freely there. Point them to the Telegram setup path at `platform/plugins/telegram/references/setup-guide.md`.

## Writing changes

After the user submits, write changes via `whatsapp-config action: "update-config"` with the `fields` parameter containing a JSON object of the changed fields. Each field is merged individually — unchanged fields are left untouched. Confirm what changed — name each setting that was modified and its new value.

## Language

Plain English goes in `label` — schema field names go in `name`. The `name` property is the machine key (must match the schema exactly); the `label` is what the user reads. Examples:

- `name: "dmPolicy"`, `label: "Who can message your agent (DMs)"`
- `name: "debounceMs"`, `label: "Message batching delay (ms)"`
- `name: "mediaMaxMb"`, `label: "Media size limit (MB)"`
- `name: "sendReadReceipts"`, `label: "Blue ticks (read receipts)"`

Group names (not JIDs) in all user-facing text.
