Discord (Bot API)
상태: 공식 Discord 게이트웨이를 통한 DM 및 길드 채널 지원 준비 완료.
빠른 설정
새 애플리케이션과 봇을 생성하고, 서버에 봇을 추가하고, OpenClaw와 페어링해야 합니다. 개인 전용 서버에 봇을 추가하는 것을 권장합니다. 아직 서버가 없다면 먼저 생성하세요 (Create My Own > For me and my friends 선택).
1단계: Discord 애플리케이션 및 봇 생성
[Discord Developer Portal](https://discord.com/developers/applications)로 이동하여 **New Application**을 클릭합니다. "OpenClaw"와 같은 이름을 지정합니다.
사이드바에서 **Bot**을 클릭합니다. **Username**을 OpenClaw 에이전트의 이름으로 설정합니다.
2단계: 특권 인텐트 활성화
**Bot** 페이지에서 아래로 스크롤하여 **Privileged Gateway Intents**에서 다음을 활성화합니다:
- **Message Content Intent** (필수)
- **Server Members Intent** (권장; 역할 허용 목록 및 이름-ID 매칭에 필요)
- **Presence Intent** (선택; 프레즌스 업데이트에만 필요)
3단계: 봇 토큰 복사
**Bot** 페이지에서 위로 스크롤하여 **Reset Token**을 클릭합니다.
> **참고:** 이름과 달리 첫 번째 토큰을 생성하는 것이며, "리셋"하는 것이 아닙니다.
토큰을 복사하여 저장합니다. 이것이 **Bot Token**이며 곧 필요합니다.
4단계: 초대 URL 생성 및 서버에 봇 추가
사이드바에서 **OAuth2**를 클릭합니다. 적절한 권한이 포함된 초대 URL을 생성합니다.
**OAuth2 URL Generator**로 스크롤하여 다음을 활성화합니다:
- `bot`
- `applications.commands`
아래에 **Bot Permissions** 섹션이 나타납니다. 다음을 활성화합니다:
- View Channels
- Send Messages
- Read Message History
- Embed Links
- Attach Files
- Add Reactions (선택)
하단에 생성된 URL을 복사하여 브라우저에 붙여넣고, 서버를 선택하고, **Continue**를 클릭하여 연결합니다. Discord 서버에 봇이 표시되어야 합니다.
5단계: 개발자 모드 활성화 및 ID 수집
Discord 앱으로 돌아가서 내부 ID를 복사할 수 있도록 개발자 모드를 활성화합니다.
1. **User Settings** (아바타 옆 기어 아이콘) -> **Advanced** -> **Developer Mode** 토글 켜기
2. 사이드바에서 **서버 아이콘**을 마우스 오른쪽 클릭 -> **Copy Server ID**
3. **자신의 아바타**를 마우스 오른쪽 클릭 -> **Copy User ID**
**Server ID**와 **User ID**를 Bot Token과 함께 저장합니다 -- 다음 단계에서 세 가지 모두 OpenClaw에 보냅니다.
6단계: 서버 멤버로부터 DM 허용
페어링이 작동하려면 Discord가 봇의 DM을 허용해야 합니다. **서버 아이콘** 마우스 오른쪽 클릭 -> **Privacy Settings** -> **Direct Messages** 토글 켜기.
서버 멤버(봇 포함)가 DM을 보낼 수 있게 됩니다. Discord DM을 OpenClaw와 함께 사용하려면 이를 활성화된 상태로 유지합니다. 길드 채널만 사용할 계획이면 페어링 후 DM을 비활성화할 수 있습니다.
7단계: 봇 토큰을 안전하게 설정 (채팅으로 보내지 마세요)
Discord 봇 토큰은 비밀(비밀번호와 같음)입니다. 에이전트에게 메시지를 보내기 전에 OpenClaw를 실행하는 머신에 설정합니다.
openclaw config set channels.discord.token '"YOUR_BOT_TOKEN"' --json
openclaw config set channels.discord.enabled true --json
openclaw gateway
OpenClaw가 이미 백그라운드 서비스로 실행 중이면 대신 `openclaw gateway restart`를 사용합니다.
8단계: OpenClaw 설정 및 페어링
#### 에이전트에게 요청
기존 채널(예: Telegram)에서 OpenClaw 에이전트와 채팅합니다. Discord가 첫 번째 채널이면 CLI / 설정 탭을 사용합니다.
> "Discord 봇 토큰을 설정에 넣었습니다. User ID `<user_id>`와 Server ID `<server_id>`로 Discord 설정을 완료해 주세요."
#### CLI / 설정
파일 기반 설정을 선호하는 경우:
{
channels: {
discord: {
enabled: true,
token: "YOUR_BOT_TOKEN",
},
},
}
기본 계정의 환경 변수 폴백:
DISCORD_BOT_TOKEN=...
`channels.discord.token`에는 SecretRef 값도 지원됩니다 (env/file/exec 프로바이더). [Secrets Management](/docs/gateway/secrets)를 참조하세요.
9단계: 첫 DM 페어링 승인
게이트웨이가 실행될 때까지 기다린 후 Discord에서 봇에게 DM을 보냅니다. 페어링 코드로 응답합니다.
#### 에이전트에게 요청
기존 채널에서 에이전트에게 페어링 코드를 보냅니다:
> "이 Discord 페어링 코드를 승인해 주세요: `<CODE>`"
#### CLI
openclaw pairing list discord
openclaw pairing approve discord <CODE>
페어링 코드는 1시간 후 만료됩니다.
이제 Discord DM을 통해 에이전트와 채팅할 수 있어야 합니다.
참고: 토큰 해석은 계정을 인식합니다. 설정 토큰 값이 환경 변수 폴백보다 우선합니다.
DISCORD_BOT_TOKEN은 기본 계정에만 사용됩니다. 고급 아웃바운드 호출 (메시지 도구/채널 액션)의 경우 해당 호출에 명시적 호출별token이 사용됩니다. 계정 정책/재시도 설정은 활성 런타임 스냅샷의 선택된 계정에서 가져옵니다.
권장: 길드 작업 공간 설정
DM이 작동하면 Discord 서버를 각 채널이 자체 에이전트 세션과 컨텍스트를 가진 완전한 작업 공간으로 설정할 수 있습니다. 봇과 당신만 있는 개인 서버에 권장됩니다.
1단계: 서버를 길드 허용 목록에 추가
에이전트가 DM뿐만 아니라 서버의 모든 채널에서 응답할 수 있게 합니다.
#### 에이전트에게 요청
> "내 Discord Server ID `<server_id>`를 길드 허용 목록에 추가해 줘"
#### 설정
{
channels: {
discord: {
groupPolicy: "allowlist",
guilds: {
YOUR_SERVER_ID: {
requireMention: true,
users: ["YOUR_USER_ID"],
},
},
},
},
}
2단계: @멘션 없이 응답 허용
기본적으로 에이전트는 길드 채널에서 @멘션될 때만 응답합니다. 개인 서버에서는 모든 메시지에 응답하도록 설정하는 것이 좋습니다.
#### 에이전트에게 요청
> "이 서버에서 @멘션 없이도 에이전트가 응답하도록 허용해 줘"
#### 설정
길드 설정에서 `requireMention: false`를 설정합니다:
{
channels: {
discord: {
guilds: {
YOUR_SERVER_ID: {
requireMention: false,
},
},
},
},
}
3단계: 길드 채널에서 메모리 계획
기본적으로 장기 메모리(MEMORY.md)는 DM 세션에서만 로드됩니다. 길드 채널은 MEMORY.md를 자동 로드하지 않습니다.
#### 에이전트에게 요청
> "Discord 채널에서 질문할 때 MEMORY.md의 장기 컨텍스트가 필요하면 memory_search 또는 memory_get을 사용해 줘."
#### 수동
모든 채널에서 공유 컨텍스트가 필요하면 안정적인 지침을 `AGENTS.md` 또는 `USER.md`에 넣습니다 (모든 세션에 주입됨). 장기 노트는 `MEMORY.md`에 보관하고 메모리 도구로 필요할 때 접근합니다.
이제 Discord 서버에 채널을 만들고 채팅을 시작합니다. 에이전트가 채널 이름을 볼 수 있으며 각 채널은 자체 격리된 세션을 갖습니다 — 워크플로에 맞게 #coding, #home, #research 등을 설정할 수 있습니다.
런타임 모델
- 게이트웨이가 Discord 연결을 소유합니다.
- 응답 라우팅은 결정론적: Discord 인바운드는 Discord로 응답합니다.
- 기본적으로 (
session.dmScope=main) 다이렉트 채팅은 에이전트 메인 세션을 공유합니다 (agent:main:main). - 길드 채널은 격리된 세션 키입니다 (
agent:<agentId>:discord:channel:<channelId>). - 그룹 DM은 기본적으로 무시됩니다 (
channels.discord.dm.groupEnabled=false). - 네이티브 슬래시 명령은 격리된 명령 세션에서 실행되며 (
agent:<agentId>:discord:slash:<userId>), 라우팅된 대화 세션에CommandTargetSessionKey를 전달합니다.
포럼 채널
Discord 포럼 및 미디어 채널은 스레드 게시물만 허용합니다. OpenClaw는 두 가지 생성 방법을 지원합니다:
- 포럼 부모에 메시지 전송 (
channel:<forumId>)으로 자동 스레드 생성. 스레드 제목은 메시지의 첫 비어있지 않은 줄을 사용합니다. openclaw message thread create로 직접 스레드 생성. 포럼 채널에는--message-id를 전달하지 마세요.
예시: 포럼 부모에 전송하여 스레드 생성
openclaw message send --channel discord --target channel:<forumId> \
--message "Topic title\nBody of the post"
예시: 포럼 스레드를 명시적으로 생성
openclaw message thread create --channel discord --target channel:<forumId> \
--thread-name "Topic title" --message "Body of the post"
포럼 부모는 Discord 컴포넌트를 허용하지 않습니다. 컴포넌트가 필요하면 스레드 자체에 전송합니다 (channel:<threadId>).
인터랙티브 컴포넌트
OpenClaw는 에이전트 메시지에 Discord 컴포넌트 v2 컨테이너를 지원합니다. components 페이로드와 함께 메시지 도구를 사용합니다. 인터랙션 결과는 일반 인바운드 메시지로 에이전트에게 라우팅되며 기존 Discord replyToMode 설정을 따릅니다.
지원되는 블록:
text,section,separator,actions,media-gallery,file- 액션 행에는 최대 5개의 버튼 또는 단일 선택 메뉴 허용
- 선택 유형:
string,user,role,mentionable,channel
기본적으로 컴포넌트는 일회용입니다. components.reusable=true를 설정하면 버튼, 선택, 폼을 만료될 때까지 여러 번 사용할 수 있습니다.
버튼 클릭을 제한하려면 해당 버튼에 allowedUsers를 설정합니다 (Discord 사용자 ID, 태그, 또는 *). 설정된 경우 일치하지 않는 사용자는 일시적 거부 메시지를 받습니다.
/model 및 /models 슬래시 명령은 프로바이더와 모델 드롭다운 및 제출 단계가 있는 인터랙티브 모델 피커를 엽니다. 피커 응답은 일시적이며 호출한 사용자만 사용할 수 있습니다.
파일 첨부:
file블록은 첨부 참조를 가리켜야 합니다 (attachment://<filename>)media/path/filePath로 첨부를 제공합니다 (단일 파일); 여러 파일에는media-gallery사용- 업로드 이름이 첨부 참조와 일치해야 하는 경우
filename으로 재정의
모달 폼:
- 최대 5개 필드로
components.modal추가 - 필드 유형:
text,checkbox,radio,select,role-select,user-select - OpenClaw가 자동으로 트리거 버튼 추가
예시:
{
channel: "discord",
action: "send",
to: "channel:123456789012345678",
message: "Optional fallback text",
components: {
reusable: true,
text: "Choose a path",
blocks: [
{
type: "actions",
buttons: [
{
label: "Approve",
style: "success",
allowedUsers: ["123456789012345678"],
},
{ label: "Decline", style: "danger" },
],
},
{
type: "actions",
select: {
type: "string",
placeholder: "Pick an option",
options: [
{ label: "Option A", value: "a" },
{ label: "Option B", value: "b" },
],
},
},
],
modal: {
title: "Details",
triggerLabel: "Open form",
fields: [
{ type: "text", label: "Requester" },
{
type: "select",
label: "Priority",
options: [
{ label: "Low", value: "low" },
{ label: "High", value: "high" },
],
},
],
},
},
}
접근 제어 및 라우팅
DM 정책
`channels.discord.dmPolicy`로 DM 접근을 제어합니다 (레거시: `channels.discord.dm.policy`):
- `pairing` (기본값)
- `allowlist`
- `open` (`channels.discord.allowFrom`에 `"*"` 필요; 레거시: `channels.discord.dm.allowFrom`)
- `disabled`
DM 정책이 open이 아닌 경우 알 수 없는 사용자는 차단됩니다 (`pairing` 모드에서는 페어링 안내를 받음).
멀티 계정 우선순위:
- `channels.discord.accounts.default.allowFrom`은 `default` 계정에만 적용됩니다.
- 이름이 지정된 계정은 자체 `allowFrom`이 미설정이면 `channels.discord.allowFrom`을 상속합니다.
- 이름이 지정된 계정은 `channels.discord.accounts.default.allowFrom`을 상속하지 않습니다.
전달용 DM 대상 형식:
- `user:<id>`
- `<@id>` 멘션
순수 숫자 ID는 모호하며 명시적 user/channel 대상 종류가 제공되지 않으면 거부됩니다.
길드 정책
길드 처리는 `channels.discord.groupPolicy`로 제어됩니다:
- `open`
- `allowlist`
- `disabled`
`channels.discord`가 존재할 때 안전한 기본값은 `allowlist`입니다.
`allowlist` 동작:
- 길드가 `channels.discord.guilds`와 일치해야 합니다 (`id` 권장, 슬러그도 허용)
- 선택적 발신자 허용 목록: `users` (안정 ID 권장) 및 `roles` (역할 ID만); 둘 중 하나가 설정되면 `users` 또는 `roles`에 일치하는 발신자가 허용됩니다
- 직접 이름/태그 매칭은 기본적으로 비활성화; `channels.discord.dangerouslyAllowNameMatching: true`는 비상 호환 모드로만 활성화
- `users`에 이름/태그를 사용할 수 있지만 ID가 더 안전합니다; `openclaw security audit`은 이름/태그 항목 사용 시 경고합니다
- 길드에 `channels`가 설정되면 나열되지 않은 채널은 거부됩니다
- 길드에 `channels` 블록이 없으면 해당 허용된 길드의 모든 채널이 허용됩니다
예시:
{
channels: {
discord: {
groupPolicy: "allowlist",
guilds: {
"123456789012345678": {
requireMention: true,
ignoreOtherMentions: true,
users: ["987654321098765432"],
roles: ["123456789012345678"],
channels: {
general: { allow: true },
help: { allow: true, requireMention: true },
},
},
},
},
},
}
`DISCORD_BOT_TOKEN`만 설정하고 `channels.discord` 블록을 생성하지 않으면, `channels.defaults.groupPolicy`가 `open`이어도 런타임 폴백은 `groupPolicy="allowlist"`입니다 (로그에 경고).
멘션 및 그룹 DM
길드 메시지는 기본적으로 멘션 게이팅됩니다.
멘션 감지 대상:
- 명시적 봇 멘션
- 설정된 멘션 패턴 (`agents.list[].groupChat.mentionPatterns`, 폴백 `messages.groupChat.mentionPatterns`)
- 지원되는 경우에서의 암묵적 봇 답장 동작
`requireMention`은 길드/채널별로 설정됩니다 (`channels.discord.guilds...`).
`ignoreOtherMentions`는 선택적으로 봇이 아닌 다른 사용자/역할을 멘션하는 메시지를 삭제합니다 (@everyone/@here 제외).
그룹 DM:
- 기본: 무시 (`dm.groupEnabled=false`)
- `dm.groupChannels` (채널 ID 또는 슬러그)를 통한 선택적 허용 목록
역할 기반 에이전트 라우팅
bindings[].match.roles를 사용하여 Discord 길드 멤버를 역할 ID별로 다른 에이전트로 라우팅합니다. 역할 기반 바인딩은 역할 ID만 허용하며 peer 또는 parent-peer 바인딩 이후, guild-only 바인딩 이전에 평가됩니다. 바인딩이 다른 매치 필드도 설정하면 (예: peer + guildId + roles) 설정된 모든 필드가 일치해야 합니다.
{
bindings: [
{
agentId: "opus",
match: {
channel: "discord",
guildId: "123456789012345678",
roles: ["111111111111111111"],
},
},
{
agentId: "sonnet",
match: {
channel: "discord",
guildId: "123456789012345678",
},
},
],
}
개발자 포털 설정
앱 및 봇 생성
1. Discord Developer Portal -> **Applications** -> **New Application**
2. **Bot** -> **Add Bot**
3. 봇 토큰 복사
특권 인텐트
**Bot -> Privileged Gateway Intents**에서 활성화:
- Message Content Intent
- Server Members Intent (권장)
Presence intent는 선택 사항이며 프레즌스 업데이트를 수신하려는 경우에만 필요합니다. 봇 프레즌스 설정 (`setPresence`)에는 멤버의 프레즌스 업데이트 활성화가 필요하지 않습니다.
OAuth 스코프 및 기본 권한
OAuth URL 생성기:
- 스코프: `bot`, `applications.commands`
일반적인 기본 권한:
- View Channels
- Send Messages
- Read Message History
- Embed Links
- Attach Files
- Add Reactions (선택)
명시적으로 필요하지 않는 한 `Administrator`는 피합니다.
ID 복사
Discord 개발자 모드를 활성화한 후 복사:
- 서버 ID
- 채널 ID
- 사용자 ID
신뢰할 수 있는 감사 및 프로빙을 위해 OpenClaw 설정에서 숫자 ID를 권장합니다.
네이티브 명령 및 명령 인가
commands.native는 기본적으로"auto"이며 Discord에서 활성화됩니다.- 채널별 재정의:
channels.discord.commands.native. commands.native=false는 이전에 등록된 Discord 네이티브 명령을 명시적으로 삭제합니다.- 네이티브 명령 인가는 일반 메시지 처리와 동일한 Discord 허용 목록/정책을 사용합니다.
- 인가되지 않은 사용자에게도 Discord UI에 명령이 표시될 수 있지만, 실행 시 OpenClaw 인가를 적용하고 “not authorized”를 반환합니다.
명령 카탈로그 및 동작은 Slash commands를 참조하세요.
기본 슬래시 명령 설정:
ephemeral: true
기능 세부사항
응답 태그 및 네이티브 응답
Discord는 에이전트 출력에서 응답 태그를 지원합니다:
- `[[reply_to_current]]`
- `[[reply_to:<id>]]`
`channels.discord.replyToMode`로 제어:
- `off` (기본값)
- `first`
- `all`
참고: `off`는 암묵적 응답 스레딩을 비활성화합니다. 명시적 `[[reply_to_*]]` 태그는 여전히 적용됩니다.
메시지 ID는 에이전트가 특정 메시지를 대상으로 할 수 있도록 컨텍스트/히스토리에 표시됩니다.
실시간 스트림 미리보기
OpenClaw는 임시 메시지를 보내고 텍스트가 도착하면 편집하여 초안 응답을 스트리밍할 수 있습니다.
- `channels.discord.streaming`은 미리보기 스트리밍을 제어합니다 (`off` | `partial` | `block` | `progress`, 기본: `off`).
- `progress`는 크로스 채널 일관성을 위해 허용되며 Discord에서 `partial`로 매핑됩니다.
- `channels.discord.streamMode`는 레거시 별칭이며 자동 마이그레이션됩니다.
- `partial`은 토큰이 도착하면 단일 미리보기 메시지를 편집합니다.
- `block`은 초안 크기의 청크를 생성합니다 (`draftChunk`으로 크기와 분할점 조정).
예시:
{
channels: {
discord: {
streaming: "partial",
},
},
}
`block` 모드 청킹 기본값 (`channels.discord.textChunkLimit`으로 클램핑):
{
channels: {
discord: {
streaming: "block",
draftChunk: {
minChars: 200,
maxChars: 800,
breakPreference: "paragraph",
},
},
},
}
미리보기 스트리밍은 텍스트 전용이며 미디어 응답은 일반 전달로 폴백합니다.
참고: 미리보기 스트리밍은 블록 스트리밍과 별개입니다. Discord에 블록 스트리밍이 명시적으로 활성화되면 OpenClaw는 이중 스트리밍을 방지하기 위해 미리보기 스트림을 건너뜁니다.
히스토리, 컨텍스트, 스레드 동작
길드 히스토리 컨텍스트:
- `channels.discord.historyLimit` 기본 `20`
- 폴백: `messages.groupChat.historyLimit`
- `0`으로 비활성화
DM 히스토리 제어:
- `channels.discord.dmHistoryLimit`
- `channels.discord.dms["<user_id>"].historyLimit`
스레드 동작:
- Discord 스레드는 채널 세션으로 라우팅됨
- 부모 스레드 메타데이터는 부모 세션 연결에 사용 가능
- 스레드 설정은 스레드별 항목이 없으면 부모 채널 설정을 상속
채널 토픽은 **신뢰할 수 없는** 컨텍스트로 주입됩니다 (시스템 프롬프트로가 아님).
서브에이전트를 위한 스레드 바인딩 세션
Discord는 스레드를 세션 대상에 바인딩하여 해당 스레드의 후속 메시지가 동일한 세션(서브에이전트 세션 포함)으로 계속 라우팅되도록 할 수 있습니다.
명령:
- `/focus <target>` 현재/새 스레드를 서브에이전트/세션 대상에 바인딩
- `/unfocus` 현재 스레드 바인딩 제거
- `/agents` 활성 실행 및 바인딩 상태 표시
- `/session idle <duration|off>` 포커스된 바인딩의 비활성 자동 해제 확인/업데이트
- `/session max-age <duration|off>` 포커스된 바인딩의 하드 최대 수명 확인/업데이트
설정:
{
session: {
threadBindings: {
enabled: true,
idleHours: 24,
maxAgeHours: 0,
},
},
channels: {
discord: {
threadBindings: {
enabled: true,
idleHours: 24,
maxAgeHours: 0,
spawnSubagentSessions: false, // 옵트인
},
},
},
}
참고:
- `session.threadBindings.*`는 전역 기본값을 설정합니다.
- `channels.discord.threadBindings.*`는 Discord 동작을 재정의합니다.
- `spawnSubagentSessions`가 true여야 `sessions_spawn({ thread: true })`에 대한 스레드를 자동 생성/바인딩합니다.
- `spawnAcpSessions`가 true여야 ACP에 대한 스레드를 자동 생성/바인딩합니다 (`/acp spawn ... --thread ...` 또는 `sessions_spawn({ runtime: "acp", thread: true })`).
- 계정에 스레드 바인딩이 비활성화되면 `/focus` 및 관련 스레드 바인딩 작업을 사용할 수 없습니다.
[Sub-agents](/docs/tools/subagents), [ACP Agents](/docs/tools/acp-agents), [Configuration Reference](/docs/gateway/configuration-reference)를 참조하세요.
영구 ACP 채널 바인딩
안정적인 "항상 켜진" ACP 작업 공간에는 Discord 대화를 대상으로 하는 최상위 타입 ACP 바인딩을 설정합니다.
설정 경로:
- `bindings[]`에 `type: "acp"` 및 `match.channel: "discord"`
예시:
{
agents: {
list: [
{
id: "codex",
runtime: {
type: "acp",
acp: {
agent: "codex",
backend: "acpx",
mode: "persistent",
cwd: "/workspace/openclaw",
},
},
},
],
},
bindings: [
{
type: "acp",
agentId: "codex",
match: {
channel: "discord",
accountId: "default",
peer: { kind: "channel", id: "222222222222222222" },
},
acp: { label: "codex-main" },
},
],
channels: {
discord: {
guilds: {
"111111111111111111": {
channels: {
"222222222222222222": {
requireMention: false,
},
},
},
},
},
},
}
참고:
- 스레드 메시지는 부모 채널 ACP 바인딩을 상속할 수 있습니다.
- 바인딩된 채널 또는 스레드에서 `/new` 및 `/reset`은 동일한 ACP 세션을 제자리에서 리셋합니다.
- 임시 스레드 바인딩은 여전히 작동하며 활성 상태에서 대상 해석을 재정의할 수 있습니다.
바인딩 동작 세부사항은 [ACP Agents](/docs/tools/acp-agents)를 참조하세요.
리액션 알림
길드별 리액션 알림 모드:
- `off`
- `own` (기본값)
- `all`
- `allowlist` (`guilds.<id>.users` 사용)
리액션 이벤트는 시스템 이벤트로 변환되어 라우팅된 Discord 세션에 첨부됩니다.
수신 확인 리액션
`ackReaction`은 OpenClaw가 인바운드 메시지를 처리하는 동안 확인 이모지를 전송합니다.
해석 순서:
- `channels.discord.accounts.<accountId>.ackReaction`
- `channels.discord.ackReaction`
- `messages.ackReaction`
- 에이전트 ID 이모지 폴백 (`agents.list[].identity.emoji`, 없으면 "👀")
참고:
- Discord는 유니코드 이모지 또는 사용자 정의 이모지 이름을 허용합니다.
- `""`를 사용하여 채널 또는 계정에서 리액션을 비활성화합니다.
설정 쓰기
채널에서 시작된 설정 쓰기는 기본적으로 활성화됩니다.
이는 `/config set|unset` 흐름에 영향을 미칩니다 (명령 기능 활성화 시).
비활성화:
{
channels: {
discord: {
configWrites: false,
},
},
}
게이트웨이 프록시
`channels.discord.proxy`로 Discord 게이트웨이 WebSocket 트래픽 및 시작 REST 조회(애플리케이션 ID + 허용 목록 해석)를 HTTP(S) 프록시를 통해 라우팅합니다.
{
channels: {
discord: {
proxy: "http://proxy.example:8080",
},
},
}
계정별 재정의:
{
channels: {
discord: {
accounts: {
primary: {
proxy: "http://proxy.example:8080",
},
},
},
},
}
PluralKit 지원
프록시된 메시지를 시스템 멤버 ID로 매핑하기 위해 PluralKit 해석을 활성화합니다:
{
channels: {
discord: {
pluralkit: {
enabled: true,
token: "pk_live_...", // 선택; 비공개 시스템에 필요
},
},
},
}
참고:
- 허용 목록에 `pk:<memberId>` 사용 가능
- 멤버 표시 이름은 `channels.discord.dangerouslyAllowNameMatching: true`일 때만 이름/슬러그로 매칭
- 조회는 원본 메시지 ID를 사용하며 시간 창 제한이 있음
- 조회 실패 시 프록시된 메시지는 봇 메시지로 취급되며 `allowBots=true`가 아니면 삭제됨
프레즌스 설정
상태나 활동 필드를 설정하거나 자동 프레즌스를 활성화하면 프레즌스 업데이트가 적용됩니다.
상태만 예시:
{
channels: {
discord: {
status: "idle",
},
},
}
활동 예시 (사용자 정의 상태가 기본 활동 유형):
{
channels: {
discord: {
activity: "Focus time",
activityType: 4,
},
},
}
스트리밍 예시:
{
channels: {
discord: {
activity: "Live coding",
activityType: 1,
activityUrl: "https://twitch.tv/openclaw",
},
},
}
활동 유형 맵:
- 0: Playing
- 1: Streaming (`activityUrl` 필요)
- 2: Listening
- 3: Watching
- 4: Custom (활동 텍스트를 상태로 사용; 이모지는 선택)
- 5: Competing
자동 프레즌스 예시 (런타임 헬스 시그널):
{
channels: {
discord: {
autoPresence: {
enabled: true,
intervalMs: 30000,
minUpdateIntervalMs: 15000,
exhaustedText: "token exhausted",
},
},
},
}
자동 프레즌스는 런타임 가용성을 Discord 상태에 매핑합니다: healthy => online, degraded 또는 unknown => idle, exhausted 또는 unavailable => dnd. 선택적 텍스트 재정의:
- `autoPresence.healthyText`
- `autoPresence.degradedText`
- `autoPresence.exhaustedText` (`{reason}` 플레이스홀더 지원)
Discord에서의 실행 승인
Discord는 DM에서 버튼 기반 실행 승인을 지원하며 원본 채널에 승인 프롬프트를 선택적으로 게시할 수 있습니다.
설정 경로:
- `channels.discord.execApprovals.enabled`
- `channels.discord.execApprovals.approvers`
- `channels.discord.execApprovals.target` (`dm` | `channel` | `both`, 기본: `dm`)
- `agentFilter`, `sessionFilter`, `cleanupAfterResolve`
`target`이 `channel` 또는 `both`이면 승인 프롬프트가 채널에 표시됩니다. 설정된 승인자만 버튼을 사용할 수 있으며, 다른 사용자는 일시적 거부를 받습니다. 승인 프롬프트에는 명령 텍스트가 포함되므로 신뢰할 수 있는 채널에서만 채널 전달을 활성화합니다. 세션 키에서 채널 ID를 유도할 수 없으면 OpenClaw는 DM 전달로 폴백합니다.
이 핸들러의 게이트웨이 인증은 다른 게이트웨이 클라이언트와 동일한 공유 자격 증명 해석 계약을 사용합니다:
- env 우선 로컬 인증 (`OPENCLAW_GATEWAY_TOKEN` / `OPENCLAW_GATEWAY_PASSWORD` 그 다음 `gateway.auth.*`)
- 로컬 모드에서 `gateway.auth.*`가 미설정이면 `gateway.remote.*`를 폴백으로 사용 가능; 설정되었지만 해석되지 않은 로컬 SecretRef는 실패 폐쇄
- 적용 가능한 경우 `gateway.remote.*`를 통한 리모트 모드 지원
- URL 재정의는 재정의 안전: CLI 재정의는 암묵적 자격 증명을 재사용하지 않으며 env 재정의는 env 자격 증명만 사용
알 수 없는 승인 ID로 승인이 실패하면 승인자 목록과 기능 활성화를 확인합니다.
관련 문서: [Exec approvals](/docs/tools/exec-approvals)
도구 및 액션 게이트
Discord 메시지 액션에는 메시징, 채널 관리, 모더레이션, 프레즌스, 메타데이터 액션이 포함됩니다.
핵심 예시:
- 메시징:
sendMessage,readMessages,editMessage,deleteMessage,threadReply - 리액션:
react,reactions,emojiList - 모더레이션:
timeout,kick,ban - 프레즌스:
setPresence
액션 게이트는 channels.discord.actions.* 아래에 있습니다.
기본 게이트 동작:
| 액션 그룹 | 기본값 |
|---|---|
| reactions, messages, threads, pins, polls, search, memberInfo, roleInfo, channelInfo, channels, voiceStatus, events, stickers, emojiUploads, stickerUploads, permissions | 활성화 |
| roles | 비활성화 |
| moderation | 비활성화 |
| presence | 비활성화 |
컴포넌트 v2 UI
OpenClaw는 실행 승인 및 크로스 컨텍스트 마커에 Discord 컴포넌트 v2를 사용합니다. Discord 메시지 액션은 사용자 정의 UI를 위한 components도 허용할 수 있으며(고급; Carbon 컴포넌트 인스턴스 필요), 레거시 embeds는 사용 가능하지만 권장되지 않습니다.
channels.discord.ui.components.accentColor는 Discord 컴포넌트 컨테이너에 사용되는 강조 색상을 설정합니다 (hex).- 계정별로
channels.discord.accounts.<id>.ui.components.accentColor로 설정합니다. - 컴포넌트 v2가 있으면
embeds는 무시됩니다.
예시:
{
channels: {
discord: {
ui: {
components: {
accentColor: "#5865F2",
},
},
},
},
}
음성 채널
OpenClaw는 실시간 연속 대화를 위해 Discord 음성 채널에 참가할 수 있습니다. 음성 메시지 첨부와는 별개입니다.
요구 사항:
- 네이티브 명령 활성화 (
commands.native또는channels.discord.commands.native). channels.discord.voice설정.- 봇에 대상 음성 채널의 Connect + Speak 권한 필요.
Discord 전용 네이티브 명령 /vc join|leave|status로 세션을 제어합니다. 이 명령은 계정 기본 에이전트를 사용하며 다른 Discord 명령과 동일한 허용 목록 및 그룹 정책 규칙을 따릅니다.
자동 참가 예시:
{
channels: {
discord: {
voice: {
enabled: true,
autoJoin: [
{
guildId: "123456789012345678",
channelId: "234567890123456789",
},
],
daveEncryption: true,
decryptionFailureTolerance: 24,
tts: {
provider: "openai",
openai: { voice: "alloy" },
},
},
},
},
}
참고:
voice.tts는 음성 재생에만messages.tts를 재정의합니다.- 음성 전사 턴은 Discord
allowFrom(또는dm.allowFrom)에서 소유자 상태를 파생합니다; 비소유자 발화자는 소유자 전용 도구(예:gateway및cron)에 접근할 수 없습니다. - 음성은 기본적으로 활성화됩니다;
channels.discord.voice.enabled=false로 비활성화합니다. voice.daveEncryption및voice.decryptionFailureTolerance는@discordjs/voicejoin 옵션으로 전달됩니다.@discordjs/voice기본값은 미설정 시daveEncryption=true및decryptionFailureTolerance=24입니다.- OpenClaw는 수신 복호화 실패도 모니터링하며 짧은 기간 내 반복 실패 후 음성 채널을 나갔다 다시 참가하여 자동 복구합니다.
- 수신 로그에
DecryptionFailed(UnencryptedWhenPassthroughDisabled)가 반복적으로 표시되면 discord.js #11419에서 추적되는 upstream@discordjs/voice수신 버그일 수 있습니다.
음성 메시지
Discord 음성 메시지는 파형 미리보기를 표시하며 OGG/Opus 오디오와 메타데이터가 필요합니다. OpenClaw는 파형을 자동으로 생성하지만, 오디오 파일을 검사하고 변환하려면 게이트웨이 호스트에 ffmpeg 및 ffprobe가 필요합니다.
요구 사항 및 제약:
- 로컬 파일 경로를 제공합니다 (URL은 거부됨).
- 텍스트 콘텐츠를 생략합니다 (Discord는 동일 페이로드에 텍스트 + 음성 메시지를 허용하지 않음).
- 모든 오디오 형식이 허용됩니다; OpenClaw는 필요 시 OGG/Opus로 변환합니다.
예시:
message(action="send", channel="discord", target="channel:123", path="/path/to/audio.mp3", asVoice=true)
문제 해결
허용되지 않는 인텐트 사용 또는 봇이 길드 메시지를 보지 못함
- Message Content Intent 활성화
- 사용자/멤버 해석에 의존하는 경우 Server Members Intent 활성화
- 인텐트 변경 후 게이트웨이 재시작
길드 메시지가 예상치 못하게 차단됨
- `groupPolicy` 확인
- `channels.discord.guilds`의 길드 허용 목록 확인
- 길드 `channels` 맵이 있으면 나열된 채널만 허용됨
- `requireMention` 동작 및 멘션 패턴 확인
유용한 명령:
openclaw doctor
openclaw channels status --probe
openclaw logs --follow
require mention false이지만 여전히 차단됨
일반적인 원인:
- 일치하는 길드/채널 허용 목록 없이 `groupPolicy="allowlist"`
- 잘못된 위치에 `requireMention` 설정 (`channels.discord.guilds` 또는 채널 항목 아래여야 함)
- 길드/채널 `users` 허용 목록에 의해 발신자 차단
장시간 핸들러 타임아웃 또는 중복 응답
일반적인 로그:
- `Listener DiscordMessageListener timed out after 30000ms for event MESSAGE_CREATE`
- `Slow listener detected ...`
- `discord inbound worker timed out after ...`
리스너 예산 조정:
- 단일 계정: `channels.discord.eventQueue.listenerTimeout`
- 멀티 계정: `channels.discord.accounts.<accountId>.eventQueue.listenerTimeout`
워커 실행 타임아웃 조정:
- 단일 계정: `channels.discord.inboundWorker.runTimeoutMs`
- 멀티 계정: `channels.discord.accounts.<accountId>.inboundWorker.runTimeoutMs`
- 기본: `1800000` (30분); `0`으로 비활성화
권장 기준선:
{
channels: {
discord: {
accounts: {
default: {
eventQueue: {
listenerTimeout: 120000,
},
inboundWorker: {
runTimeoutMs: 1800000,
},
},
},
},
},
}
느린 리스너 설정에는 `eventQueue.listenerTimeout`을, 큐에 넣은 에이전트 턴에 대한 별도 안전 밸브가 필요한 경우에만 `inboundWorker.runTimeoutMs`를 사용합니다.
권한 감사 불일치
`channels status --probe` 권한 검사는 숫자 채널 ID에서만 작동합니다.
슬러그 키를 사용하면 런타임 매칭은 여전히 작동할 수 있지만 프로빙으로 권한을 완전히 확인할 수 없습니다.
DM 및 페어링 문제
- DM 비활성화: `channels.discord.dm.enabled=false`
- DM 정책 비활성화: `channels.discord.dmPolicy="disabled"` (레거시: `channels.discord.dm.policy`)
- `pairing` 모드에서 페어링 승인 대기 중
봇 간 루프
기본적으로 봇이 작성한 메시지는 무시됩니다.
`channels.discord.allowBots=true`를 설정하면 루프 동작을 방지하기 위해 엄격한 멘션 및 허용 목록 규칙을 사용합니다.
봇 메시지 중 봇을 멘션하는 것만 수락하려면 `channels.discord.allowBots="mentions"`를 권장합니다.
DecryptionFailed(...)로 음성 STT 드롭
- OpenClaw를 최신 상태로 유지합니다 (`openclaw update`) - Discord 음성 수신 복구 로직이 포함됨
- `channels.discord.voice.daveEncryption=true` 확인 (기본값)
- `channels.discord.voice.decryptionFailureTolerance=24` (upstream 기본값)에서 시작하고 필요할 때만 조정
- 다음 로그를 확인합니다:
- `discord voice: DAVE decrypt failures detected`
- `discord voice: repeated decrypt failures; attempting rejoin`
- 자동 재참가 후에도 실패가 계속되면 로그를 수집하고 [discord.js #11419](https://github.com/discordjs/discord.js/issues/11419)와 비교합니다
설정 참조 포인터
기본 참조:
주요 Discord 필드:
- 시작/인증:
enabled,token,accounts.*,allowBots - 정책:
groupPolicy,dm.*,guilds.*,guilds.*.channels.* - 명령:
commands.native,commands.useAccessGroups,configWrites,slashCommand.* - 이벤트 큐:
eventQueue.listenerTimeout(리스너 예산),eventQueue.maxQueueSize,eventQueue.maxConcurrency - 인바운드 워커:
inboundWorker.runTimeoutMs - 응답/히스토리:
replyToMode,historyLimit,dmHistoryLimit,dms.*.historyLimit - 전달:
textChunkLimit,chunkMode,maxLinesPerMessage - 스트리밍:
streaming(레거시 별칭:streamMode),draftChunk,blockStreaming,blockStreamingCoalesce - 미디어/재시도:
mediaMaxMb,retrymediaMaxMb는 아웃바운드 Discord 업로드를 제한합니다 (기본:8MB)
- 액션:
actions.* - 프레즌스:
activity,status,activityType,activityUrl - UI:
ui.components.accentColor - 기능:
threadBindings, 최상위bindings[](type: "acp"),pluralkit,execApprovals,intents,agentComponents,heartbeat,responsePrefix
안전 및 운영
- 봇 토큰은 시크릿으로 취급합니다 (관리 환경에서는
DISCORD_BOT_TOKEN권장). - 최소 권한 Discord 권한을 부여합니다.
- 명령 배포/상태가 오래된 경우 게이트웨이를 재시작하고
openclaw channels status --probe로 재확인합니다.