2026-06-18
Automate Discord with OpenClaw: Put an Outbound Gate Before the Bot
A 40-case egress drill turns Discord permissions, OpenClaw channel policy, action gates, human review, and idempotency into one testable outbound contract.
Discord operations
To automate Discord with OpenClaw safely, make the first workflow an outbound gate. A moderation classifier, FAQ writer, digest, and onboarding helper all cross the same boundary: untrusted conversation becomes a message or privileged action in a community that believes the bot speaks for its operators.
The earlier version of this article promised response times, conversion lifts, monthly costs, and four production-ready agents without retaining a source, a server trace, or a reproducible configuration. Those numbers are gone. This rewrite uses current Discord developer contracts, OpenClaw 2026.7.1-2 channel documentation, and a deterministic 40-case egress fixture. It does not connect to Discord. The fixture asks a smaller question before any model or bot call: may this exact event, in this exact guild and channel, produce this exact external action? All 40 expected decisions matched. Three cases allowed a send, one allowed a read, one produced a draft for review, one returned a cached receipt, and 34 were held or blocked.
c1ec24dd0327b8637e29ac56cba5609c5228fd406728b5fc1826aa7b34589610. That proves only the local decision function matched its expected cases; it does not prove a bot can moderate a real server.Four bots are one outbound problem
A community team may describe four products. The boundary sees four variants of the same operation.
An FAQ reply changes public conversation. A digest changes what the community treats as important. An onboarding DM opens a private channel with a person who did not ask a model to contact them. A timeout or ban changes a member's access. Calling all four “content automation” hides the authority difference.
That difference belongs in code. Read-only observation, draft creation, ordinary message send, moderation, role mutation, and presence mutation should not share one boolean named discordEnabled. They need separate action gates, separate evidence, and separate review policy.
The useful unit is therefore not “the Discord agent.” It is an action packet bound to account, guild, channel, triggering sender, triggering event, intended action, message body, citations, reply target, review status, and idempotency key. If one field is missing, the system should stop before egress.
The effective policy is narrower than the bot role
Discord permissions describe what an application can do at the platform boundary. OpenClaw policy decides which inbound events may reach an agent and which channel actions the runtime exposes. The narrower result wins. Discord's permission contract combines base guild permissions, role aggregation, channel overwrites, and administrator behavior. Gateway intents separately control which event classes reach the connection; privileged intents require explicit enablement and may require approval for verified applications. Neither contract says an agent should answer every event it can see. OpenClaw adds another set of gates: its Discord channel uses dmPolicy and allowFrom for DMs, while guild traffic can be open, allowlist, or disabled. The secure baseline is allowlist. An allowlisted guild can narrow senders by stable user or role IDs, deny every non-listed channel, and retain the default mention gate. Action groups then narrow the result again. In the current OpenClaw documentation, messages and several metadata groups are enabled by default, while roles, moderation, and presence are disabled. A bot account holding Discord's ban permission does not make ban available through an OpenClaw action gate that remains off.
| Layer | Question | Fail-closed result |
|---|---|---|
| Discord application | Does the bot have the required permission and intent? | No event or API action. |
| OpenClaw channel | Is this sender, guild, channel, and activation pattern allowed? | No agent dispatch. |
| OpenClaw action gate | Is message, moderation, role, or presence access enabled? | No tool action. |
| Workflow packet | Is the target, evidence, review, and idempotency binding complete? | No external side effect. |
Capability is not authorization. The safe configuration is the intersection of these layers, not the union.
Validation: forty decisions before a real message
The retained fixture starts with one approved FAQ reply. Its guild, channel, sender, mention activation, source snapshot, triggering event, reply target, evidence state, message length, action gate, review status, component lifetime, and idempotency key are all pinned. Each negative case changes one boundary.
The three send cases are intentionally boring: the approved baseline, an explicitly allowed bot-authored mention with the same reply binding, and a fresh retry packet with its own idempotency key. A completed duplicate does not send again; it returns the retained receipt.
Policy failures stop early. A denied guild, channel, sender, or activation pattern never reaches content review. Missing event or target bindings block. Private DM context cannot be copied into a guild reply. Empty or oversized messages block. Mass mentions and role mentions block. Stale evidence waits. Moderation, roles, and presence remain privileged even when a test packet claims their gate is enabled.
The order matters. It avoids spending model tokens on a request that cannot be sent and avoids treating a polished draft as permission to publish it. It also gives operators a reason code that belongs to the boundary that failed.
{
"event": "bound",
"target": { "guild": "fixed", "channel": "fixed", "replyTo": "fixed" },
"action": "send",
"evidence": "current-cited",
"review": "approved",
"idempotency": "event:workflow:revision",
"result": "ALLOW_SEND"
}
No model chose these outcomes. The JavaScript fixture compares exact fields in a fixed order and writes a body-independent evidence artifact.
A community loop that stops before egress
The practical workflow is observe, draft, review, send, verify. It is deliberately less glamorous than four autonomous agents.
Observe receives one Discord event only after the channel policy admits it. Keep the guild, channel, message, author, and reply relationship. Do not silently blend private messages, hidden channels, or unrelated history into a public response.
Draft creates an artifact. An FAQ answer carries the source URL and source revision. A digest carries the included channels and window. An onboarding note carries the trigger and contact limit. A moderation proposal carries the exact message, proposed action, rule, evidence, and expiry. None of these drafts performs egress.
The approval seal expires with the artifact
Review binds an operator decision to that artifact. OpenClaw's Discord component callbacks expire after 30 minutes by default and can be configured up to 24 hours. A longer lifetime helps a slow review queue but increases the window in which an old message can still trigger an action. The fixture rejects zero, over-limit, and expired callback lifetimes.
Send uses the approved packet rather than asking the model to recreate its answer. Verify stores the Discord response or failure against the same idempotency key. If the process restarts after Discord accepted the request, the retry should return the receipt instead of posting a second message.
Failure modes: moderation is not just a stronger reply
Deleting a message, timing out a member, kicking, banning, and changing roles alter access or erase community state. They deserve a different contract from posting an answer. The current OpenClaw Discord action defaults reflect that split: moderation and roles are disabled. Turning them on is a configuration change, not an inference-time decision. A classifier's confidence should not enable a gate. Nor should a human approval for one proposed reply authorize a later ban created from the same conversation.
A moderation packet needs the target user and message, proposed action, exact duration where applicable, cited server rule, retained evidence, appeal path, approving operator, approval expiry, and verification result. “This looks like spam” is evidence for review, not an authority token.
Bot-authored traffic adds another failure mode. OpenClaw ignores it by default. If allowBots is enabled, strict mentions and allowlists matter; mentions is safer than admitting every bot message. Shared loop protection can suppress a noisy bot pair after an event budget is exceeded, but that guard is a last boundary, not a reason to design two bots that answer each other.
For the first deployment, leave moderation, roles, presence, DMs, and bot-authored input off. Admit one help channel, one stable operator group, mention activation, read access, and draft creation. Add ordinary replies after review works. Privileged actions can wait for separate evidence.
Troubleshooting duplicate sends and bot loops
Discord documents rate limits per route and globally, and warns clients not to hard-code limits. A correct client reads rate-limit headers, respects retry_after, and handles 429 responses. That is necessary, but it does not solve duplicate egress.
A timeout can occur after Discord accepted a request but before the caller stored the response. Retrying blindly may create a second FAQ answer, digest, welcome message, or moderation record. The workflow therefore needs an event-bound idempotency key and a durable state transition: new, in progress, completed with receipt, or failed before side effect.
The fixture treats a completed duplicate as success with an existing receipt. An unknown replay state waits. It never asks a model whether two messages “look the same.” Semantic similarity is the wrong tool for exactly-once delivery.
What this drill did not test
The fixture did not start OpenClaw, connect a Discord bot, open a Gateway session, read a guild, fetch a member, inspect effective Discord permissions, send or delete a message, create a DM, exercise a component callback, trigger a rate limit, or call a model. It used no token and made no external side effect. That limitation is useful. It keeps the claim precise: given the retained synthetic packets, the local decision function produced all 40 expected results. It does not establish moderation accuracy, FAQ correctness, response time, community conversion, monthly cost, or return on investment.
The next test should use a private Discord server and a non-production bot. Start with read-only and draft cases. Probe the exact numeric guild and channel IDs, verify permission and intent failures, approve one ordinary reply, force a retry after a simulated lost response, and confirm that only one message exists. Then run an explicitly denied moderation action and verify that it never reaches Discord.
Measure false replies, unsupported citations, duplicate sends, human review time, rejected drafts, rate-limit recovery, and side effects per accepted action. Those results can justify expanding the gate. A launch post, prompt, or attractive workflow diagram cannot.
Sources
- Discord permissions — permission bitfields, role aggregation, channel overwrites, administrator behavior, and permission computation.
- Discord Gateway intents — event subscription boundaries, privileged intents, and application approval requirements.
- Discord message resource — create-message contract, message limits, replies, mentions, and allowed mentions.
- Discord rate limits — per-route and global limits, response headers, 429 handling, and
retry_after. - OpenClaw Discord channel documentation for 2026.7.1-2 — DM and guild policy, mention activation, access groups, session routing, components, action gates, capability checks, and bot-loop protection.
- Local deterministic egress fixture — 40 cases, 40 matches, 25 decision states, three sends, two read/draft outcomes, one cached receipt, and 34 blocks or holds. SHA-256:
c1ec24dd0327b8637e29ac56cba5609c5228fd406728b5fc1826aa7b34589610.