Files
openclaw/docs/channels/channel-routing.md
Sid 4ffe15c6b2 fix(telegram): warn when accounts.default is missing in multi-account setup (#32544)
Merged via squash.

Prepared head SHA: 7ebc3f65b2
Co-authored-by: Sid-Qin <201593046+Sid-Qin@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-03-03 03:27:19 -05:00

4.5 KiB
Raw Permalink Blame History

summary, read_when, title
summary read_when title
Routing rules per channel (WhatsApp, Telegram, Discord, Slack) and shared context
Changing channel routing or inbox behavior
Channel Routing

Channels & routing

OpenClaw routes replies back to the channel where a message came from. The model does not choose a channel; routing is deterministic and controlled by the host configuration.

Key terms

  • Channel: whatsapp, telegram, discord, slack, signal, imessage, webchat.
  • AccountId: perchannel account instance (when supported).
  • Optional channel default account: channels.<channel>.defaultAccount chooses which account is used when an outbound path does not specify accountId.
    • In multi-account setups, set an explicit default (defaultAccount or accounts.default) when two or more accounts are configured. Without it, fallback routing may pick the first normalized account ID.
  • AgentId: an isolated workspace + session store (“brain”).
  • SessionKey: the bucket key used to store context and control concurrency.

Session key shapes (examples)

Direct messages collapse to the agents main session:

  • agent:<agentId>:<mainKey> (default: agent:main:main)

Groups and channels remain isolated per channel:

  • Groups: agent:<agentId>:<channel>:group:<id>
  • Channels/rooms: agent:<agentId>:<channel>:channel:<id>

Threads:

  • Slack/Discord threads append :thread:<threadId> to the base key.
  • Telegram forum topics embed :topic:<topicId> in the group key.

Examples:

  • agent:main:telegram:group:-1001234567890:topic:42
  • agent:main:discord:channel:123456:thread:987654

Main DM route pinning

When session.dmScope is main, direct messages may share one main session. To prevent the sessions lastRoute from being overwritten by non-owner DMs, OpenClaw infers a pinned owner from allowFrom when all of these are true:

  • allowFrom has exactly one non-wildcard entry.
  • The entry can be normalized to a concrete sender ID for that channel.
  • The inbound DM sender does not match that pinned owner.

In that mismatch case, OpenClaw still records inbound session metadata, but it skips updating the main session lastRoute.

Routing rules (how an agent is chosen)

Routing picks one agent for each inbound message:

  1. Exact peer match (bindings with peer.kind + peer.id).
  2. Parent peer match (thread inheritance).
  3. Guild + roles match (Discord) via guildId + roles.
  4. Guild match (Discord) via guildId.
  5. Team match (Slack) via teamId.
  6. Account match (accountId on the channel).
  7. Channel match (any account on that channel, accountId: "*").
  8. Default agent (agents.list[].default, else first list entry, fallback to main).

When a binding includes multiple match fields (peer, guildId, teamId, roles), all provided fields must match for that binding to apply.

The matched agent determines which workspace and session store are used.

Broadcast groups (run multiple agents)

Broadcast groups let you run multiple agents for the same peer when OpenClaw would normally reply (for example: in WhatsApp groups, after mention/activation gating).

Config:

{
  broadcast: {
    strategy: "parallel",
    "120363403215116621@g.us": ["alfred", "baerbel"],
    "+15555550123": ["support", "logger"],
  },
}

See: Broadcast Groups.

Config overview

  • agents.list: named agent definitions (workspace, model, etc.).
  • bindings: map inbound channels/accounts/peers to agents.

Example:

{
  agents: {
    list: [{ id: "support", name: "Support", workspace: "~/.openclaw/workspace-support" }],
  },
  bindings: [
    { match: { channel: "slack", teamId: "T123" }, agentId: "support" },
    { match: { channel: "telegram", peer: { kind: "group", id: "-100123" } }, agentId: "support" },
  ],
}

Session storage

Session stores live under the state directory (default ~/.openclaw):

  • ~/.openclaw/agents/<agentId>/sessions/sessions.json
  • JSONL transcripts live alongside the store

You can override the store path via session.store and {agentId} templating.

WebChat behavior

WebChat attaches to the selected agent and defaults to the agents main session. Because of this, WebChat lets you see crosschannel context for that agent in one place.

Reply context

Inbound replies include:

  • ReplyToId, ReplyToBody, and ReplyToSender when available.
  • Quoted context is appended to Body as a [Replying to ...] block.

This is consistent across channels.