Slack

상태: Slack 앱 통합을 통한 DM + 채널 프로덕션 레벨. 기본 모드는 Socket Mode이며, HTTP Events API 모드도 지원됩니다.

빠른 설정

Socket Mode (기본)

  ### 1단계: Slack 앱 및 토큰 생성
    Slack 앱 설정에서:

    - **Socket Mode** 활성화
    - `connections:write` 권한으로 **App Token** (`xapp-...`) 생성
    - 앱을 설치하고 **Bot Token** (`xoxb-...`) 복사


  ### 2단계: OpenClaw 설정
{
  channels: {
    slack: {
      enabled: true,
      mode: "socket",
      appToken: "xapp-...",
      botToken: "xoxb-...",
    },
  },
}
    환경 변수 폴백 (기본 계정만):
SLACK_APP_TOKEN=xapp-...
SLACK_BOT_TOKEN=xoxb-...
  ### 3단계: 앱 이벤트 구독
    봇 이벤트 구독 대상:

    - `app_mention`
    - `message.channels`, `message.groups`, `message.im`, `message.mpim`
    - `reaction_added`, `reaction_removed`
    - `member_joined_channel`, `member_left_channel`
    - `channel_rename`
    - `pin_added`, `pin_removed`

    또한 App Home **Messages Tab**을 활성화하여 DM을 사용합니다.


  ### 4단계: 게이트웨이 시작
openclaw gateway

HTTP Events API 모드

  ### 1단계: HTTP용 Slack 앱 설정

    - 모드를 HTTP로 설정 (`channels.slack.mode="http"`)
    - Slack **Signing Secret** 복사
    - Event Subscriptions + Interactivity + Slash command Request URL을 동일한 웹훅 경로로 설정 (기본 `/slack/events`)



  ### 2단계: OpenClaw HTTP 모드 설정
{
  channels: {
    slack: {
      enabled: true,
      mode: "http",
      botToken: "xoxb-...",
      signingSecret: "your-signing-secret",
      webhookPath: "/slack/events",
    },
  },
}
  ### 3단계: 멀티 계정 HTTP에 고유 웹훅 경로 사용
    계정별 HTTP 모드가 지원됩니다.

    등록이 충돌하지 않도록 각 계정에 고유한 `webhookPath`를 지정합니다.

토큰 모델

  • Socket Mode에는 botToken + appToken이 필요합니다.
  • HTTP 모드에는 botToken + signingSecret이 필요합니다.
  • 설정 토큰이 환경 변수 폴백보다 우선합니다.
  • SLACK_BOT_TOKEN / SLACK_APP_TOKEN 환경 변수 폴백은 기본 계정에만 적용됩니다.
  • userToken (xoxp-...)은 설정 전용이며 (환경 변수 폴백 없음) 기본적으로 읽기 전용 동작입니다 (userTokenReadOnly: true).
  • 선택 사항: 발신 메시지에 활성 에이전트 ID(사용자 지정 username 및 아이콘)를 사용하려면 chat:write.customize를 추가합니다. icon_emoji:emoji_name: 구문을 사용합니다.

팁: 액션/디렉토리 읽기에는 사용자 토큰이 설정된 경우 우선됩니다. 쓰기에는 봇 토큰이 우선되며, 사용자 토큰 쓰기는 userTokenReadOnly: false이고 봇 토큰이 없을 때만 허용됩니다.

접근 제어 및 라우팅

DM 정책

`channels.slack.dmPolicy`로 DM 접근을 제어합니다 (레거시: `channels.slack.dm.policy`):

- `pairing` (기본값)
- `allowlist`
- `open` (`channels.slack.allowFrom`에 `"*"` 필요; 레거시: `channels.slack.dm.allowFrom`)
- `disabled`

DM 플래그:

- `dm.enabled` (기본값 true)
- `channels.slack.allowFrom` (권장)
- `dm.allowFrom` (레거시)
- `dm.groupEnabled` (그룹 DM 기본값 false)
- `dm.groupChannels` (선택적 MPIM 허용 목록)

멀티 계정 우선순위:

- `channels.slack.accounts.default.allowFrom`은 `default` 계정에만 적용됩니다.
- 이름이 지정된 계정은 자체 `allowFrom`이 미설정이면 `channels.slack.allowFrom`을 상속합니다.
- 이름이 지정된 계정은 `channels.slack.accounts.default.allowFrom`을 상속하지 않습니다.

DM에서의 페어링은 `openclaw pairing approve slack <code>`를 사용합니다.

채널 정책

`channels.slack.groupPolicy`로 채널 처리를 제어합니다:

- `open`
- `allowlist`
- `disabled`

채널 허용 목록은 `channels.slack.channels`에 위치하며 안정적인 채널 ID를 사용해야 합니다.

런타임 참고: `channels.slack`이 완전히 누락된 경우 (환경 변수만 사용하는 설정), `channels.defaults.groupPolicy`가 설정되어 있어도 런타임은 `groupPolicy="allowlist"`로 폴백하고 경고를 기록합니다.

이름/ID 해석:

- 채널 허용 목록 항목과 DM 허용 목록 항목은 토큰 접근이 허용되는 경우 시작 시 해석됨
- 해석되지 않은 채널 이름 항목은 설정대로 유지되지만 기본적으로 라우팅에서 무시됨
- 인바운드 인가 및 채널 라우팅은 기본적으로 ID 우선; 직접 사용자 이름/슬러그 매칭에는 `channels.slack.dangerouslyAllowNameMatching: true` 필요

멘션 및 채널 사용자

채널 메시지는 기본적으로 멘션 게이팅됩니다.

멘션 소스:

- 명시적 앱 멘션 (`<@botId>`)
- 멘션 정규식 패턴 (`agents.list[].groupChat.mentionPatterns`, 폴백 `messages.groupChat.mentionPatterns`)
- 암묵적 봇 답장 스레드 동작

채널별 제어 (`channels.slack.channels.<id>`; 이름은 시작 시 해석 또는 `dangerouslyAllowNameMatching`을 통해서만):

- `requireMention`
- `users` (허용 목록)
- `allowBots`
- `skills`
- `systemPrompt`
- `tools`, `toolsBySender`
- `toolsBySender` 키 형식: `id:`, `e164:`, `username:`, `name:`, 또는 `"*"` 와일드카드
  (레거시 접두사 없는 키는 여전히 `id:`로만 매핑)

명령 및 슬래시 동작

  • Slack에서는 네이티브 명령 자동 모드가 꺼져 있습니다 (commands.native: "auto"는 Slack 네이티브 명령을 활성화하지 않음).
  • channels.slack.commands.native: true (또는 전역 commands.native: true)로 네이티브 Slack 명령 핸들러를 활성화합니다.
  • 네이티브 명령이 활성화되면 Slack에서 일치하는 슬래시 명령 (/<command> 이름)을 등록합니다. 한 가지 예외:
    • 상태 명령에는 /agentstatus를 등록합니다 (Slack이 /status를 예약)
  • 네이티브 명령이 활성화되지 않은 경우 channels.slack.slashCommand를 통해 단일 설정 슬래시 명령을 실행할 수 있습니다.
  • 네이티브 인수 메뉴는 렌더링 전략을 자동으로 조정합니다:
    • 5개까지: 버튼 블록
    • 6-100개: 정적 선택 메뉴
    • 100개 초과: 인터랙티비티 옵션 핸들러가 사용 가능할 때 비동기 옵션 필터링이 있는 외부 선택
    • 인코딩된 옵션 값이 Slack 제한을 초과하면 버튼으로 폴백
  • 긴 옵션 페이로드의 경우, 슬래시 명령 인수 메뉴는 선택된 값을 디스패치하기 전에 확인 대화상자를 사용합니다.

인터랙티브 응답

Slack은 에이전트가 작성한 인터랙티브 응답 컨트롤을 렌더링할 수 있지만, 이 기능은 기본적으로 비활성화되어 있습니다.

전역 활성화:

{
  channels: {
    slack: {
      capabilities: {
        interactiveReplies: true,
      },
    },
  },
}

또는 하나의 Slack 계정에만 활성화:

{
  channels: {
    slack: {
      accounts: {
        ops: {
          capabilities: {
            interactiveReplies: true,
          },
        },
      },
    },
  },
}

활성화되면 에이전트가 Slack 전용 응답 디렉티브를 생성할 수 있습니다:

  • [[slack_buttons: Approve:approve, Reject:reject]]
  • [[slack_select: Choose a target | Canary:canary, Production:production]]

이 디렉티브들은 Slack Block Kit으로 컴파일되며 클릭이나 선택은 기존 Slack 인터랙션 이벤트 경로를 통해 라우팅됩니다.

참고:

  • Slack 전용 UI입니다. 다른 채널은 Slack Block Kit 디렉티브를 자체 버튼 시스템으로 변환하지 않습니다.
  • 인터랙티브 콜백 값은 OpenClaw가 생성한 불투명 토큰이며, 에이전트가 작성한 원시 값이 아닙니다.
  • 생성된 인터랙티브 블록이 Slack Block Kit 제한을 초과하면 OpenClaw는 유효하지 않은 블록 페이로드 대신 원본 텍스트 응답으로 폴백합니다.

기본 슬래시 명령 설정:

  • enabled: false
  • name: "openclaw"
  • sessionPrefix: "slack:slash"
  • ephemeral: true

슬래시 세션은 격리된 키를 사용합니다:

  • agent:<agentId>:slack:slash:<userId>

그리고 대상 대화 세션 (CommandTargetSessionKey)에 대해 명령 실행을 라우팅합니다.

스레딩, 세션, 응답 태그

  • DM은 direct, 채널은 channel, MPIM은 group으로 라우팅됩니다.
  • 기본 session.dmScope=main에서 Slack DM은 에이전트 메인 세션으로 통합됩니다.
  • 채널 세션: agent:<agentId>:slack:channel:<channelId>.
  • 스레드 응답은 해당하는 경우 스레드 세션 접미사 (:thread:<threadTs>)를 생성할 수 있습니다.
  • channels.slack.thread.historyScope의 기본값은 thread; thread.inheritParent의 기본값은 false.
  • channels.slack.thread.initialHistoryLimit은 새 스레드 세션 시작 시 가져올 기존 스레드 메시지 수를 제어합니다 (기본 20; 0으로 비활성화).

응답 스레딩 제어:

  • channels.slack.replyToMode: off|first|all (기본 off)
  • channels.slack.replyToModeByChatType: direct|group|channel
  • 다이렉트 채팅의 레거시 폴백: channels.slack.dm.replyToMode

수동 응답 태그 지원:

  • [[reply_to_current]]
  • [[reply_to:<id>]]

참고: replyToMode="off"는 명시적 [[reply_to_*]] 태그를 포함하여 Slack의 모든 응답 스레딩을 비활성화합니다. 이는 "off" 모드에서도 명시적 태그가 적용되는 Telegram과 다릅니다. 이 차이는 플랫폼 스레딩 모델을 반영합니다: Slack 스레드는 채널에서 메시지를 숨기지만, Telegram 응답은 메인 채팅 흐름에 표시됩니다.

미디어, 청킹, 전달

인바운드 첨부 파일
Slack 파일 첨부는 Slack 호스팅 비공개 URL(토큰 인증 요청 흐름)에서 다운로드되며, 가져오기가 성공하고 크기 제한이 허용되면 미디어 저장소에 기록됩니다.

런타임 인바운드 크기 상한은 `channels.slack.mediaMaxMb`로 재정의하지 않는 한 기본 `20MB`입니다.
아웃바운드 텍스트 및 파일
- 텍스트 청크는 `channels.slack.textChunkLimit` (기본 4000) 사용
- `channels.slack.chunkMode="newline"`은 단락 우선 분할 활성화
- 파일 전송은 Slack 업로드 API를 사용하며 스레드 응답 포함 가능 (`thread_ts`)
- 아웃바운드 미디어 상한은 설정된 경우 `channels.slack.mediaMaxMb`를 따르며, 그렇지 않으면 미디어 파이프라인의 MIME 종류 기본값을 사용
전달 대상
권장 명시적 대상:

- DM의 경우 `user:<id>`
- 채널의 경우 `channel:<id>`

Slack DM은 사용자 대상에게 전송할 때 Slack 대화 API를 통해 열립니다.

액션 및 게이트

Slack 액션은 channels.slack.actions.*로 제어됩니다.

현재 Slack 도구의 사용 가능한 액션 그룹:

그룹기본값
messages활성화
reactions활성화
pins활성화
memberInfo활성화
emojiList활성화

이벤트 및 운영 동작

  • 메시지 편집/삭제/스레드 브로드캐스트는 시스템 이벤트로 매핑됩니다.
  • 리액션 추가/제거 이벤트는 시스템 이벤트로 매핑됩니다.
  • 멤버 참가/탈퇴, 채널 생성/이름 변경, 핀 추가/제거 이벤트는 시스템 이벤트로 매핑됩니다.
  • 어시스턴트 스레드 상태 업데이트 (스레드의 “입력 중…” 표시기)는 assistant.threads.setStatus를 사용하며 봇 스코프 assistant:write가 필요합니다.
  • configWrites가 활성화되면 channel_id_changed가 채널 설정 키를 마이그레이션할 수 있습니다.
  • 채널 토픽/목적 메타데이터는 신뢰할 수 없는 컨텍스트로 취급되며 라우팅 컨텍스트에 주입될 수 있습니다.
  • 블록 액션 및 모달 인터랙션은 풍부한 페이로드 필드가 포함된 구조화된 Slack interaction: ... 시스템 이벤트를 생성합니다:
    • 블록 액션: 선택된 값, 라벨, 피커 값, workflow_* 메타데이터
    • view_submissionview_closed 모달 이벤트(라우팅된 채널 메타데이터 및 폼 입력 포함)

수신 확인 리액션

ackReaction은 OpenClaw가 인바운드 메시지를 처리하는 동안 확인 이모지를 전송합니다.

해석 순서:

  • channels.slack.accounts.<accountId>.ackReaction
  • channels.slack.ackReaction
  • messages.ackReaction
  • 에이전트 ID 이모지 폴백 (agents.list[].identity.emoji, 없으면 ”👀”)

참고:

  • Slack은 숏코드를 사용합니다 (예: "eyes").
  • ""를 사용하여 Slack 계정 또는 전역에서 리액션을 비활성화합니다.

입력 중 리액션 폴백

typingReaction은 OpenClaw가 응답을 처리하는 동안 인바운드 Slack 메시지에 임시 리액션을 추가하고, 실행이 완료되면 제거합니다. Slack 네이티브 어시스턴트 입력이 사용 불가능할 때, 특히 DM에서 유용한 폴백입니다.

해석 순서:

  • channels.slack.accounts.<accountId>.typingReaction
  • channels.slack.typingReaction

참고:

  • Slack은 숏코드를 사용합니다 (예: "hourglass_flowing_sand").
  • 리액션은 최선의 노력으로 처리되며 응답 또는 실패 경로 완료 후 자동으로 정리가 시도됩니다.

매니페스트 및 스코프 체크리스트

Slack 앱 매니페스트 예시
{
  "display_information": {
    "name": "OpenClaw",
    "description": "Slack connector for OpenClaw"
  },
  "features": {
    "bot_user": {
      "display_name": "OpenClaw",
      "always_online": false
    },
    "app_home": {
      "messages_tab_enabled": true,
      "messages_tab_read_only_enabled": false
    },
    "slash_commands": [
      {
        "command": "/openclaw",
        "description": "Send a message to OpenClaw",
        "should_escape": false
      }
    ]
  },
  "oauth_config": {
    "scopes": {
      "bot": [
        "chat:write",
        "channels:history",
        "channels:read",
        "groups:history",
        "im:history",
        "im:read",
        "im:write",
        "mpim:history",
        "mpim:read",
        "mpim:write",
        "users:read",
        "app_mentions:read",
        "assistant:write",
        "reactions:read",
        "reactions:write",
        "pins:read",
        "pins:write",
        "emoji:read",
        "commands",
        "files:read",
        "files:write"
      ]
    }
  },
  "settings": {
    "socket_mode_enabled": true,
    "event_subscriptions": {
      "bot_events": [
        "app_mention",
        "message.channels",
        "message.groups",
        "message.im",
        "message.mpim",
        "reaction_added",
        "reaction_removed",
        "member_joined_channel",
        "member_left_channel",
        "channel_rename",
        "pin_added",
        "pin_removed"
      ]
    }
  }
}
선택적 사용자 토큰 스코프 (읽기 작업)
`channels.slack.userToken`을 설정하는 경우 일반적인 읽기 스코프:

- `channels:history`, `groups:history`, `im:history`, `mpim:history`
- `channels:read`, `groups:read`, `im:read`, `mpim:read`
- `users:read`
- `reactions:read`
- `pins:read`
- `emoji:read`
- `search:read` (Slack 검색 읽기에 의존하는 경우)

문제 해결

채널에서 응답 없음
다음 순서로 확인합니다:

- `groupPolicy`
- 채널 허용 목록 (`channels.slack.channels`)
- `requireMention`
- 채널별 `users` 허용 목록

유용한 명령:
openclaw channels status --probe
openclaw logs --follow
openclaw doctor
DM 메시지 무시됨
확인 사항:

- `channels.slack.dm.enabled`
- `channels.slack.dmPolicy` (또는 레거시 `channels.slack.dm.policy`)
- 페어링 승인 / 허용 목록 항목
openclaw pairing list slack
Socket 모드 연결 안 됨
Slack 앱 설정에서 봇 + 앱 토큰과 Socket Mode 활성화를 확인합니다.
HTTP 모드에서 이벤트 수신 안 됨
확인 사항:

- signing secret
- 웹훅 경로
- Slack Request URL (Events + Interactivity + Slash Commands)
- HTTP 계정별 고유 `webhookPath`
네이티브/슬래시 명령이 작동하지 않음
의도한 것이 무엇인지 확인합니다:

- Slack에 일치하는 슬래시 명령이 등록된 네이티브 명령 모드 (`channels.slack.commands.native: true`)
- 또는 단일 슬래시 명령 모드 (`channels.slack.slashCommand.enabled: true`)

`commands.useAccessGroups` 및 채널/사용자 허용 목록도 확인합니다.

텍스트 스트리밍

OpenClaw은 Agents and AI Apps API를 통해 Slack 네이티브 텍스트 스트리밍을 지원합니다.

channels.slack.streaming으로 실시간 미리보기 동작을 제어합니다:

  • off: 실시간 미리보기 스트리밍 비활성화.
  • partial (기본값): 미리보기 텍스트를 최신 부분 출력으로 교체.
  • block: 청크 단위 미리보기 업데이트를 추가.
  • progress: 생성 중 진행 상태 텍스트를 표시한 후 최종 텍스트를 전송.

channels.slack.nativeStreamingstreamingpartial일 때 Slack의 네이티브 스트리밍 API (chat.startStream / chat.appendStream / chat.stopStream)를 제어합니다 (기본값: true).

네이티브 Slack 스트리밍 비활성화 (초안 미리보기 동작 유지):

channels:
  slack:
    streaming: partial
    nativeStreaming: false

레거시 키:

  • channels.slack.streamMode (replace | status_final | append)는 channels.slack.streaming으로 자동 마이그레이션됩니다.
  • 불리언 channels.slack.streamingchannels.slack.nativeStreaming으로 자동 마이그레이션됩니다.

요구 사항

  1. Slack 앱 설정에서 Agents and AI Apps를 활성화합니다.
  2. 앱에 assistant:write 스코프가 있는지 확인합니다.
  3. 해당 메시지에 사용 가능한 응답 스레드가 있어야 합니다. 스레드 선택은 여전히 replyToMode를 따릅니다.

동작

  • 첫 번째 텍스트 청크가 스트림을 시작합니다 (chat.startStream).
  • 이후 텍스트 청크가 동일한 스트림에 추가됩니다 (chat.appendStream).
  • 응답 종료 시 스트림을 완료합니다 (chat.stopStream).
  • 미디어 및 비텍스트 페이로드는 일반 전달로 폴백합니다.
  • 응답 중 스트리밍이 실패하면 OpenClaw는 나머지 페이로드에 대해 일반 전달로 폴백합니다.

설정 참조 포인터

기본 참조:

  • Configuration reference - Slack

    주요 Slack 필드:

    • 모드/인증: mode, botToken, appToken, signingSecret, webhookPath, accounts.*
    • DM 접근: dm.enabled, dmPolicy, allowFrom (레거시: dm.policy, dm.allowFrom), dm.groupEnabled, dm.groupChannels
    • 호환성 토글: dangerouslyAllowNameMatching (비상 모드; 필요하지 않으면 끄기)
    • 채널 접근: groupPolicy, channels.*, channels.*.users, channels.*.requireMention
    • 스레딩/히스토리: replyToMode, replyToModeByChatType, thread.*, historyLimit, dmHistoryLimit, dms.*.historyLimit
    • 전달: textChunkLimit, chunkMode, mediaMaxMb, streaming, nativeStreaming
    • 운영/기능: configWrites, commands.native, slashCommand.*, actions.*, userToken, userTokenReadOnly

관련 문서