From slack-digest
Slack channel ingest + analysis skill. Pulls messages, threads, replies, permalinks, and resolved user names from any Slack channel over a time window using a Slack user token (xoxp-), emits normalized JSONL, then hands off to a recipe (FAQ / daily digest / knowledge-base publish / raw). **Invoke this skill whenever the user mentions Slack in a data/analysis/summary context**, even with minimal input. Trigger phrases include (non-exhaustive): - "슬랙 채널 분석", "슬랙 분석해줘", "슬랙 대화 요약", "슬랙 FAQ", "슬랙 수집", "슬랙 대화 긁어줘", "슬랙 채널 정리", "슬랙 스레드 요약", "슬랙에서 뽑아줘" - "analyze slack", "slack channel summary", "fetch slack", "pull slack history", "ingest slack", "slack to faq", "summarize slack threads" - Any Slack archive URL (https://*.slack.com/archives/C...) or channel ID (C0XXXXXXXX / G0XXXXXXXX) appearing with an analysis/summary/dump intent - Any mention of `xoxp-` token + "channel" When invoked with only a vague instruction (e.g. "슬랙 채널 분석해줘"), DO NOT ask a long list of questions up-front. Instead, read the "Minimal-context invocation" section of SKILL.md and follow its single-consolidated-question protocol. This skill owns the **collection + normalization** layer only. Downstream operations (FAQ, digest, Confluence/Notion/Pika publish) live as recipes in `recipes/` — read the matching recipe file after collection.
How this skill is triggered — by the user, by Claude, or both
Slash command
/slack-digest:slack-digestThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
**One job: reliably pull Slack conversation data into a normalized local JSONL.** Everything else (summarize, FAQ-ify, publish, diff-against-last-week, ...) is a downstream consumer of that JSONL, implemented as a *recipe* in `recipes/`.
One job: reliably pull Slack conversation data into a normalized local JSONL. Everything else (summarize, FAQ-ify, publish, diff-against-last-week, ...) is a downstream consumer of that JSONL, implemented as a recipe in recipes/.
Think of this skill as the Slack ingest layer. Recipes are the cookbook that consumes the ingested data.
recipes/. Read the recipe before executing it — each recipe has its own inputs, prompting rules, and output format.If no clear recipe matches, stop after Step 3 and give the user the path to threads.jsonl so they can decide.
The user will often invoke this skill with a one-liner like:
When that happens, do not interrogate them with 5 separate questions. Follow this protocol:
Before asking anything, reuse whatever context is already available:
#channelname, or C0XXXXXXXX ID anywhere in the conversation, cwd, clipboard hint, recent files, or the user's prior turns? If yes, use it.recipes/faq.mdrecipes/daily-digest.mdrecipes/faq.md → recipes/knowledge-base.mdrecipes/faq.md (most common use case).env and $SLACK_USER_TOKEN. If neither exists, that's the first blocker.Format (adapt to the user's language):
슬랙 채널 분석 시작할게요. 아래만 확인해주세요:
- 채널: (#name / C01XXXXXX / archive URL)
- 기간: 지난 3개월 (default) — 다르면 알려주세요
- 목적: FAQ 문서 (default) / daily recap / Confluence 발행 / raw JSONL
답 주시면 바로 수집 시작합니다. 토큰은
.env에서 자동 로드됩니다.
After inputs are resolved (or defaulted), go directly to Step 0 → Step 4 of the main pipeline below. Don't re-confirm again unless something changes.
conversations.list to browse channels — always require an explicit channel from the user.Token. The fetch script auto-loads $SKILL_ROOT/.env (SLACK_USER_TOKEN=xoxp-...). If .env is absent AND $SLACK_USER_TOKEN is not exported, tell the user to create .env from .env.example and stop.
Sanity check the token:
set -a; source "$SKILL_ROOT/.env" 2>/dev/null; set +a
curl -s -H "Authorization: Bearer $SLACK_USER_TOKEN" https://slack.com/api/auth.test
If ok:false, surface error and stop.
Python 3.9+ available. Stdlib only — no pip install.
Ask the user (in one consolidated question) for anything missing:
| Input | Default | Accepted forms |
|---|---|---|
| channel | required | #name, C01ABCDE12, or https://*.slack.com/archives/C... |
| time window | last 3 months | --months N, --days N, or --oldest YYYY-MM-DD [--latest YYYY-MM-DD] |
| goal / recipe | raw | faq, daily-digest, knowledge-base, raw, or free-form |
Channel must be explicitly named — never iterate across the workspace.
python3 "$SKILL_ROOT/scripts/fetch_slack.py" \
--channel "<channel>" \
--months 3 \
--out "./.slack-digest/<channel>-<yyyymmdd>"
The script produces, under --out:
| File | Contents |
|---|---|
threads.jsonl | The canonical artifact. One JSON object per thread — parent + cleaned replies, resolved user names, permalink, date, participants. |
meta.json | channel info, time window, counts, generation timestamp |
users.json | user ID → display_name cache (reusable across runs) |
raw/ | untouched conversations.history / conversations.replies responses (for reproducibility + re-normalization) |
The script handles: channel name/URL/ID resolution, cursor pagination, thread drill-down, users.info caching, chat.getPermalink, Slack markup cleanup (<@U123> → @name, <#C123|name> → #name, <http|label> → label), Tier-3 rate limits (1.2s floor + Retry-After), and system-message filtering (channel_join, etc.).
Before handing off to a recipe, sanity-check:
wc -l ./.slack-digest/<out>/threads.jsonl
head -1 ./.slack-digest/<out>/threads.jsonl | python3 -m json.tool
cat ./.slack-digest/<out>/meta.json
Report to the user: channel, time window, thread count, first/last date. If counts are suspiciously low (e.g. 0 threads on a busy channel), the token is probably not in the channel or the private-channel scope is missing — surface that before proceeding.
Based on the user's goal, open the corresponding recipe file and follow its instructions:
| Goal | Recipe file |
|---|---|
| FAQ / Q&A document from threads | recipes/faq.md |
| Daily / weekly digest | recipes/daily-digest.md |
| Publish to Confluence / Notion / Pika | recipes/knowledge-base.md |
| Something else | Use threads.jsonl directly; consider writing a new recipe afterwards. |
Always read the recipe file before executing it — recipes evolve independently of this SKILL.md.
When the user asks for a new downstream operation that doesn't fit existing recipes:
recipes/<name>.md with: Inputs, Prompting rules, Output format, Handoff (if any).threads.jsonl.conversations.list to iterate the workspace — only touch the channel the user explicitly named..env, .slack-digest/, raw/ are in .gitignore. Do not commit collected data or tokens.slack-digest/
├── SKILL.md ← this file (ingest layer)
├── README.md ← human setup guide
├── .env / .env.example ← SLACK_USER_TOKEN
├── .gitignore
├── scripts/
│ └── fetch_slack.py ← the collector (stdlib only)
└── recipes/ ← downstream consumers of threads.jsonl
├── faq.md
├── daily-digest.md
└── knowledge-base.md
$SKILL_ROOT = the directory containing this SKILL.md ($CLAUDE_PLUGIN_ROOT/skills/slack-digest).
Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
npx claudepluginhub seo-junho/slack-digest --plugin slack-digest