English | 한국어
터미널에서 Slack 주요 워크플로를 빠르게 처리하세요. 메시지 전송, 검색, 리액션, 핀, 북마크, 사용자/채널 조회를 브라우저 없이 수행할 수 있습니다.
- 빠름 — SQLite FTS5 기반 밀리초 단위 검색
- 실용적 — 메시지, 검색, 리액션, 핀, 북마크, 사용자/채널 조회 지원
- 자동화 — 스크립트, CI/CD, AI 에이전트와 통합 가능
# 설치
curl -fsSL https://raw.githubusercontent.com/junyeong-ai/slack-cli/main/scripts/install.sh | bash
# 로그인 (브라우저 OAuth)
slack-cli auth login --client-id <your-client-id>
# 또는 기존 토큰을 붙여넣기
slack-cli auth login --user-token xoxp-your-token
# 사용
slack-cli cache refresh
slack-cli users "john"
slack-cli send "#general" -t "Hello!"#name · name (대소문자를 무시한 유일한 정확한 캐시 이름) · C…/G… 채널 ID · D… DM ID · U…/W… 유저 ID (실제 작업 토큰으로 접근 가능한 기존 DM을 조회하며, DM을 새로 만들지 않음)
slack-cli send "#general" -t "공지사항입니다" # 전송 (텍스트)
slack-cli send "#general" --markdown-text "**볼드**" # 전송 (표준 Markdown, Slack이 렌더링)
slack-cli send U123ABCDEF -t "DM by user-id" # 유저 ID → DM 자동 해석
slack-cli send "#general" -b @blocks.json -t "fallback" # Block Kit + 폴백 텍스트
slack-cli send "#general" -m @meta.json -t "deploy done" # 추적용 metadata 첨부
echo '{"event_type":"x","event_payload":{}}' | slack-cli send "#general" -t "x" -m -
slack-cli update "#general" 1234.5678 -t "수정됨" # 수정 (text/markdown_text/blocks/attachments/metadata)
slack-cli delete "#general" 1234.5678 # 삭제
slack-cli permalink "#general" 1234.5678 # permalink URL 조회
slack-cli messages "#general" --limit 15 # 조회 (lean 기본 필드)
slack-cli messages "#general" --expand blocks,reactions # 필드 확장
slack-cli messages "#general" --oldest 2025-01-01 --latest 2025-01-31
slack-cli messages "#general" --exclude-bots # 봇 메시지 제외
slack-cli messages "#general" --cursor <next_cursor> # 다음 페이지 (JSON 출력의 next_cursor)
slack-cli thread "#general" 1234.5678 # 스레드
slack-cli search "키워드" --sort timestamp # Real-time SearchJSON 입력: --blocks / --attachments / --metadata는 세 가지 입력 형태를 지원합니다.
| 형식 | 의미 |
|---|---|
- |
stdin 에서 읽기 (한 호출에 최대 1회) |
@path.json |
파일에서 읽기 |
| 그 외 | inline JSON 리터럴 |
slack-cli react "#general" 1234.5678 thumbsup # 추가
slack-cli unreact "#general" 1234.5678 thumbsup # 제거
slack-cli reactions "#general" 1234.5678 # 조회slack-cli pin "#general" 1234.5678 # 핀 추가
slack-cli unpin "#general" 1234.5678 # 핀 제거
slack-cli pins "#general" # 핀 목록
slack-cli bookmark "#general" "Wiki" "https://..." # 북마크 추가
slack-cli bookmarks "#general" # 북마크 목록slack-cli users "john" --limit 10 # 사용자 검색
slack-cli users --id U123,U456 # ID로 조회
slack-cli users "john" --expand avatar,title # 추가 필드 포함
slack-cli channels "dev" # 채널 검색
slack-cli channels --id C123,C456 # ID로 조회
slack-cli channels "dev" --expand topic,purpose # 추가 필드 포함
slack-cli members "#dev-team" # 멤버 목록
slack-cli emoji --query "party" # 이모지 검색slack-cli auth login # 새 워크스페이스 로그인 (기본: PKCE)
slack-cli auth login --method static --user-token xoxp-... # 토큰 붙여넣기
slack-cli auth scopes # 앱에 등록할 scope 확인
slack-cli auth profiles # 저장된 프로필 목록
slack-cli auth status --verify # 활성 프로필 검증
slack-cli auth use work # 활성 프로필 전환
slack-cli auth logout # 활성 프로필 제거
slack-cli --profile work users "john" # 특정 프로필로 1회 호출
slack-cli cache stats # 캐시 상태
slack-cli cache refresh # 캐시 새로고침
slack-cli config show # 설정 표시curl -fsSL https://raw.githubusercontent.com/junyeong-ai/slack-cli/main/scripts/install.sh | bash설치·제거 스크립트에는 Bash와 core Fcntl을 포함한 Perl이 필요합니다. 사전 빌드 다운로드에는 curl, tar, SHA-256 도구(sha256sum 또는 shasum)도 필요합니다. 같은 사용자의 설치·제거 실행은 같은 커널 잠금으로 직렬화합니다.
install.sh는 GitHub Release의 사전 빌드 바이너리를 내려받아 SHA-256 체크섬을 검증하고, cosign이 설치돼 있으면 sigstore 서명까지 검증한 뒤 ~/.local/bin/slack-cli에 설치합니다. Linux에서는 glibc/musl을 자동 감지합니다. 같은 실행 안에서 Claude Code 스킬도 ~/.claude/skills/slack-workspace에 설치할 수 있으므로 저장소를 clone할 필요가 없습니다. 스킬은 설치한 바이너리와 같은 버전의 태그에서 가져오며, 소스 빌드에서는 같은 버전의 로컬 스킬을 사용합니다. 일치하는 스킬이 없으면 기존 설치본을 유지합니다. 교체 전에는 사용자 추가 파일을 포함한 기존 스킬 폴더 전체를 ~/.claude/skills 바깥에 보관하고 경로를 알려줍니다. 백업에 실패하면 기존 스킬을 유지합니다. SKILL.md가 없거나 기존 경로가 파일·깨진 심볼릭 링크여도 교체 전에 보존합니다.
# 특정 릴리스 설치
curl -fsSL https://raw.githubusercontent.com/junyeong-ai/slack-cli/main/scripts/install.sh | SLACK_CLI_VERSION=v0.5.0 bash
# 제거 (비대화형 기본값은 바이너리만 제거하고 스킬/설정은 보존)
curl -fsSL https://raw.githubusercontent.com/junyeong-ai/slack-cli/main/scripts/uninstall.sh | bash
# 스킬과 설정까지 제거
curl -fsSL https://raw.githubusercontent.com/junyeong-ai/slack-cli/main/scripts/uninstall.sh | bash -s -- --yescargo install --locked --git https://github.com/junyeong-ai/slack-cligit clone https://github.com/junyeong-ai/slack-cli && cd slack-cli
cargo build --release --locked # rust-toolchain.toml이 1.99.1 툴체인을 자동 선택요구사항: Rust 1.98.0+ (rustup). 저장소 빌드는 1.99.1을 사용합니다.
slack-cli는 토큰을 auth.json에 저장하며(Unix에서는 0600, 상위 디렉터리 0700 — Windows에서는 %APPDATA%의 기본 ACL에 의존), 워크스페이스마다 명명된 프로필로 관리합니다. config.toml에는 사용자·봇 토큰이 들어가지 않습니다. 같은 디렉터리의 빈 auth.json.lock은 동시 실행을 직렬화하는 잠금 파일이며 내용이 없습니다.
필요한 scope는 CLI가 호출하는 Slack 메서드에서 그대로 파생되므로, 언제든 아래로 확인할 수 있습니다.
slack-cli auth scopes # 앱에 등록할 scope 목록slack-cli auth login --method pkce --client-id <client-id>
# 또는 환경변수
SLACK_CLI_CLIENT_ID=<client-id> slack-cli auth login --method pkceauth login이 로컬 콜백 서버를 127.0.0.1:53682(--port로 변경)에 잠깐 띄우고, 브라우저로 Slack 인증 페이지를 열어 코드를 받아 user token을 발급받습니다. 포트는 앱에 등록한 Redirect URL과 정확히 같아야 합니다. 터미널에서 실행할 때만 브라우저를 열고, 그 외(스크립트·CI)에는 URL을 출력합니다 — --no-browser로 항상 출력하게 할 수 있습니다. 사전 준비:
- api.slack.com/apps에서 앱 생성
- OAuth & Permissions → User Token Scopes에 아래 항목 추가
- OAuth & Permissions → Redirect URLs에
http://127.0.0.1:53682/callback등록 - OAuth & Permissions → PKCE 활성화 후 Basic Information에서 client_id 복사
PKCE 활성화는 앱을 public client로 표시하며 되돌릴 수 없습니다(해제하려면 Slack 지원 문의). PKCE 앱의 loopback 리다이렉트는 데스크톱 리다이렉트로 처리되어 bot scope를 요청할 수 없고, 발급 토큰은 항상 12시간마다 회전합니다. CLI가 refresh token으로 자동 갱신하므로 재로그인은 필요 없습니다.
User Token Scopes (전체 기능 사용 시):
bookmarks:read bookmarks:write channels:history channels:read
chat:write emoji:read groups:history groups:read
im:history im:read mpim:history mpim:read
pins:read pins:write reactions:read reactions:write
search:read.files search:read.im search:read.mpim search:read.private
search:read.public search:read.users users:read users:read.email
기존 발급된 xoxp- / xoxb- 토큰이 있을 때:
slack-cli auth login --method static --user-token xoxp-your-token
# 봇 토큰을 함께 등록
slack-cli auth login --method static --user-token xoxp-... --bot-token xoxb-...auth.test로 토큰을 검증한 뒤 프로필이 저장됩니다. 붙여넣은 토큰은 만료·갱신 메타데이터 없이 저장되며 자동 갱신되지 않습니다. Slack에서 만료되거나 폐기되면 새 토큰으로 교체하세요.
Bot Token Scopes (--bot-token으로 봇 토큰을 함께 등록할 때):
bookmarks:read bookmarks:write channels:history channels:read
chat:write emoji:read groups:history groups:read
im:history im:read metadata.message:read mpim:history
mpim:read pins:read pins:write reactions:read
reactions:write search:read.public users:read users:read.email
Slack은 PKCE 설치에 항상 만료 시각과 refresh token을 함께 발급합니다. CLI가 만료 2시간 전부터 oauth.v2.access로 자동 갱신합니다. 갱신은 auth.json에 대한 프로세스 간 잠금 아래에서 수행되므로, 동시에 실행된 여러 호출이 이미 소진된 refresh token을 다시 쓰는 일이 없습니다.
slack-cli auth status # 토큰별 만료 시각과 갱신 가능 여부slack-cli auth profiles # 목록
slack-cli auth status --verify # 활성 프로필 + auth.test 검증
slack-cli auth use work # 활성 프로필 전환
slack-cli --profile work users "john" # 1회 호출에만 다른 프로필 사용
slack-cli auth logout # 활성 프로필 제거
slack-cli auth logout --all # 모든 프로필 제거--profile NAME은 글로벌 플래그로 어느 위치에도 둘 수 있습니다.
SLACK_USER_TOKEN과 SLACK_BOT_TOKEN은 --profile보다 우선합니다. 저장된 프로필을 사용하려면 두 환경 변수를 해제하세요. SLACK_APP_TOKEN은 독립적으로 적용됩니다.
auth status --verify --json은 저장된 프로필을 확인합니다. 검증 실패는 종료 코드가 0이어도 verified.error에 표시되며, 저장된 프로필이 없으면 {profiles: []}를 반환합니다. 환경 토큰의 유효성을 확인하는 명령은 아닙니다.
정적 로그인은 전달된 user/bot 토큰을 모두 검증하고 같은 워크스페이스인지 확인합니다. 로그아웃은 실행 시 선택된 인증만 제거하며, 동시에 새로 로그인한 인증은 보존합니다.
캐시는 프로필의 인증별로 분리됩니다. 재로그인은 새 캐시를 사용하고 토큰 자동 갱신은 기존 캐시를 유지합니다. 환경 토큰도 별도 캐시를 사용합니다. --data-dir는 캐시들의 루트이며, cache path로 선택된 DB 경로를 확인합니다. 이전 공용 캐시는 가져오지 않습니다. 정상적인 빈 응답도 기존 스냅샷을 비우고 캐시합니다.
slack-cli self update # 최신 릴리스로 교체 (확인 프롬프트)
slack-cli self update --check # 새 버전 유무만 확인
slack-cli self update --yes # 프롬프트 없이
slack-cli self update --force # 선택 버전이 설치돼 있어도 재설치
slack-cli self update --version 0.9.0 # 특정 버전으로릴리스에 게시된 실행 파일 자체를 내려받아 SHA-256을 반드시 검증합니다. cosign이 설치돼 있으면 sigstore 서명도 검증하며, 이때 인증서는 해당 태그의 릴리스 워크플로로 고정되므로 다른 릴리스의 정상 서명본을 이 릴리스 이름으로 올려두는 대체도 거부됩니다. cosign이 있는데 서명이 없는 릴리스는 설치를 거부합니다 — 체크섬은 바이너리를 올린 쪽이 함께 만들 수 있으므로 출처를 증명하지 않습니다. cosign이 없으면 체크섬만으로 신뢰하며 그 사실을 알립니다.
교체는 같은 디렉터리에 스테이징한 뒤 rename 하므로, 중간에 실패해도 반쯤 쓰인 바이너리가 남지 않습니다.
~/.local/bin처럼 쓰기 권한이 있는 위치에 설치된 경우에 동작합니다. 시스템 경로에 설치했다면 install.sh를 다시 실행하세요.
실행 파일 자산은 v0.9.0부터 게시되므로, --version으로 그 이전 릴리스를 지정하면 해당 자산이 없다는 안내와 함께 거부됩니다 — 그 경우 install.sh를 사용하세요.
config.toml (사용자 환경설정. 사용자·봇 토큰은 들어가지 않습니다 — 그건 auth.json이 관리합니다). 경로는 플랫폼 규약을 따릅니다 — Linux/macOS는 $XDG_CONFIG_HOME/slack-cli 또는 ~/.config/slack-cli, Windows는 %APPDATA%\slack-cli. 실제 경로는 slack-cli config path로 확인하세요.
[auth]
client_id = "1234.5678" # 브라우저 로그인이 인가받을 앱 (= --client-id)
exclude_scopes = [] # 워크스페이스가 허용하지 않는 scope (아래 참조)
[cache]
ttl_users_hours = 168 # 1주일
ttl_channels_hours = 168
refresh_threshold_percent = 10 # TTL의 10% 시점부터 stale 경고
channel_types = ["public_channel", "private_channel"]
# 캐시할 conversation 타입.
# 토큰 scope에 맞춰 조정 (public만 있으면 ["public_channel"]).
# 허용 값: public_channel, private_channel, mpim, im
[output]
users_fields = ["id", "name", "real_name", "email"]
channels_fields = ["id", "name", "type", "members"]
messages_fields = ["ts", "user", "bot_id", "username", "text", "thread_ts", "reply_count", "subtype", "metadata"]
[connection]
api_base_url = "https://slack.com/api"
rate_limit_per_minute = 20
app_distribution = "commercial_external"
timeout_seconds = 30
[retry]
max_attempts = 3 # 429 재시도 횟수 (Retry-After 우선)
initial_delay_ms = 1000 # Retry-After 헤더가 없을 때의 최초 백오프
max_delay_ms = 60000
exponential_base = 2.0
[events]
mode = "spool" # stream | spool | archive — 이벤트를 얼마나 오래 보관할지
store_body = false # false면 참조만 저장 (본문·원본 payload 제외)
store_raw = false # true면 Slack 원본 payload를 이벤트에 실음 (룰 작성용)
retention_days = 7 # archive 모드의 보관 기간, spool 모드의 안전 상한
buffer = 1024 # 처리 대기 큐 크기
on_overflow = "drop_oldest" # drop_oldest | drop_newest (버림은 항상 카운트됨)
max_bytes = 268435456 # 이벤트 로그의 실데이터 상한 (256MiB, 최소 1MiB)
backfill = true # 재연결 시 놓친 메시지 복구
backfill_max_channels = 20 # 복구 대상 채널 수 상한
backfill_max_age_hours = 24 # 복구가 거슬러 올라가는 한계 (커서가 더 오래됐으면 여기서부터 읽고 경고)
# data_path = "~/other/place" # 이벤트 저장소 위치 (기본: 설정 디렉터리의 events/)
[[events.sink]]
name = "agent"
type = "stdout" # stdout | exec | http
# exec/http는 push, `events pull`은 pull입니다.
# 둘 다 쓰면 같은 이벤트가 두 번 전달됩니다.
[[events.rule]]
name = "mention"
on = ["message"]
mentions_me = true
[[events.rule]]
name = "watched-thread"
on = ["message", "reaction_added", "reaction_removed"]
subscribe_emoji = "eyes" # 내가 :eyes: 를 찍은 스레드의 답글을 추적알 수 없는 키는 무시되지 않고 오류로 처리됩니다 — 이전 버전의 잔여 키(user_token, bot_token, max_idle_per_host, pool_idle_timeout_seconds)가 있으면 명시적 에러로 표면화되니 제거하세요.
app_distribution은 Slack의 conversations.history/conversations.replies 제한 정책에 맞춥니다. Slack Marketplace 승인 앱 또는 내부 고객 제작 앱이면 marketplace_or_internal로 설정할 수 있습니다.
[auth]의 우선순위는 명령행 플래그 > 환경변수 > config.toml 입니다. client_id를 여기 두면 auth login에 매번 플래그나 환경변수를 붙일 필요가 없습니다.
exclude_scopes는 앱이나 워크스페이스가 허용하지 않는 scope를 인가 요청에서 뺍니다. Slack은 scope 집합을 통째로 승인하므로, 등록할 수 없는 scope가 하나라도 섞이면 로그인 전체가 거부됩니다. 항목은 CLI가 원래 요청하는 scope여야 하며, 아닌 이름은 설정 로드 시점에 거부됩니다. auth scopes는 제외를 반영한 실효 목록을 출력하므로 그대로 앱에 등록하면 됩니다.
제외한 scope가 필요한 명령은 Slack이 거부하고, CLI가 어느 scope였는지 알려줍니다 — Slack API error: missing_scope. bookmarks.list needs bookmarks:read; the token in use was not granted it.
| 변수 | 용도 |
|---|---|
SLACK_USER_TOKEN |
저장된 프로필을 무시하고 이 토큰을 직접 사용 (CI/headless) |
SLACK_BOT_TOKEN |
위와 동일, bot 토큰 |
SLACK_APP_TOKEN |
Socket Mode 연결에 쓸 현재 유효한 app-level 액세스 토큰 (xapp- 또는 xoxe.xapp-). 필요한 갱신은 외부에서 관리합니다. 저장된 user/bot 토큰을 대체하지 않습니다. SLACK_USER_TOKEN으로 실행하면 이벤트는 프로필이 아니라 env 네임스페이스에 저장됩니다 |
SLACK_PROFILE |
활성 프로필 1회 override (= 글로벌 --profile) |
SLACK_CLI_CLIENT_ID |
브라우저 로그인 시 client_id (= --client-id, config.toml [auth]보다 우선) |
RUST_LOG |
로그 필터 (예: debug, slack_cli::cache=debug). 설정 시 --verbose보다 우선 |
작업 디렉터리에 .env 파일이 있으면 위 변수들을 거기서 읽습니다.
| 명령어 | 설명 |
|---|---|
auth login |
워크스페이스 인증 (--method pkce|static) |
auth logout [--all] |
프로필 제거 (--keep-remote로 auth.revoke 생략) |
auth status [--verify] |
프로필 상태 + 선택적 토큰 검증 |
auth profiles |
저장된 프로필 목록 |
auth use <name> |
활성 프로필 전환 |
auth scopes |
앱에 등록할 OAuth scope 출력 |
users <query> |
사용자 검색 |
users --id <ids> |
ID로 조회 (쉼표 구분) |
channels <query> |
채널 검색 |
channels --id <ids> |
ID로 조회 (쉼표 구분) |
send <ch> [-t -b -a -m --markdown-text --thread] |
메시지 전송 (content 필드 ≥1 필수) |
update <ch> <ts> [-t -b -a -m --markdown-text] |
메시지 수정 (content 필드 ≥1 필수) |
delete <ch> <ts> |
메시지 삭제 |
permalink <ch> <ts> |
메시지 permalink URL 조회 |
messages <ch> |
메시지 조회 |
thread <ch> <ts> |
스레드 조회 |
members <ch> |
멤버 목록 |
search <query> |
Real-time Search API 검색 |
search --capabilities |
워크스페이스의 시맨틱 검색 가용 여부 |
react <ch> <ts> <emoji> |
리액션 추가 |
unreact <ch> <ts> <emoji> |
리액션 제거 |
reactions <ch> <ts> |
리액션 조회 |
emoji |
이모지 목록 |
pin <ch> <ts> |
핀 추가 |
unpin <ch> <ts> |
핀 제거 |
pins <ch> |
핀 목록 |
bookmark <ch> <title> <url> |
북마크 추가 |
unbookmark <ch> <id> |
북마크 제거 |
bookmarks <ch> |
북마크 목록 |
watch |
매칭 이벤트를 stdout으로 스트리밍 (저장 없음, 설정된 싱크도 무시) |
daemon run |
Socket Mode 데몬을 포그라운드로 실행 |
daemon status |
데몬이 실행 중인지(락으로 판단), 마지막 하트비트와 카운터 |
daemon stop |
현재 프로필의 데몬에 정상 종료 요청 |
events pull [--consumer --ack --follow] |
아직 ack하지 않은 이벤트 읽기 |
events ack --through <seq> |
소비자 위치 전진 |
events stats |
이벤트 로그 크기·보존·소비자 지연 |
events prune |
보존 정책 즉시 적용 |
events path |
데몬 파일 위치 |
cache stats/refresh/path |
캐시 관리 및 현재 데이터베이스 경로 |
config show/path/edit |
설정 관리 |
self update |
최신 릴리스로 이 바이너리를 교체 |
self update --check |
업데이트 유무만 확인 (교체하지 않음) |
--json— JSON 출력--profile <name>— 1회 호출에 사용할 프로필 (env:SLACK_PROFILE)--config <path>— config.toml 경로 override. 지정한 파일이 없으면 기본값으로 넘어가지 않고 오류입니다--data-dir <path>— 프로필별 캐시를 담는 루트 디렉터리 지정. 현재 데이터베이스 경로는cache path로 확인--verbose— debug 로그 활성
--limit <N>— 결과 제한 (기본:10)--id <ids>— ID로 조회 (쉼표 구분)--expand <fields>— 기본 필드 외 추가로 노출할 필드- users:
display_name,status,status_emoji,avatar,title,timezone,is_admin,is_bot,deleted - channels:
topic,purpose,created,creator,is_member,is_archived,is_private,user(DM 의 상대 user id)
- users:
-t, --text <TEXT>— 메시지 텍스트 (blocks 동반 시 알림 폴백)--markdown-text <TEXT>— 표준 Markdown 본문 (Slack이 렌더링, 최대 12,000자).--text/--blocks와 동시 사용 불가-b, --blocks <SOURCE>— Block Kit blocks (JSON array).-/@file/ inline-a, --attachments <SOURCE>— Legacy attachments (JSON array). 동일 SOURCE 어휘-m, --metadata <SOURCE>— Message metadata{event_type, event_payload}(JSON object). 동일 SOURCE 어휘--thread <ts>— (send 전용) 스레드 답장
text/markdown_text/blocks/attachments 중 최소 하나는 반드시 제공해야 합니다. 같은 호출에서 - (stdin) 은 최대 한 플래그에만 사용 가능합니다.
--limit <N>— 결과 제한 (기본:15)--cursor <cursor>— (messages 전용) 이전 응답의next_cursor로 다음 페이지 조회--oldest <date>— (messages 전용) 시작 시간 (Unix timestamp 또는 YYYY-MM-DD)--latest <date>— (messages 전용) 종료 시간 (Unix timestamp 또는 YYYY-MM-DD)--exclude-bots— 봇 메시지 제외 (messages·thread 공통)--expand <fields>— 기본 필드에 추가로 노출할 필드- 계산 필드:
date,user_name - 응답 필드:
blocks,attachments,reactions,edited,parent_user_id,reply_users,reply_users_count,latest_reply,channel,permalink
- 계산 필드:
messages_fields 기본값(lean): ts, user, bot_id, username, text, thread_ts, reply_count, subtype, metadata. AI 에이전트 컨텍스트 절약을 위해 기본 출력은 가볍게 유지하며, 풍부한 필드는 --expand 로 명시 opt-in 합니다.
messages --json 출력은 {messages: [...], next_cursor} 봉투입니다. next_cursor 가 null 이 아니면 같은 명령에 --cursor 로 넘겨 다음 페이지를 조회합니다. thread --json 은 --limit 까지 내부 페이징하므로 배열 그대로입니다.
| 코드 | 의미 |
|---|---|
0 |
성공 |
1 |
일반 오류 |
2 |
사용법 오류 (clap) |
3 |
인증 오류 (오류 내용에 따라 자격 증명·프로필·권한 확인) |
4 |
레이트리밋 |
--json 모드의 런타임 실패는 stderr 로 {"error": {"code", "message"}} 봉투를 출력합니다. 사용법 오류(종료 코드 2)는 파싱 단계에서 발생하므로 clap 의 진단 텍스트가 그대로 출력됩니다 — 종료 코드만으로 구분하면 됩니다. code 는 Slack API 오류면 Slack 의 오류 문자열 그대로(channel_not_found 등), 그 외에는 auth_error / rate_limited / http_error / network_error / error 입니다. --json의 stdout에는 JSON 데이터가 출력되며, 이벤트 스트림은 NDJSON 형식입니다.
--limit <N>— 총 결과 수 (1-100, 기본:10. 20개 단위 페이지로 자동 페이징)--channel <id|name>— 특정 채널로 검색 한정--before <date>— 이 시점 이전 결과만 (Unix ts 또는 YYYY-MM-DD)--after <date>— 이 시점 이후 결과만--channel-types <types>— 검색할 대화 타입 (기본:public_channel,private_channel,mpim,im)--content-types <types>— 검색 대상 (기본:messages)--include-context— 검색 결과 주변 맥락 포함--include-bots— 봇 메시지 포함--include-deleted-users— 삭제된 사용자 포함--include-archived— 아카이브 채널 포함--modifiers <expr>— 검색 수식어 (예:"has:pin from:@alice")--no-semantic— 키워드 일치만 사용 (시맨틱 검색 비활성)--capabilities— 질의 대신 워크스페이스의 시맨틱 검색 가용 여부 출력--sort <score|timestamp>— 정렬 기준--sort-dir <asc|desc>— 정렬 방향
Slack이 이벤트를 밀어주는 WebSocket 연결을 열고, 규칙에 걸린 것만 골라 로컬로 전달합니다. conversations.history는 Marketplace 미승인 상용 배포 앱에서 분당 1회·15건으로 제한될 수 있으므로 폴링으로는 여러 채널을 따라갈 수 없습니다. 이벤트 전달은 그 제한과 별개 축입니다.
- Socket Mode를 켭니다.
- Basic Information → App-Level Tokens에서
connections:writescope로 토큰을 만듭니다. 비회전형은xapp-, 회전형은xoxe.xapp-로 시작합니다. 아래 수명 주기와 지원 범위를 확인하세요. - Event Subscriptions → Subscribe to events on behalf of users에
message.channels,message.groups,message.im,message.mpim,reaction_added,reaction_removed를 등록합니다. 봇 이벤트가 아니라 사용자 대행 이벤트입니다 — 그래야 봇을 채널마다 초대하지 않고도 내가 보는 대화가 그대로 옵니다. - 토큰을 등록합니다:
# 기존 프로필에 app-level 토큰을 붙입니다 (프로필을 새로 만들지 않습니다)
slack-cli auth login --app-token xapp-1-A0000-000-abc
# 또는 환경변수로
export SLACK_APP_TOKEN=xapp-1-A0000-000-abc브라우저 로그인은 app-level 토큰을 만들지 않습니다. connections:write는 브라우저 로그인의 user/bot scope 요청과 분리됩니다.
auth login --app-token은 비회전형 xapp- 토큰만 저장합니다. Slack은 액세스 토큰이 12시간 후 만료되는 회전형 app-level 토큰도 지원합니다. 이 CLI는 해당 갱신 자격 증명을 저장하거나 갱신하지 않습니다. 현재 유효한 액세스 토큰을 SLACK_APP_TOKEN으로 전달하고, 외부에서 갱신한 후 교체된 토큰으로 데몬을 재시작하세요. 환경변수를 바꿔도 이미 실행 중인 프로세스에는 반영되지 않습니다.
slack-cli watch # 포그라운드. 저장하지 않고, 설정된 싱크 대신 stdout으로
slack-cli watch --json | my-agent # NDJSON 스트림
slack-cli daemon run # launchd/systemd 아래에서 상주
slack-cli daemon statusstdout 싱크가 시간 초과되거나 쓰기에 실패하면 해당 프로세스의 stdout 전달을 중단합니다. 이미 시작된 쓰기는 늦게 끝날 수 있으며, 재개하려면 프로세스를 다시 시작하세요. 다른 싱크와 보존 로그는 계속 처리합니다. 보존된 이벤트는 events pull로 읽을 수 있습니다.
config path, cache path, events path는 --json에서 {"path": "..."}를 출력합니다.
events.mode는 얼마나 오래 보관할지, events.store_body는 얼마나 많이 보관할지를 정합니다. 커서·스레드 구독·중복 판정은 어느 모드에서든 별도의 상태 DB에 남으며, 거기에는 남의 메시지 내용이 들어가지 않습니다.
| 모드 | 디스크에 남는 것 | 배달 보장 |
|---|---|---|
stream |
없음 (상태 DB 제외) | best-effort — 소비자가 꺼져 있으면 그 이벤트는 사라집니다 |
spool |
retention_days와 max_bytes 범위에서 ack될 때까지 |
보존 중 재전달 가능 |
archive |
retention_days와 max_bytes 범위 |
보존 중 재전달 가능 |
store_body = false면 로그는 참조 인덱스가 됩니다(채널·ts·작성자·매칭 규칙). 본문이 필요하면 그때 slack-cli thread로 가져오면 되고, Slack이 유일한 원본으로 남습니다.
stream 모드에서는 events pull이 조용히 빈 결과를 주지 않고 이유를 말하며 실패합니다.
첫 events pull은 로그가 비어 있어도 소비자를 등록합니다. 일정한 이름을 재사용하세요. spool 정리는 등록된 모든 소비자의 ack를 기다리지만, 보존 기간과 크기 상한은 계속 적용됩니다.
서비스 관리자로 기존 데몬을 멈추고, 업그레이드 전에 기존 바이너리로 미처리 이벤트를 처리하거나 내보내세요. 이전 디렉터리는 검증된 소유자 정보가 없어 자동으로 가져오지 않고 그대로 보존합니다. 새 저장소는 소비자 커서와 스레드 구독을 새로 시작하므로 구독하려면 다시 리액션하세요. 이후 같은 프로필·워크스페이스·사용자로 재로그인하면 저장소를 유지합니다.
규칙은 코드가 아니라 설정이고, 잘못된 규칙은 설정 로드 시점에 거부됩니다. 조건이 하나도 없는 규칙(= 워크스페이스 전체 전달)도 거부됩니다.
mentions_me— 나를 멘션한 메시지keywords— 대소문자 무시 부분 문자열from_users— 특정 작성자channels— 대화 ID 허용 목록 (이름이 아니라 ID —slack-cli channels <name>으로 확인)subscribe_emoji— 내가 그 이모지를 찍은 메시지의 스레드를 구독하고, 이후 답글이 매칭됩니다. 이모지를 떼면 구독이 해제됩니다. 이모지가 곧 구독 버튼입니다.
include_own_messages = false는 인증된 사람과 봇의 메시지를 모두 제외하며, 다른 봇 메시지는 규칙에 따라 처리합니다. 멘션과 구독 리액션은 기본 사용자 기준으로 판정합니다. 기본값은 false입니다 — 자기 메시지에 반응하는 비서는 루프가 됩니다.
이벤트는 slack-cli.event/1 스키마의 JSON 한 줄로 전달됩니다. 전달 경로는 두 가지이고, 둘 중 하나만 고르세요 — 같이 쓰면 같은 이벤트가 두 번 갑니다.
- push —
exec/http싱크가 매칭 즉시 에이전트를 호출합니다. 저지연이지만 보장 경로는 아닙니다: 실패는 카운트되고 재시도하지 않습니다(인라인 재시도는 뒤의 모든 이벤트를 막습니다). 에이전트가 꺼져 있던 동안의 호출은 그대로 사라집니다. - pull —
events pull이 커서 기준으로 읽습니다. 에이전트가 재시작해도 이어서 받습니다.mode가spool또는archive여야 합니다.
보존 중인 이벤트를 push로 재전달할 때는 최초 id와 seq를 유지합니다. 보존 한도로 삭제된 행과 stream 모드는 과거 식별자를 보관하지 않습니다.
회신은 새 프로토콜 없이 기존 CLI 그대로입니다:
set -euo pipefail
batch=$(slack-cli events pull --consumer agent --limit 20 --json)
while IFS= read -r event; do
[ -n "$event" ] || continue
ts=$(jq -er '.thread_ts // .ts' <<<"$event")
ch=$(jq -er '.channel' <<<"$event")
id=$(jq -er '.id' <<<"$event")
seq=$(jq -er '.seq' <<<"$event")
reply=$(my-agent "$event")
metadata=$(jq -cn --arg id "$id" \
'{event_type:"assistant_reply",event_payload:{source_event:$id}}')
slack-cli send "$ch" --thread "$ts" -t "$reply" -m "$metadata"
slack-cli events ack --consumer agent --through "$seq"
done <<<"$batch"처리에 성공한 이벤트만 ack합니다. --metadata는 원본 이벤트를 식별하는 표식이며 중복 전송을 자동 차단하지 않습니다. 소비자는 완료한 이벤트 ID를 기록하고, 재처리 전에 이전 전송 결과를 확인해야 합니다. 전송 성공 후 ack 전 종료되거나 응답이 유실되면 같은 이벤트가 다시 전달될 수 있습니다.
경고: user 토큰으로 보낸 메시지는 봇 표시 없이 본인 이름으로 나갑니다. 자동 전송은 봇 토큰으로 하거나, 초안을 본인에게 DM으로 보내고 승인 후 전송하세요.
- Socket Mode는 끊긴 동안의 이벤트를 재생하지 않습니다. 복구는
conversations.history(채널)와conversations.replies(구독 중인 스레드)로 하며, 규칙이 관심 있는 채널만, 개수 상한 안에서 읽습니다. 시간 상한은 읽기 시작점을 자르는 것이지 채널을 빼는 것이 아닙니다 — 커서가 더 오래됐으면 그 지점부터 읽고, 읽지 못한 구간을 경고로 남깁니다. 리액션 이벤트는 어느 쪽으로도 되읽을 수 없어 끊긴 동안의 구독 변경은 유실됩니다. - 끊긴 동안 일어난 편집·삭제는 복구되지 않습니다.
conversations.history는 편집된 메시지를 원래 ts로 돌려주므로 이미 본 원본과 같은 키가 되어 합쳐집니다. 복구가 ts를 기준으로 하는 한 피할 수 없는 바닥입니다. - 구독 중인 스레드는 마지막으로 따라간 지점부터 다시 읽습니다. 그 커서가 없으면 재연결마다 스레드를 처음부터 읽고, 중복 판정이 만료된 뒤에는 스레드 전체를 다시 배달하게 됩니다.
- 복구는
backfill_max_channels와 채널당 5페이지로 제한됩니다. 중단되거나 완료되지 않은 조회는 다음 복구를 위해 체크포인트를 유지하며, 구독 스레드는 처리한 답글까지만 전진합니다. 시간 범위 밖의 오래된 메시지는 복구되지 않을 수 있습니다. 저장 오류가 계속되면 데몬을 종료해 재시작 시 복구를 재개합니다. - 이벤트 저장소는 API 엔드포인트·프로필 이름·워크스페이스·사용자별로 격리합니다. 같은 소유자의 재로그인과 토큰 갱신은 저장소를 유지하고, 소유자가 달라지면 별도 저장소를 사용합니다. 환경 토큰은 토큰 조합마다 최초 한 번 검증하고 비밀정보가 없는 식별자 바인딩을 저장해 이후 로컬 조회에 사용합니다. 새 토큰 조합의 첫 로컬 조회에는 Slack 연결이 필요합니다. 선택한 저장소는
events path로 확인합니다. - 전달은 순차적입니다. 하나의 태스크가 파이프라인 전체를 소유하는 것이 중복 판정 게이트를 경합 없이 만들고 소비자에게 도착 순서를 보장합니다. 느린 싱크는 파이프라인을 붙잡고, 그 압력은 앞의 유계 큐가 흡수합니다(= 버립니다).
- app-level 토큰과 user 토큰은 따로 등록되고 Slack은 둘이 같은 워크스페이스인지 확인하지 않습니다. 이 설치에 인가되지 않은 페이로드는 폐기하고 오류를 남깁니다. 판정은
authorizations기준입니다 — Slack Connect 공유 채널에서는 최상위team_id가 상대 조직의 것이므로, 그걸로 판정하면 상대가 보낸 메시지를 전부 버리게 됩니다. - Slack은 한 앱의 이벤트를 열려 있는 연결들에 나눠서 보냅니다. 같은 app 토큰을 서로 다른 이름의 프로필 둘에 등록하면 잠금이 분리되어 데몬 둘이 각자 절반만 보게 됩니다. 두 대에서 데몬을 띄우면 각자 절반만 봅니다 — 그래서 프로필당 하나만 실행되도록 잠급니다. 두 대가 필요하면 Slack 앱을 두 개 만드세요.
- 이모지 구독은 스레드 시작 메시지(또는 최상위 메시지)에 찍어야 합니다. 답글에 찍으면 그 답글이 루트인 스레드를 구독하게 됩니다.
- Socket Mode 앱은 공개 Slack Marketplace에 등재할 수 없습니다 (조직 내 배포는 가능).
watch와daemon run은 같은 프로필에서 동시에 실행할 수 없습니다. 커서·스레드 구독·중복 판정을 공유하기 때문에 하나만 잠금을 가집니다.
# 현재 인증의 사용자·채널 스냅샷 갱신
slack-cli cache refresh
# --data-dir 또는 [cache].data_path를 반영한 실제 DB 위치
slack-cli cache path토큰 scope 확인 → Workspace 재설치 → 새 scope 반영 위해 slack-cli auth login 재실행
RUST_LOG=debug slack-cli users "john"English | 한국어
Made with Rust