Configuration

Broadcast groups

Status: experimental

Overview

Agent group threads run multiple agents on the same inbound message, using the top-level broadcast config. Each agent runs in its own session. Channel-qualified entries can select participants by mention and allow a bounded number of follow-up rounds so agents can build on sibling replies.

Channel allowlists and group activation rules still apply. For qualified entries on Discord, Slack, and Telegram, an explicit mention of any configured participant can satisfy the room’s mention gate, even when that participant is not the ordinary routed agent. Legacy WhatsApp entries keep their existing admission behavior.

The live WhatsApp QA lane includes whatsapp-broadcast-group-fanout, which verifies that one mentioned group message can produce distinct visible replies from two configured agents.

Configuration

Agent group threads

Use a key in the form "<channel>:<peerId>", such as "discord:123456789", "slack:C0123", "telegram:-100123", or "whatsapp:1203@g.us". The value can be an agent ID array or a strict object:

json5
{  agents: {    ownership: "explicit",    entries: {      reviewer: {        name: "Reviewer",        groupChat: { mentionPatterns: ["@reviewer\\b"] },      },      writer: {        name: "Writer",        groupChat: { mentionPatterns: ["@writer\\b"] },      },    },  },  bindings: [{ agentId: "reviewer", match: { channel: "telegram" } }],  broadcast: {    "telegram:-100123": {      agents: ["reviewer", "writer"],      mentionGating: true,      maxRounds: 2,      maxTurns: 4,    },  },}

The ordinary channel route still needs an agent; the binding above selects Reviewer for admission before group dispatch. After the room is allowed by its channel config, send @reviewer @writer Review this draft. Both participants can answer the initial message and, within the budget, add something new in one follow-up round. Send @writer to select only Writer for the initial round.

Object field Default Contract
agents Required Configured agent IDs; at most 16 participants.
mentionGating true Select explicitly mentioned participants; if none match, select all.
maxRounds 1 Integer from 1 to 4, including the initial round.
maxTurns agents.length Integer from 1 to 32; total participant turns started for one inbound message.

Unknown object fields are rejected. Qualified arrays use the same defaults: "slack:C0123": ["reviewer", "writer"] runs one initial round with mention selection. A qualified WhatsApp key takes precedence over an unqualified key for the same peer. Unqualified object entries are not supported.

maxTurns counts agent runs started by the coordinator, including runs that pass or fail. Slots are reserved synchronously before parallel launch, so parallel participants cannot overspend the budget. If the budget is smaller than the eligible participant count, configured order determines which turns start. A turn can produce multiple platform messages through chunks, previews, or message-tool sends. Those deliveries are governed by the agent run and channel transport; maxTurns does not count, buffer, or cap physical messages.

Telegram, Discord, and Slack disable their shared preview and progress drafts for qualified group threads so concurrent participants do not overwrite each other's drafts. Final replies, block replies, and message-tool sends remain available.

The default turn budget covers one turn per configured agent. To let every agent run twice, set maxRounds: 2 and maxTurns to twice the participant count.

Mention selection

Selection uses only explicit @-style matches in the current inbound text, computed once for the participant set. A name in prose or a bare emoji does not select a participant. Mention patterns resolve from the agent’s groupChat.mentionPatterns, then messages.groupChat.mentionPatterns, then its identity-derived patterns. Give participants distinct patterns when you want to address them separately.

With mentionGating: true, a match selects only the matching participants for round 1; no matches selects all. With mentionGating: false, all participants are selected. This option does not turn off the channel’s requireMention policy, sender allowlists, or command authorization.

Bounded follow-up rounds

After a completed round, another round can run only within both maxRounds and maxTurns. Eligible participants are those that produced a final reply in the previous round or were addressed by name in a sibling’s final reply. Each participant's final text is limited to 4,000 characters in the digest; the combined sibling text is limited to 16,000 characters. Each receives an attributed, size-bounded digest of sibling finals from that round, with an instruction to reply only when adding something new and otherwise return NO_REPLY. Passing does not produce a visible final reply.

All participants passing ends the thread. Reaching either limit or cancellation also stops further turns. Each continuation has its own internal identity; it is not a replay of the physical inbound message. Sequential strategy changes launch order within a round; it does not turn that round into a pipeline where each participant sees earlier replies from the same round.

Budget state is in memory, scoped to the channel, account, conversation, thread, and root inbound message. It is not restart-resumable: a Gateway restart loses the active round and budget state. Ordinary inbound deduplication remains a separate protection.

Participant labels

When a qualified entry configures more than one participant, Discord, Slack, and Telegram replies begin with the participant name in bold. The configured count controls labeling, even if mention selection, the turn budget, or silence leaves only one responder. WhatsApp presentation remains unchanged.

Basic setup

Legacy single-pass setup uses unqualified WhatsApp peer IDs as keys and arrays of agent IDs as values:

  • group chats: group JID (e.g. 120363403215116621@g.us)
  • DMs: sender E.164 phone number (e.g. +15551234567)
json
{  "broadcast": {    "120363403215116621@g.us": ["alfred", "baerbel", "assistant3"]  }}

Result: when OpenClaw would reply in this chat, it runs all three agents.

Every listed agent ID must exist in the configured roster: config validation rejects unknown IDs in both arrays and objects. Deleting an agent prunes it from both forms.

Runtime membership uses the canonical agents.entries roster when present, including an empty roster. Legacy agents.list is used only when agents.entries is absent.

Processing strategy

broadcast.strategy sets how agents process the message:

Strategy Behavior
parallel (default) All agents process simultaneously; replies arrive in any order.
sequential Agents process in array order; each waits for the previous to finish.
json
{  "broadcast": {    "strategy": "sequential",    "120363403215116621@g.us": ["alfred", "baerbel"]  }}

Complete example

json
{  "agents": {    "entries": {      "code-reviewer": {        "default": true,        "name": "Code Reviewer",        "workspace": "/path/to/code-reviewer",        "sandbox": { "mode": "all" }      },      "security-auditor": {        "name": "Security Auditor",        "workspace": "/path/to/security-auditor",        "sandbox": { "mode": "all" }      },      "docs-generator": {        "name": "Documentation Generator",        "workspace": "/path/to/docs-generator",        "sandbox": { "mode": "all" }      }    }  },  "broadcast": {    "strategy": "parallel",    "120363403215116621@g.us": ["code-reviewer", "security-auditor", "docs-generator"]  }}

How it works

Message flow

  • Incoming message arrives

    A channel message arrives.

  • Route and admission

    OpenClaw applies channel allowlists, group activation rules, and configured ACP binding ownership.

  • Broadcast check

    If no configured ACP binding owns the route, OpenClaw checks the qualified channel/peer key, then the legacy peer key for WhatsApp.

  • If broadcast applies

    • Selected participants process the message within the round and turn limits.
    • Each agent has its own session key and isolated context.
    • Agents process in parallel (default) or sequentially.
    • WhatsApp audio attachments are transcribed once before fan-out, so agents share one transcript instead of making separate STT calls.
  • If broadcast does not apply

    OpenClaw dispatches the ordinary route or the configured ACP session route selected during routing.

  • Session isolation

    Each agent in a broadcast group maintains completely separate:

    • Session keys (agent:alfred:whatsapp:group:120363... vs agent:baerbel:whatsapp:group:120363...)
    • Conversation history (sibling replies are shared only through bounded follow-up digests)
    • Workspace (separate sandboxes if configured)
    • Tool access (different allow/deny lists)
    • Memory/context (separate IDENTITY.md, SOUL.md, etc.)

    On Discord, Slack, and Telegram, reply delivery and completion hooks use the responding participant's session, and local media resolves with that participant's media roots. This also applies to qualified entries with one participant, whose replies do not have a participant name label.

    On WhatsApp, one input is shared on purpose: the group context buffer (recent group messages used for context) is shared per peer, so all broadcast agents see the same context when triggered. It is cleared once after the fan-out completes.

    This allows each agent to have different personalities, models, skills, and tool access (for example read-only vs. read-write).

    Example: isolated sessions

    In group 120363403215116621@g.us with agents ["alfred", "baerbel"]:

    Alfred's context

    text
    Session: agent:alfred:whatsapp:group:120363403215116621@g.usHistory: [user message, alfred's previous responses]Workspace: ~/openclaw-alfred/Tools: read, write, exec

    Baerbel's context

    text
    Session: agent:baerbel:whatsapp:group:120363403215116621@g.usHistory: [user message, baerbel's previous responses]Workspace: ~/openclaw-baerbel/Tools: read only

    Use cases

    • Specialized agent teams: a dev group where code-reviewer, security-auditor, test-generator, and docs-checker each answer the same message from their own angle.
    • Multi-language support: one support chat with support-en, support-de, support-es responding in their languages.
    • Quality assurance: support-agent answers while qa-agent reviews and only responds when it finds issues.
    • Task automation: task-tracker, time-logger, and report-generator all consume the same status update.

    Best practices

    1. Keep agents focused

    Give each agent a single, clear responsibility (formatter, linter, tester) instead of one generic "dev-helper" agent.

    2. Use descriptive ids and names
    json
    {  "agents": {    "entries": {      "security-scanner": { "default": true, "name": "Security Scanner" },      "code-formatter": { "name": "Code Formatter" },      "test-generator": { "name": "Test Generator" }    }  }}
    3. Configure different tool access
    json
    {  "agents": {    "entries": {      "reviewer": {        "default": true,        "tools": { "allow": ["read", "exec"] }      },      "fixer": { "tools": { "allow": ["read", "write", "edit", "exec"] } }    }  }}

    reviewer is read-only. fixer can read and write.

    4. Monitor performance

    With many agents, prefer "strategy": "parallel" (default), keep broadcast groups to a handful of agents, and use faster models for simpler agents.

    5. Failures stay isolated

    Agents fail independently. One agent's error is logged (Broadcast agent <id> failed: ...) and does not block the others.

    Compatibility

    Providers

    Channel-qualified entries use the shared core dispatch path across channel plugins. Discord, Slack, and Telegram additionally support participant mention admission and name labels. Legacy unqualified entries apply only to WhatsApp (web channel).

    Routing

    Broadcast groups work alongside existing routing:

    json
    {  "bindings": [    {      "match": { "channel": "whatsapp", "peer": { "kind": "group", "id": "GROUP_A" } },      "agentId": "alfred"    }  ],  "broadcast": {    "GROUP_B": ["agent1", "agent2"]  }}
    • GROUP_A: only alfred responds (normal routing).
    • GROUP_B: agent1 AND agent2 respond (broadcast).

    Troubleshooting

    Agents not responding

    Check:

    1. Agent IDs exist in agents.entries (config validation rejects unknown ids).
    2. The qualified channel/peer key matches the room. Legacy WhatsApp keys use a group JID like 120363403215116621@g.us, or E.164 like +15551234567 for DMs.
    3. The message passed normal gating (mention/activation rules still apply).

    Debug:

    bash
    openclaw logs --follow | grep -i broadcast

    A successful fan-out logs Broadcasting message to <n> agents (<strategy>).

    Only one agent responding

    Check: explicit mentions may select one participant, maxTurns may allow only one run, or the others may pass. Also check whether the peer is only in ordinary route bindings or matches an exclusive configured ACP binding.

    Fix: add ordinary route-bound peers to the broadcast config, or remove/change the configured ACP binding if fan-out broadcast is desired.

    Performance issues

    If slow with many agents: reduce the number of agents per group, use lighter models, and check sandbox startup time.

    Examples

    Example 1: Code review team
    json
    {  "broadcast": {    "strategy": "parallel",    "120363403215116621@g.us": [      "code-formatter",      "security-scanner",      "test-coverage",      "docs-checker"    ]  },  "agents": {    "entries": {      "code-formatter": {        "default": true,        "workspace": "~/agents/formatter",        "tools": { "allow": ["read", "write"] }      },      "security-scanner": {        "workspace": "~/agents/security",        "tools": { "allow": ["read", "exec"] }      },      "test-coverage": {        "workspace": "~/agents/testing",        "tools": { "allow": ["read", "exec"] }      },      "docs-checker": { "workspace": "~/agents/docs", "tools": { "allow": ["read"] } }    }  }}

    One code snippet in the group can produce four perspectives: formatting fixes, a security finding, a coverage gap, and a docs nit.

    Example 2: Multi-language pipeline
    json
    {  "broadcast": {    "strategy": "sequential",    "+15555550123": ["detect-language", "translator-en", "translator-de"]  },  "agents": {    "entries": {      "detect-language": { "default": true, "workspace": "~/agents/lang-detect" },      "translator-en": { "workspace": "~/agents/translate-en" },      "translator-de": { "workspace": "~/agents/translate-de" }    }  }}

    API reference

    Config schema

    typescript
    type BroadcastGroupConfig = {  agents: string[];  mentionGating?: boolean;  maxRounds?: number;  maxTurns?: number;}; type BroadcastConfig = {  strategy?: "parallel" | "sequential";  [key: string]: string[] | BroadcastGroupConfig | "parallel" | "sequential" | undefined;};

    Fields

    strategy"parallel" | "sequential"default: "parallel"

    How to process eligible agents within each round. parallel launches reserved turns together; sequential runs them in configured order.

    [channel:peerId]string[] | BroadcastGroupConfig

    Channel-qualified peer ID. Arrays use the group-thread defaults; objects configure mention selection, rounds, and participant-turn budgets. At most 16 agents.

    [peerId]string[]

    Legacy WhatsApp group JID or E.164 phone number. Every listed agent processes one turn, with no internal follow-up rounds or participant selection.

    Limitations

    1. Shared context: follow-up digests contain bounded sibling finals, not full sibling sessions or tool histories.
    2. Message ordering: parallel responses may arrive in any order.
    3. Rate limits: participants share the channel account’s transport limits; one turn can produce several platform messages.
    4. Recovery: round and turn-budget state is in memory and cannot resume after a Gateway restart.
    5. Control UI: a dedicated team-thread session is not yet available. Each participant keeps its own session.
    Was this useful?
    On this page

    On this page