Flat vector illustration of two bot agents with circular message arrows blocked by a shield inside a self-hosted server gateway

OpenClaw Bot Loop Protection: Stop Bot-to-Bot Reply Storms

OpenClaw bot loop protection exists for the moment every agent operator eventually fears: one bot answers another bot, the second bot answers back, and suddenly a useful automation lane turns into a reply storm.

This is not a theoretical problem in self-hosted agent systems. Slack, Discord, Google Chat, Feishu, Matrix, and similar channels all make it normal for software identities to speak in the same room as people. That is useful. It also means an agent can accidentally treat another automation as a fresh human request, answer it, and keep the cycle alive.

OpenClaw does not solve that by banning bot-authored messages everywhere. That would be too blunt. Some teams want bots to talk to agents on purpose: a CI bot can ask for a deployment summary, a support bot can hand off a ticket, or one agent can coordinate with another in a controlled channel. OpenClaw’s answer is narrower and better: admit bot messages only where policy allows them, then put a sliding-window budget around each pair of bot identities.

What OpenClaw bot loop protection actually guards

The feature guards rapid exchanges between two bot identities after a channel has already admitted bot-authored traffic. The docs describe it as pair loop protection. That wording matters. It is not a general spam detector, not a content classifier, and not a replacement for access policy.

OpenClaw channels that support allowBots can let bot-authored messages reach dispatch. Discord and Slack default to accepting bot messages under the usual mention and access rules. An explicit allowBots: false still shuts that down. Bot messages may also remain visible as conversation context even when they do not start a turn.

Once a bot-authored message is allowed to trigger a turn, the pair guard asks a smaller question: is this same bot pair exchanging too many events too quickly?

If the answer is no, the message can continue through the normal route. If the answer is yes, OpenClaw suppresses that pair for a cooldown period. Human-authored messages are not affected. Single-bot deployments are not affected. Self-message filtering still has its own job. Replies that stay under the budget continue normally.

The default limits and what they mean

OpenClaw ships with pair loop protection enabled for channels that support it. The built-in defaults are deliberately plain:

Key Default Meaning
enabled true The guard is active for supporting channels.
maxEventsPerWindow 20 A bot pair can exchange 20 events inside the active window.
windowSeconds 60 The sliding window is 60 seconds long.
cooldownSeconds 60 The pair is suppressed for 60 seconds after exceeding the budget.

Read those defaults as a safety budget, not as a performance target. A bot pair that sends 19 events in a minute is technically under the limit, but that may still be too chatty for a normal team channel. A busy automation room may need a different budget. The default is a sane baseline for avoiding runaway loops without blocking every useful bot-to-agent exchange.

The guard is also a sliding-window rate check. A slow exchange can continue. A burst is what gets stopped. That distinction is useful when you are debugging. If two bots trade one or two messages every few minutes, loop protection should not fire. If they bounce messages rapidly, it should.

How the pair guard counts bot traffic

OpenClaw enforces the guard in the core inbound reply runner. Each supporting channel maps the platform event into generic facts:

  • account or scope
  • conversation id
  • sender bot id
  • receiver bot id

Core then tracks the participant pair in both directions. A-to-B and B-to-A count as the same pair. That is exactly what you want, because a loop usually alternates: one bot says something, the other responds, the first responds again.

This is also why reliable bot identity matters. Discord exposes bot identity through native author facts such as author.bot; the Discord developer docs also show a bot boolean on user objects. Slack exposes accepted bot-authored messages with bot_id. Feishu, Google Chat, and Matrix have their own identity paths. A channel that cannot identify both sides of the bot pair should not pretend it can run the same guard.

The practical operator takeaway is simple: if loop protection does not seem to fire, do not start by guessing better thresholds. First confirm the channel can map bot identity for both participants. If the identity facts are missing, the numbers are not the real problem.

Configure shared defaults first

The cleanest setup is to define one shared baseline at channels.defaults.botLoopProtection. That gives every supporting channel the same starting point:

{
  channels: {
    defaults: {
      botLoopProtection: {
        maxEventsPerWindow: 20,
        windowSeconds: 60,
        cooldownSeconds: 60,
      },
    },
  },
}

Most installations should begin here and leave enabled alone. Turning the guard off globally means every bot-admitted channel now depends on channel policy, prompt discipline, and luck to avoid a loop. That is a lot of trust to place in rooms that may include several automations.

A better pattern is this: keep the shared default conservative, then use narrower overrides only where you have a clear reason. A noisy staging channel might need a stricter limit. A private automation room with two known bots may need a slightly higher budget. The important thing is that the exception remains visible in config.

Override limits by channel, account, or room

Supporting channels layer their bot loop protection config over the shared default key by key. OpenClaw resolves the narrowest matching setting first. The docs list the precedence like this:

  1. channels.<channel>.<room-or-space>.botLoopProtection, where room-level overrides exist
  2. channels.<channel>.accounts.<account>.botLoopProtection, where account-level overrides exist
  3. channels.<channel>.botLoopProtection
  4. channels.defaults.botLoopProtection
  5. built-in defaults

That lets you tune the blast radius. A stricter Slack channel does not need to make Discord stricter. A secondary Discord account can have a shorter budget than the main account. A Google Chat space can be more locked down than the rest of Google Chat.

{
  channels: {
    defaults: {
      botLoopProtection: {
        maxEventsPerWindow: 20,
      },
    },
    discord: {
      botLoopProtection: {
        maxEventsPerWindow: 8,
      },
      accounts: {
        secondary: {
          allowBots: true,
          botLoopProtection: {
            maxEventsPerWindow: 5,
            cooldownSeconds: 90,
          },
        },
      },
    },
    slack: {
      allowBots: "mentions",
      botLoopProtection: {
        maxEventsPerWindow: 8,
      },
    },
  },
}

Notice the relationship between allowBots and the guard. allowBots decides whether bot-authored traffic can trigger turns. botLoopProtection decides how much rapid bot-pair traffic is allowed after admission. You usually need to reason about both.

Channel identity support

OpenClaw’s current channel support is specific, not magical. The docs call out these identity mappings:

  • Discord: native author.bot facts, keyed by Discord account, channel, and bot pair.
  • Feishu: native sender_type=bot facts for admitted bot-authored group messages, keyed by Feishu account, chat, and bot pair.
  • Google Chat: native sender.type=BOT facts for accepted bot-authored messages, keyed by account, space, and bot pair.
  • Matrix: configured Matrix bot accounts, keyed by Matrix account, room, and configured bot pair.
  • Slack: native bot_id facts for accepted bot-authored messages, keyed by Slack account, channel, and bot pair.

Feishu has one extra wrinkle: it intentionally uses only the shared baseline at channels.defaults.botLoopProtection. Do not build a Feishu setup that assumes narrower channel overrides will work unless the channel docs change.

Channels without reliable inbound bot identity continue to use their normal self-message and access-policy filters. That is the right tradeoff. A weak pair guard is worse than no pair guard because it gives operators false confidence.

Broadcast group rounds are a different budget

OpenClaw also has agent group threads through broadcast groups, and those use a separate coordinator budget. Do not mix the two in your head.

Pair loop protection watches bot-authored messages arriving from the platform. Broadcast group budgets govern internal participant turns that start from one inbound message. The bot loop protection docs note that qualified broadcast entries allow at most 4 rounds and 32 participant turns. maxRounds includes the initial round. maxTurns counts agent runs started, with slots reserved before parallel launch.

A broadcast participant turn may produce several physical messages through chunking, previews, or message-tool sends. The coordinator does not count those physical messages. Its budget is scoped in memory to the channel, account, conversation, thread, and root message, and it does not resume after a Gateway restart.

That separation is healthy. Internal multi-agent coordination needs a round-and-turn budget. External bot-to-bot transport traffic needs a pair budget. They protect different failure modes.

When to lower, raise, or disable the guard

Lower the budget when a room is noisy, public-ish, or full of automations with unclear ownership. For example, a Slack channel where CI, monitoring, support triage, and an AI agent all speak should probably have a smaller per-pair budget than a private testing room.

Raise the budget only when you can describe the intended exchange. “Our deployment bot sends status updates and the agent replies with a short analysis during a release drill” is a reason. “The default feels low” is not much of a reason.

Disable the guard only when your channel policy intentionally allows unrestricted bot-to-bot conversations and you are willing to own the consequences. Even then, prefer a narrow override. Turning it off globally is the kind of config that looks harmless until a second automation joins the room.

There is one more boring but useful habit: keep bot admission narrow. If the channel does not need bot-authored messages to trigger turns, set allowBots: false or leave bot admission restricted. Loop protection is a seatbelt, not a reason to drive faster.

Troubleshooting bot loops

When a bot loop slips through, work from admission to identity to budget. Jumping straight to threshold tuning wastes time.

  1. Confirm whether the channel allows bot-authored messages to trigger turns.
  2. Check whether the triggering message was bot-authored or only bot-visible context.
  3. Confirm the channel exposes sender and receiver bot identities.
  4. Check the effective botLoopProtection config at the room, account, channel, and default levels.
  5. Look for a pair exceeding maxEventsPerWindow inside windowSeconds.
  6. Check whether the pair is inside cooldownSeconds.
  7. Separate platform bot loops from broadcast group follow-up rounds.

If the loop involves webhook infrastructure, also check delivery behavior. GitHub’s webhook guide, for example, tells receivers to send a 2XX response within 10 seconds or the delivery is treated as failed. That kind of retry behavior can look like duplicated automation traffic if your handler does slow work before acknowledging. It is not the same as an OpenClaw bot pair loop, but it can make the symptom messier.

For Discord, remember that bot identity is a first-class user distinction. For Slack, check bot IDs and channel access. For Matrix, confirm the configured bot accounts. For Feishu, verify the shared default because that is the supported config path.

A sane production stance

The safest production stance is boring: admit bot messages only where they are useful, keep pair loop protection enabled, start with shared defaults, and make exceptions close to the channel that needs them.

That gives you enough room for real workflows without letting two automations turn your agent into an amplifier. It also leaves an audit trail. When a room has a different budget, the config tells you why that room is special.

The mental model I like is a turnstile with a counter. Access policy decides who can walk up to the turnstile. Bot loop protection counts whether the same two bot badges keep spinning it too fast. Both pieces matter.

FAQ

What is OpenClaw bot loop protection?

It is a sliding-window guard that limits rapid exchanges between two admitted bot identities on supported channels. When the pair exceeds its budget, OpenClaw suppresses that pair during a cooldown.

Does bot loop protection block human messages?

No. The docs state that the guard does not affect human-authored messages, single-bot deployments, self-message filtering, or bot replies that stay under the configured budget.

What are the default limits?

The built-in defaults are enabled: true, maxEventsPerWindow: 20, windowSeconds: 60, and cooldownSeconds: 60.

Should I turn off bot loop protection for trusted rooms?

Usually no. If a trusted room needs a different behavior, use a narrow room, account, or channel override first. Disabling the guard should be rare and deliberate.

Why did a bot message appear in context but not start a turn?

OpenClaw can keep bot messages visible as conversation context independently of turn admission. Admission still depends on channel support, allowBots, mention rules, and access policy.

Is broadcast group budgeting the same thing?

No. Broadcast group budgets cap internal participant rounds and turns for a shared inbound message. Bot loop protection caps rapid platform-level exchanges between two bot identities.

Next step

If you run OpenClaw with Slack, Discord, Feishu, Google Chat, or Matrix, check one channel today. Confirm whether bot-authored messages are admitted, keep the shared pair guard enabled, and set one narrow override only if the room has a real operating reason. Then test with a controlled bot-to-bot exchange before trusting the setup in a busy room.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *