# Agent bindings

> Route channel accounts and conversations to the right OpenClaw agent

- 网址：https://funcoding.ai/agents/openclaw/concepts/agent-bindings/
- 来源：OpenClaw 官方文档原文（英文），MIT 许可，同步于 2026-10-11
- 官方原文：https://docs.openclaw.ai/zh-CN/concepts/agent-bindings

---
When a message arrives on a channel, OpenClaw has to decide which agent answers it. An agent binding makes that choice for a slice of your traffic — each binding names an `agentId` and matches channel facts such as the account, peer, guild, team, or Discord roles, and the matched agent owns the resulting session.

Bindings only pick the agent. They do not create channel accounts and they do not grant access — a binding is consulted only after the channel has already accepted the message through its normal pairing, allowlist, and account rules.

## When to use a binding

With one configured agent, every conversation can share one workspace, one model policy, and one session boundary without bindings. Reach for bindings when you want a stable split, for example:

- one channel account per agent
- a support inbox routed to a support workspace
- one direct message or group routed to a specialist
- a guild, team, or Discord role routed differently from the rest of an account

Configure the channel account first, then bind it. A binding pointing at an account the channel never accepts does nothing.

## Route an account to an agent

This example uses explicit multi-agent ownership, routes the Discord account named `support` to its own agent and workspace, and sends other Discord accounts to `main`:

```json5
{
  agents: {
    ownership: "explicit",
    entries: {
      main: {
        workspace: "~/.openclaw/workspace",
      },
      support: {
        workspace: "~/.openclaw/workspace-support",
      },
    },
  },
  bindings: [
    {
      agentId: "support",
      comment: "Route the support bot account to the support agent",
      match: {
        channel: "discord",
        accountId: "support",
      },
    },
    {
      agentId: "main",
      match: {
        channel: "discord",
        accountId: "*",
      },
    },
  ],
}
```

Messages on the `support` account now resolve to `agentId: "support"`. The channel-wide binding routes other Discord accounts to `main`; add bindings for other channels that need routing.

When no binding matches, routing can use a caller-supplied owner, a configured or preserved default owner, or the sole configured agent. If none is available in a multi-agent setup, routing reports `AGENT_SELECTION_REQUIRED` and asks you to add a binding.

Older configurations may still contain one `default: true` marker. [Doctor migration](https://funcoding.ai/agents/openclaw/gateway/doctor/config-migrations/) carries that ownership into explicit bindings and service targets while preserving existing explicit choices. The marker cannot be combined with `agents.ownership: "explicit"`.

Valid binding changes apply automatically under the default `hybrid` [reload mode](https://funcoding.ai/agents/openclaw/gateway/configuration/hot-reload/). If `gateway.reload.mode` is `off`, restart the Gateway to apply them. Then verify the roster and channel accounts:

```bash
openclaw agents list --bindings
openclaw channels status --probe
```

## Match a specific conversation

Add `match.peer` when only one direct message, group, or channel should reach the specialized agent:

```json5
{
  bindings: [
    {
      agentId: "support",
      match: {
        channel: "discord",
        accountId: "default",
        peer: {
          kind: "channel",
          id: "123456789012345678",
        },
      },
    },
  ],
}
```

`peer.kind` accepts `direct`, `group`, or `channel`. Use the channel's canonical peer ID, not a display name.

## Match fields and precedence

Every binding requires `agentId` and `match.channel`. Additional fields control matching and session scope:

- `accountId`: one configured account. Omitting it matches only the channel's default account; `"*"` is an explicit channel-wide fallback.
- `peer`: a concrete or wildcard direct, group, or channel peer
- `guildId` and `teamId`: channel-specific group-space constraints
- `roles`: Discord role IDs, evaluated together with the guild constraint
- `session.dmScope`: an optional session-scoping override for matched direct messages
- `session.groupScope`: an optional `main` or `per-group` override for matched groups and channels

Precedence is by specificity: concrete conversation and group-space matches win over account and channel fallbacks. Within the same tier, the first binding in config order wins — put narrow rules before broad ones when they share a tier.

Top-level `bindings` also accepts `type: "acp"` entries for persistent ACP conversations. Those require a concrete `match.peer.id` and follow the ACP conversation identity contract instead of ordinary route precedence; see [ACP agents](https://funcoding.ai/agents/openclaw/tools/acp-agents/) when that is what you need.

## Common mistakes

### Omitting accountId to mean every account

An omitted `accountId` matches only the channel's default account. If you want a channel-wide fallback, say so explicitly with `accountId: "*"`.

### Binding to an unknown agent

Choose an `agentId` from `agents.entries`. Do not rely on a missing target falling back to another agent. If routing reports `AGENT_SELECTION_REQUIRED` for a binding, update its `agentId` to the intended configured agent.

### Treating bindings as access control

Bindings choose an agent for messages that were already admitted. Pairing, `dmPolicy`, group policy, and allowlists are separate controls — configure them independently.

## Related

- [Multi-agent routing](https://funcoding.ai/agents/openclaw/concepts/multi-agent/)
- [Agent configuration](https://funcoding.ai/agents/openclaw/gateway/config-agents/)
- [Channel routing](https://funcoding.ai/agents/openclaw/channels/channel-routing/)
