Bot Loop Protection: Defaults and Channel Overrides
Learn how OpenClaw prevents bot-to-bot loops with pair loop protection. This page covers default settings and channel overrides for developers managing bot interactions.
Read this when
- Configuring bot-authored channel messages
- Tuning bot-to-bot loop protection
OpenClaw is capable of processing messages that originate from other bots, but only on channels where allowBots is supported. Once this feature is turned on, pair loop protection stops two different bot identities from endlessly responding to one another.
This safeguard is managed by the core inbound reply runner. Every channel that supports this feature translates its incoming events into a standard set of facts: the account or scope, conversation identifier, sender bot ID, and receiver bot ID. The core system tracks the participant pair in both directions (A to B and B to A are treated as the same pair), enforces a budget using a sliding window, and then puts the pair into a cooldown period once that budget has been used up.
Defaults
Pair loop protection is always in effect when a channel allows bot-generated messages to reach the dispatch layer. Built-in defaults:
| Key | Default | Meaning |
|---|---|---|
enabled | true | Guard is active for any channel that supports it. |
maxEventsPerWindow | 20 | Number of events a bot pair can exchange inside the window. |
windowSeconds | 60 | Duration of the sliding window. |
cooldownSeconds | 60 | How long suppression lasts after the pair exceeds the budget. |
Messages from humans, single-bot setups, self-message filtering, and bot replies that remain within the budget are all unaffected by this guard.
Configure shared defaults
Apply channels.defaults.botLoopProtection once to give every supporting channel the same default configuration. Individual channels may provide more specific overrides; Feishu intentionally relies solely on this shared baseline.
{
channels: {
defaults: {
botLoopProtection: {
maxEventsPerWindow: 20,
windowSeconds: 60,
cooldownSeconds: 60,
},
},
},
}
Only set enabled: false if your channel policy deliberately permits bot-to-bot conversations without any automatic suppression.
Override per channel, account, or room
Supporting channels layer their own settings over the shared default, key by key. Precedence, from narrowest to broadest:
channels.<channel>.<room-or-space>.botLoopProtection, when the channel supports per-conversation overrideschannels.<channel>.accounts.<account>.botLoopProtection, when the channel supports accountschannels.<channel>.botLoopProtection, when the channel supports top-level defaultschannels.defaults.botLoopProtection- built-in defaults
{
channels: {
defaults: {
botLoopProtection: {
maxEventsPerWindow: 20,
},
},
discord: {
botLoopProtection: {
maxEventsPerWindow: 8,
},
accounts: {
secondary: {
allowBots: true,
botLoopProtection: {
maxEventsPerWindow: 5,
cooldownSeconds: 90,
},
},
},
},
googlechat: {
allowBots: true,
groups: {
"spaces/AAAA": {
botLoopProtection: {
maxEventsPerWindow: 5,
},
},
},
},
matrix: {
allowBots: "mentions",
groups: {
"!roomid:example.org": {
botLoopProtection: {
maxEventsPerWindow: 5,
},
},
},
},
slack: {
allowBots: "mentions",
botLoopProtection: {
maxEventsPerWindow: 8,
},
},
},
}
Channel support
- Discord: uses native
author.botfacts, keyed by Discord account, channel, and bot pair. - Feishu: uses native
sender_type=botfacts for admitted bot-authored group messages, keyed by Feishu account, chat, and bot pair. Feishu only useschannels.defaults.botLoopProtection. - Google Chat: uses native
sender.type=BOTfacts for accepted bot-authored messages, keyed by account, space, and bot pair. - Matrix: uses configured Matrix bot accounts, keyed by Matrix account, room, and configured bot pair.
- Slack: uses native
bot_idfacts for accepted bot-authored messages, keyed by Slack account, channel, and bot pair.
Channels that cannot provide a reliable inbound bot identity continue to rely on their standard self-message and access-policy filters. They should not enable this guard until both participants in the bot pair can be identified.
Refer to the SDK runtime for details on implementing the plugin.