Discord (Bot API)
상태: 공식 Discord gateway를 통해 DM과 guild channel 모두 사용할 준비가 되어 있습니다.Pairing
Slash commands
Channel troubleshooting
Quick setup
새 Discord application과 bot을 만든 뒤, bot을 서버에 추가하고 OpenClaw와 pair해야 합니다. bot은 본인 전용 private server에 추가하는 구성을 권장합니다. 아직 서버가 없다면 먼저 새 서버를 생성하세요. 권장 선택은 Create My Own > For me and my friends 입니다.Create a Discord application and bot
Enable privileged intents
- Message Content Intent (필수)
- Server Members Intent (권장; role allowlist와 name-to-ID matching에 필요)
- Presence Intent (선택; presence update를 받을 때만 필요)
Copy your bot token
Generate an invite URL and add the bot to your server
botapplications.commands
- View Channels
- Send Messages
- Read Message History
- Embed Links
- Attach Files
- Add Reactions (선택)
Enable Developer Mode and collect your IDs
- User Settings(아바타 옆 톱니바퀴) -> Advanced -> Developer Mode 활성화
- 사이드바에서 server icon을 우클릭 -> Copy Server ID
- 자신의 avatar를 우클릭 -> Copy User ID
Allow DMs from server members
Step 0: Set your bot token securely (do not send it in chat)
openclaw gateway restart를 사용하세요.Configure OpenClaw and pair
- Ask your agent
- CLI / config
“I already set my Discord bot token in config. Please finish Discord setup with User ID<user_id>and Server ID<server_id>.”
DISCORD_BOT_TOKEN은 default account에만 사용됩니다.
고급 outbound call(message tool/channel action)에서는 per-call token이 해당 호출에만 사용됩니다. account policy와 retry 설정은 active runtime snapshot에서 선택된 account 기준으로 계속 적용됩니다.Recommended: Set up a guild workspace
DM이 정상 동작하면 Discord server를 full workspace로 구성할 수 있습니다. 이 구성에서는 각 channel이 각자 별도의 agent session과 context를 가집니다. private server에서 본인과 bot만 사용하는 경우 특히 권장됩니다.Add your server to the guild allowlist
- Ask your agent
- Config
“Add my Discord Server ID <server_id> to the guild allowlist”
Allow responses without @mention
- Ask your agent
- Config
“Allow my agent to respond on this server without having to be @mentioned”
#coding, #home, #research 같은 작업별 분리가 가능합니다.
Runtime model
- gateway가 Discord connection을 소유합니다.
- reply routing은 결정적입니다. Discord로 들어온 요청은 Discord로 다시 응답합니다.
- 기본값(
session.dmScope=main)에서는 direct chat이 agent의 main session(agent:main:main)을 공유합니다. - guild channel은 격리된 session key(
agent:<agentId>:discord:channel:<channelId>)를 사용합니다. - group DM은 기본적으로 무시됩니다(
channels.discord.dm.groupEnabled=false). - native slash command는 격리된 command session(
agent:<agentId>:discord:slash:<userId>)에서 실행되지만, 라우팅 대상 대화 session에는CommandTargetSessionKey를 계속 전달합니다.
Forum channels
Discord forum channel과 media channel은 thread post만 받을 수 있습니다. OpenClaw는 두 가지 생성 방식을 지원합니다.- forum parent(
channel:<forumId>)에 메시지를 보내 thread를 자동 생성합니다. 제목은 메시지의 첫 번째 non-empty line을 사용합니다. openclaw message thread create로 thread를 직접 생성합니다. forum channel에서는--message-id를 넘기지 마세요.
channel:<threadId>)로 보내세요.
Interactive components
OpenClaw는 agent message에서 Discord components v2 container를 지원합니다. message tool에components payload를 전달하면 됩니다. interaction 결과는 기존 Discord replyToMode 규칙을 따르는 일반 inbound message로 agent에게 다시 전달됩니다.
지원 block:
text,section,separator,actions,media-gallery,file- action row는 최대 5개의 button 또는 단일 select menu를 가질 수 있음
- select type:
string,user,role,mentionable,channel
components.reusable=true를 설정하세요.
특정 사용자만 button을 누르게 하려면 해당 button에 allowedUsers를 지정합니다. Discord user ID, tag, 또는 *를 넣을 수 있습니다. 일치하지 않는 사용자는 ephemeral denial을 받습니다.
/model과 /models slash command는 provider/model dropdown과 Submit 단계를 갖는 interactive model picker를 엽니다. 이 picker의 응답은 ephemeral이며, 실행한 사용자만 사용할 수 있습니다.
파일 첨부:
fileblock은attachment://<filename>참조를 가리켜야 함- 첨부 파일은
media/path/filePath(단일 파일)로 제공 - 여러 파일은
media-gallery사용 - 업로드 이름이 attachment reference와 맞아야 할 때는
filename지정
components.modal에 최대 5개의 field를 추가- field type:
text,checkbox,radio,select,role-select,user-select - OpenClaw가 trigger button을 자동으로 추가
Access control and routing
- DM policy
- Guild policy
- Mentions and group DMs
channels.discord.dmPolicy가 DM 접근 정책을 제어합니다(legacy: channels.discord.dm.policy).pairing(기본값)allowlistopen(channels.discord.allowFrom에"*"가 포함되어야 함; legacy:channels.discord.dm.allowFrom)disabled
pairing 모드라면 pairing prompt를 받게 됩니다.multi-account precedence:channels.discord.accounts.default.allowFrom은defaultaccount에만 적용- named account는 자체
allowFrom이 없을 때channels.discord.allowFrom을 상속 - named account는
channels.discord.accounts.default.allowFrom을 상속하지 않음
user:<id><@id>mention
Role-based agent routing
Discord guild member를 role ID로 서로 다른 agent에 라우팅하려면bindings[].match.roles를 사용합니다. role-based binding은 role ID만 허용하며, peer 또는 parent-peer binding 뒤, guild-only binding 앞에서 평가됩니다. binding이 peer + guildId + roles처럼 다른 match field도 함께 설정하면, 설정된 필드가 모두 일치해야 합니다.
Developer Portal setup
Create app and bot
Create app and bot
- Discord Developer Portal -> Applications -> New Application
- Bot -> Add Bot
- bot token 복사
Privileged intents
Privileged intents
- Message Content Intent
- Server Members Intent (권장)
setPresence 자체는 member presence update 권한이 없어도 됩니다.OAuth scopes and baseline permissions
OAuth scopes and baseline permissions
- scopes:
bot,applications.commands
- View Channels
- Send Messages
- Read Message History
- Embed Links
- Attach Files
- Add Reactions (선택)
Administrator는 피하세요.Copy IDs
Copy IDs
- server ID
- channel ID
- user ID
Native commands and command auth
commands.native의 기본값은"auto"이며 Discord에서 활성화됩니다.- channel 단위 override는
channels.discord.commands.native를 사용합니다. commands.native=false는 이전에 등록된 Discord native command를 명시적으로 제거합니다.- native command 인증은 일반 메시지 처리와 동일한 Discord allowlist/policy를 사용합니다.
- 권한이 없는 사용자에게도 Discord UI에서 command가 보일 수는 있지만, 실제 실행 시에는 OpenClaw auth가 적용되어 “not authorized”가 반환됩니다.
ephemeral: true
Feature details
Reply tags and native replies
Reply tags and native replies
Live stream preview
Live stream preview
channels.discord.streaming이 preview streaming을 제어합니다(off|partial|block|progress, 기본값:off).progress는 cross-channel consistency를 위해 허용되며 Discord에서는partial로 매핑됩니다.channels.discord.streamMode는 legacy alias이며 자동 마이그레이션됩니다.partial은 token이 도착할 때 하나의 preview message를 계속 수정합니다.block은 draft 크기의 chunk를 순서대로 보냅니다. 세부 크기와 분할 기준은draftChunk로 조정합니다.
block mode chunking 기본값(channels.discord.textChunkLimit 범위 내로 clamp):History, context, and thread behavior
History, context, and thread behavior
channels.discord.historyLimit기본값20- fallback:
messages.groupChat.historyLimit 0이면 비활성화
channels.discord.dmHistoryLimitchannels.discord.dms["<user_id>"].historyLimit
- Discord thread는 channel session으로 라우팅됨
- parent thread metadata를 parent-session linkage에 활용할 수 있음
- thread-specific entry가 없으면 parent channel config를 상속
Thread-bound sessions for subagents
Thread-bound sessions for subagents
/focus <target>현재 또는 새 thread를 subagent/session target에 bind/unfocus현재 thread binding 제거/agents활성 run과 binding 상태 표시/session idle <duration|off>focused binding의 inactivity auto-unfocus 조회/변경/session max-age <duration|off>focused binding의 hard max age 조회/변경
session.threadBindings.*는 global default를 설정channels.discord.threadBindings.*는 Discord 동작을 overridespawnSubagentSessions를true로 해야sessions_spawn({ thread: true })에 대해 thread를 자동 생성하고 bind함spawnAcpSessions를true로 해야 ACP(/acp spawn ... --thread ...또는sessions_spawn({ runtime: "acp", thread: true }))에 대해 thread를 자동 생성하고 bind함- account에서 thread binding이 비활성화되면
/focus와 관련 작업을 사용할 수 없음
Persistent ACP channel bindings
Persistent ACP channel bindings
bindings[]withtype: "acp"andmatch.channel: "discord"
- thread message는 parent channel ACP binding을 상속할 수 있음
- binding된 channel 또는 thread에서
/new와/reset은 같은 ACP session을 제자리에서 reset함 - 임시 thread binding도 계속 사용할 수 있으며, 활성 상태에서는 target resolution을 override할 수 있음
Reaction notifications
Reaction notifications
offown(기본값)allallowlist(guilds.<id>.users사용)
Ack reactions
Ack reactions
ackReaction은 OpenClaw가 inbound message를 처리하는 동안 acknowledgement emoji를 보냅니다.resolution 순서:channels.discord.accounts.<accountId>.ackReactionchannels.discord.ackReactionmessages.ackReaction- agent identity emoji fallback(
agents.list[].identity.emoji, 없으면"👀")
- Discord는 unicode emoji와 custom emoji name을 모두 허용함
- channel 또는 account에서 reaction을 끄려면
""사용
Config writes
Config writes
/config set|unset 흐름에 영향을 줍니다.비활성화:Gateway proxy
Gateway proxy
channels.discord.proxy를 사용하면 Discord gateway WebSocket traffic과 startup REST lookup(application ID + allowlist resolution)을 HTTP(S) proxy로 라우팅할 수 있습니다.PluralKit support
PluralKit support
- allowlist에는
pk:<memberId>사용 가능 - member display name은
channels.discord.dangerouslyAllowNameMatching: true일 때만 name/slug로 매칭 - lookup은 원본 message ID를 사용하며 time window 제약이 있음
- lookup이 실패하면 proxied message는 bot message로 취급되어
allowBots=true가 아니면 drop됨
Presence configuration
Presence configuration
- 0: Playing
- 1: Streaming (
activityUrl필요) - 2: Listening
- 3: Watching
- 4: Custom (activity text를 status state로 사용하며 emoji는 선택)
- 5: Competing
autoPresence.healthyTextautoPresence.degradedTextautoPresence.exhaustedText({reason}placeholder 지원)
Exec approvals in Discord
Exec approvals in Discord
channels.discord.execApprovals.enabledchannels.discord.execApprovals.approverschannels.discord.execApprovals.target(dm|channel|both, 기본값:dm)agentFilter,sessionFilter,cleanupAfterResolve
target이 channel 또는 both이면 approval prompt가 channel에 표시됩니다. button은 approver로 설정된 사용자만 사용할 수 있으며, 다른 사용자는 ephemeral denial을 받습니다. prompt에는 command text가 포함되므로, trusted channel에서만 channel delivery를 켜는 것이 안전합니다. session key에서 channel ID를 파생할 수 없으면 OpenClaw는 DM delivery로 fallback합니다.이 handler의 gateway auth는 다른 gateway client와 같은 shared credential resolution contract를 사용합니다.- env-first local auth (
OPENCLAW_GATEWAY_TOKEN/OPENCLAW_GATEWAY_PASSWORD, 그다음gateway.auth.*) - local mode에서는
gateway.auth.*가 unset일 때만gateway.remote.*를 fallback으로 사용하며, 설정은 되었지만 resolve되지 않은 local SecretRef는 fail closed - applicable한 경우
gateway.remote.*기반 remote-mode 지원 - URL override는 override-safe하며, CLI override는 implicit credential을 재사용하지 않고 env override는 env credential만 사용
Tools and action gates
Discord message action에는 messaging, channel admin, moderation, presence, metadata action이 포함됩니다. 핵심 예시:- messaging:
sendMessage,readMessages,editMessage,deleteMessage,threadReply - reactions:
react,reactions,emojiList - moderation:
timeout,kick,ban - presence:
setPresence
channels.discord.actions.* 아래에 있습니다.
기본 gate 동작:
| Action group | Default |
|---|---|
| reactions, messages, threads, pins, polls, search, memberInfo, roleInfo, channelInfo, channels, voiceStatus, events, stickers, emojiUploads, stickerUploads, permissions | enabled |
| roles | disabled |
| moderation | disabled |
| presence | disabled |
Components v2 UI
OpenClaw는 Discord components v2를 exec approval과 cross-context marker에 사용합니다. Discord message action도 custom UI를 위해components를 받을 수 있습니다. 이 기능은 고급 사용 사례이며 Carbon component instance가 필요합니다. legacy embeds도 계속 쓸 수 있지만 권장하지는 않습니다.
channels.discord.ui.components.accentColor는 Discord component container의 accent color(hex)를 설정합니다.- account별로는
channels.discord.accounts.<id>.ui.components.accentColor를 사용합니다. - components v2가 존재하면
embeds는 무시됩니다.
Voice channels
OpenClaw는 Discord voice channel에 참가해 realtime, continuous conversation을 수행할 수 있습니다. 이는 voice message attachment와는 별도 기능입니다. 요구 사항:- native command를 활성화해야 함(
commands.native또는channels.discord.commands.native) channels.discord.voice를 설정해야 함- target voice channel에서 bot에 Connect + Speak 권한이 있어야 함
/vc join|leave|status를 사용합니다. 이 command는 account default agent를 사용하며, 다른 Discord command와 같은 allowlist와 group policy를 따릅니다.
auto-join 예시:
voice.tts는 voice playback에 대해서만messages.tts를 override함- voice transcript turn은 Discord
allowFrom(또는dm.allowFrom) 기준으로 owner status를 파생하며, non-owner speaker는 owner-only tool(예:gateway,cron)에 접근할 수 없음 - voice는 기본 활성화 상태이며, 비활성화하려면
channels.discord.voice.enabled=false voice.daveEncryption과voice.decryptionFailureTolerance는@discordjs/voicejoin option으로 그대로 전달됨@discordjs/voice기본값은 각각daveEncryption=true,decryptionFailureTolerance=24- OpenClaw는 receive decrypt failure를 감시하고, 짧은 시간 동안 반복 실패가 발생하면 voice channel을 leave/rejoin하여 자동 복구를 시도함
- receive log에
DecryptionFailed(UnencryptedWhenPassthroughDisabled)가 반복되면, upstream@discordjs/voicereceive bug인 discord.js #11419와 비교해 보세요
Voice messages
Discord voice message는 waveform preview와 함께 표시되며 OGG/Opus audio와 metadata가 필요합니다. OpenClaw는 waveform을 자동 생성하지만, gateway host에ffmpeg와 ffprobe가 있어야 audio file을 검사하고 변환할 수 있습니다.
요구 사항 및 제약:
- local file path를 제공해야 함(URL은 거부됨)
- text content는 생략해야 함(Discord는 같은 payload에서 text + voice message를 허용하지 않음)
- 어떤 audio format이든 입력 가능하며, 필요하면 OpenClaw가 OGG/Opus로 변환
Troubleshooting
Used disallowed intents or bot sees no guild messages
Used disallowed intents or bot sees no guild messages
- Message Content Intent 활성화
- user/member resolution이 필요하면 Server Members Intent도 활성화
- intent를 바꾼 뒤 gateway 재시작
Guild messages blocked unexpectedly
Guild messages blocked unexpectedly
groupPolicy확인channels.discord.guilds의 guild allowlist 확인- guild에
channelsmap이 있으면 listed channel만 허용됨 requireMention동작과 mention pattern 확인
Require mention false but still blocked
Require mention false but still blocked
groupPolicy="allowlist"인데 일치하는 guild/channel allowlist가 없음requireMention을 잘못된 위치에 설정함(channels.discord.guilds또는 channel entry 아래여야 함)- sender가 guild/channel
usersallowlist에서 차단됨
Long-running handlers time out or duplicate replies
Long-running handlers time out or duplicate replies
Listener DiscordMessageListener timed out after 30000ms for event MESSAGE_CREATESlow listener detected ...discord inbound worker timed out after ...
- single-account:
channels.discord.eventQueue.listenerTimeout - multi-account:
channels.discord.accounts.<accountId>.eventQueue.listenerTimeout
- single-account:
channels.discord.inboundWorker.runTimeoutMs - multi-account:
channels.discord.accounts.<accountId>.inboundWorker.runTimeoutMs - 기본값:
1800000(30 minutes),0이면 비활성화
eventQueue.listenerTimeout을 사용하고, queued agent turn에 별도 safety valve가 필요할 때만 inboundWorker.runTimeoutMs를 조정하세요.Permissions audit mismatches
Permissions audit mismatches
channels status --probe의 permission check는 numeric channel ID에서만 완전하게 동작합니다.slug key를 사용해도 runtime matching은 작동할 수 있지만, probe는 권한을 완전히 검증할 수 없습니다.DM and pairing issues
DM and pairing issues
- DM 비활성화:
channels.discord.dm.enabled=false - DM policy 비활성화:
channels.discord.dmPolicy="disabled"(legacy:channels.discord.dm.policy) pairingmode에서 pairing approval 대기 중
Bot to bot loops
Bot to bot loops
channels.discord.allowBots=true를 사용하는 경우에는 loop를 피할 수 있도록 strict mention과 allowlist 규칙을 함께 사용하세요.
bot mention이 있는 메시지만 허용하려면 channels.discord.allowBots="mentions"가 더 안전합니다.Voice STT drops with DecryptionFailed(...)
Voice STT drops with DecryptionFailed(...)
- Discord voice receive recovery logic가 포함되도록 OpenClaw를 최신 상태로 유지(
openclaw update) channels.discord.voice.daveEncryption=true확인(기본값)- 우선
channels.discord.voice.decryptionFailureTolerance=24(upstream 기본값)로 시작하고 필요할 때만 조정 - 다음 log를 확인:
discord voice: DAVE decrypt failures detecteddiscord voice: repeated decrypt failures; attempting rejoin
- automatic rejoin 이후에도 실패가 계속되면 log를 수집해 discord.js #11419와 비교
Configuration reference pointers
주요 reference: 중요한 Discord field:- startup/auth:
enabled,token,accounts.*,allowBots - policy:
groupPolicy,dm.*,guilds.*,guilds.*.channels.* - command:
commands.native,commands.useAccessGroups,configWrites,slashCommand.* - event queue:
eventQueue.listenerTimeout(listener budget),eventQueue.maxQueueSize,eventQueue.maxConcurrency - inbound worker:
inboundWorker.runTimeoutMs - reply/history:
replyToMode,historyLimit,dmHistoryLimit,dms.*.historyLimit - delivery:
textChunkLimit,chunkMode,maxLinesPerMessage - streaming:
streaming(legacy alias:streamMode),draftChunk,blockStreaming,blockStreamingCoalesce - media/retry:
mediaMaxMb,retrymediaMaxMb는 outbound Discord upload 상한(default:8MB)
- actions:
actions.* - presence:
activity,status,activityType,activityUrl - UI:
ui.components.accentColor - features:
threadBindings, top-levelbindings[](type: "acp"),pluralkit,execApprovals,intents,agentComponents,heartbeat,responsePrefix
Safety and operations
- bot token은 secret으로 취급하세요. supervised environment에서는
DISCORD_BOT_TOKEN사용을 권장합니다. - Discord permission은 최소 권한 원칙으로 부여하세요.
- command 배포 상태가 stale해 보이면 gateway를 재시작하고
openclaw channels status --probe로 다시 확인하세요.