Skip to content

Broadcast Groups: Multi-Agent Responses for Team-Based Workflows #546

@pasogott

Description

@pasogott

Broadcast Groups: Multi-Agent Responses for Team-Based Workflows

Summary

Enable multiple agents to process and respond to the same message simultaneously, allowing teams of specialized agents with atomic tasks to work together in a single WhatsApp group using one phone number.

Problem

Currently, ClawdBot's routing uses first-match logic. When multiple bindings target the same peer (group/DM), only the first agent in the bindings array responds.

Example:

{
  "routing": {
    "bindings": [
      { "agentId": "alfred", "match": { "peer": { "id": "GROUP_A" } } },
      { "agentId": "baerbel", "match": { "peer": { "id": "GROUP_A" } } }
    ]
  }
}

Current behavior: Only alfred responds ❌
Desired behavior: Both alfred AND baerbel respond ✅

This limits the ability to:

  • Deploy specialized agents with different roles in the same group
  • Scale to hundreds of micro-agents on a single phone number
  • Create agent ensembles that collaborate on responses with atomic responsibilities

Proposed Solution

Add a new routing.broadcast config field that maps peer IDs to arrays of agent IDs:

{
  "routing": {
    "broadcast": {
      "strategy": "parallel",
      "120363403215116621@g.us": ["alfred", "baerbel", "assistant3"]
    }
  }
}

Result: All three agents process every message in this group, each with isolated sessions and contexts.

Use Cases

1. Specialized Agent Teams (Atomic Responsibilities)

Group: "Development Team"
Message: "Review this code: [snippet]"

Agents:
  - CodeFormatter → "Fixed indentation and added type hints"
  - SecurityScanner → "⚠️ SQL injection vulnerability in line 12"  
  - TestCoverage → "Missing tests for error cases"
  - DocsChecker → "Missing docstring for function process_data"

Each agent has one atomic task and responds independently.

2. Multi-Language Support

Group: "International Support"
Message: "How do I reset my password?"

Agents:
  - Agent_EN → Responds in English
  - Agent_DE → Responds in German
  - Agent_ES → Responds in Spanish

3. Quality Assurance Workflows

Group: "Customer Support"

Agents:
  - SupportAgent → Provides answer to customer
  - QAAgent → Reviews answer quality, only responds if issues found

4. Task Automation

Group: "Project Management"  
Message: "Meeting from 2-3pm about Q1 planning"

Agents:
  - TaskTracker → Creates task in database
  - TimeLogger → Logs meeting time
  - CalendarBot → Adds to calendar
  - ReportGenerator → Updates weekly report

Key Benefits

Minimal code changes - Only ~60 lines in core routing
Backward compatible - Existing configs work unchanged
Session isolation - Each agent has separate history, workspace, tools
Flexible processing - Parallel (default) or sequential strategies
Scalable - Enables 100s of specialized agents on one number
Atomic tasks - Each agent focuses on one specific responsibility
One phone number - All agents share the same WhatsApp account

Example Configuration

{
  "routing": {
    "defaultAgentId": "main",
    "broadcast": {
      "strategy": "parallel",
      "120363403215116621@g.us": ["code-formatter", "security-scanner", "docs-checker"],
      "+15555550123": ["support-en", "support-de", "support-es"]
    },
    "agents": {
      "code-formatter": {
        "name": "Code Formatter",
        "workspace": "/path/to/formatter",
        "sandbox": { "mode": "all" },
        "tools": { "allow": ["read", "write"] }
      },
      "security-scanner": {
        "name": "Security Scanner",
        "workspace": "/path/to/security",
        "sandbox": { "mode": "all" },
        "tools": { "allow": ["read", "bash"] }
      },
      "docs-checker": {
        "name": "Documentation Checker",
        "workspace": "/path/to/docs",
        "sandbox": { "mode": "all" },
        "tools": { "allow": ["read"] }
      }
    }
  }
}

Processing Strategies

Parallel (Default)

All agents process simultaneously:

{
  "routing": {
    "broadcast": {
      "strategy": "parallel",
      "GROUP_ID": ["agent1", "agent2", "agent3"]
    }
  }
}

Uses Promise.allSettled() - fastest, all agents work at once.

Sequential

Agents process one after another:

{
  "routing": {
    "broadcast": {
      "strategy": "sequential",
      "GROUP_ID": ["agent1", "agent2", "agent3"]
    }
  }
}

Agent2 waits for Agent1 to finish, etc.

Session Isolation

Each agent in a broadcast group maintains completely separate:

  • Session keys: agent:alfred:whatsapp:group:... vs agent:baerbel:whatsapp:group:...
  • Conversation history: Doesn't see other agents' messages
  • Workspace: Separate sandboxes if configured
  • Tool access: Different allow/deny lists
  • Memory: Separate IDENTITY.md, SOUL.md, etc.
  • Models: Can use different Claude versions (Opus vs Sonnet)

This allows each agent to have different personalities, tool access, and responsibilities.

Implementation Approach

Minimal Code Changes (~60 lines)

File: src/web/auto-reply.ts

After routing resolution, check for broadcast groups:

const route = resolveAgentRoute({ cfg, provider, accountId, peer });

// NEW: Check for broadcast group
const broadcastAgents = cfg.routing?.broadcast?.[peerId];
if (broadcastAgents && Array.isArray(broadcastAgents) && broadcastAgents.length > 0) {
  const strategy = cfg.routing?.broadcast?.strategy || "parallel";
  
  const processForAgent = (agentId: string) => {
    const agentRoute = {
      ...route,
      agentId: normalizeAgentId(agentId),
      sessionKey: buildAgentPeerSessionKey({ agentId, provider, peer }),
      mainSessionKey: buildAgentMainSessionKey({ agentId }),
    };
    return processMessage(msg, agentRoute).catch(err => {
      log.error(`Broadcast agent ${agentId} failed: ${err}`);
    });
  };
  
  if (strategy === "sequential") {
    for (const agentId of broadcastAgents) await processForAgent(agentId);
  } else {
    await Promise.allSettled(broadcastAgents.map(processForAgent));
  }
  return;
}

// Existing single-agent logic
return processMessage(msg, route);

Config Types: src/config/types.ts

export type RoutingConfig = {
  // ... existing fields ...
  broadcast?: {
    strategy?: "parallel" | "sequential";
    [peerId: string]: string[] | "parallel" | "sequential";
  };
};

Similar changes needed for:

  • Telegram (src/telegram/bot.ts)
  • Discord (src/discord/monitor.ts)
  • Slack (src/slack/monitor.ts)

Real-World Impact

This enables scaling to hundreds of specialized micro-agents on a single phone number:

Instead of: 1 general-purpose agent that does everything
Deploy:

  • 10 agents for code review (formatter, linter, security, docs, tests, performance, accessibility, i18n, best-practices, deprecations)
  • 5 agents for customer support (EN, DE, ES, FR, IT)
  • 8 agents for project management (tasks, time, calendar, reports, notifications, reminders, standup, retro)

Each agent:

  • Has one atomic responsibility
  • Can be developed independently
  • Can be tested in isolation
  • Can be enabled/disabled individually
  • Can use different models (cheap Haiku for simple tasks, Opus for complex)
  • Runs in its own sandbox

All on one WhatsApp number. 📱

Alternatives Considered

1. Multi-Agent Bindings

{
  "bindings": [{
    "agentId": "alfred",
    "multiAgent": ["baerbel"],
    "match": { ... }
  }]
}

Rejected: More invasive, requires changing routing core logic.

2. Virtual Account IDs

Create fake accountIds like cyberheld-alfred, cyberheld-baerbel.
Rejected: Doesn't work - incoming message has only ONE accountId from WhatsApp.

3. Agent-to-Agent via sessions_send

First agent manually triggers others using tool calls.
Rejected:

  • Not transparent (agent must know about others)
  • Extra latency (sequential tool calls)
  • Complex orchestration logic
  • Agent must decide who to call

Breaking Changes

None. This is purely additive:

  • New optional routing.broadcast config field
  • Existing configs continue to work unchanged
  • If broadcast is not configured, behavior is identical to current
  • Broadcast takes precedence over bindings (explicit configuration wins)

Testing Plan

Unit tests:

  • Config parsing for routing.broadcast
  • Agent list validation
  • Strategy selection (parallel vs sequential)

Integration tests:

  • Single broadcast group with 2 agents
  • Multiple broadcast groups
  • Mix of broadcast + regular bindings
  • Error handling (one agent fails, others continue)
  • Sequential vs parallel strategy

Manual testing:

  • Real WhatsApp group with 2+ agents
  • Verify separate session histories
  • Verify parallel responses
  • Performance with 5+ agents

Documentation

Would include:

  • docs/broadcast-groups.md - Complete feature guide
  • Configuration examples
  • Use cases with real-world examples
  • Best practices (keep agents focused, max 10 agents per group, etc.)
  • Troubleshooting guide
  • API reference

Future Enhancements

Potential follow-ups:

  • Shared context mode (agents see each other's responses)
  • Agent coordination (agents can signal each other)
  • Dynamic agent selection (choose agents based on message content)
  • Agent priorities (some respond before others)
  • Max agents per broadcast group limit
  • Implement for all providers (Telegram, Discord, Slack, Signal, iMessage)

Questions

  1. Should there be a hard limit on max agents per broadcast group? (e.g., 10)
  2. Should agents see each other's responses in the context? (Currently no - isolated sessions)
  3. Who sends the ACK reaction (👀) in groups? (Proposal: first agent in array)
  4. Should we add metrics/logging for broadcast performance?

Related

  • Multi-agent routing: docs/multi-agent-sandbox-tools.md
  • Session management: docs/sessions.md
  • Current routing code: src/routing/resolve-route.ts

Labels: enhancement, routing, multi-agent
Priority: Medium-High
Effort: ~2-3 days

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions