Slack Digest
Produce a weekly digest of key Slack threads from configured channels using Slack semantic search MCP tools. The digest surfaces high-engagement threads, groups by topic, and highlights unanswered questions.
Configuration
See _shared/report-config.md for the standard config resolution pattern.
Config schema (~/.claude/skills/slack-digest/config.json):
channel_ids: list of Slack channel ID strings
lookback_days: number (default: 7)
Required scope: at least one channel_ids entry.
Arguments
- channel_ids: list of Slack channel IDs to scan
- lookback_days: how far back to search (default: 7)
Workflow
Search Slack channels. See _shared/slack-search.md for the standard Slack search workflow. Use query terms: "discussion update question issue decision" with size=20 per channel. Count replies per thread from the full thread fetch — this is the engagement signal.
Classify threads. For each thread, determine:
- Topic category: incident, decision, question, announcement, discussion, or request
- Engagement level: high (10+ replies), medium (4-9 replies), low (1-3 replies)
- Resolution status: resolved (answer given, decision made), unresolved (question still open, no conclusion), or informational (no resolution needed)
- Classification is based on thread content: questions end with
? or start with "does anyone", "how do we"; decisions contain "let's go with", "we decided", "agreed"; incidents contain "incident", "outage", "SEV", "pages".
Identify unanswered questions. A thread is "unanswered" if: it was classified as a question AND has fewer than 3 replies AND no reply contains a clear answer (code block, link, or statement without a trailing ?).
Group threads by topic category. Within each category, sort by engagement (highest first).
Generate report. Output markdown:
## Slack Digest — {date}
Channels: {channel names or IDs} | Period: last {lookback_days} days | Threads analyzed: {N}
### Summary
- Total threads: {N} | High engagement: {N} | Unanswered questions: {N}
### Unanswered Questions (action needed)
(For each: channel, thread summary, who asked, when, permalink)
### Key Decisions
(For each: thread summary, decision outcome, participants, permalink)
### Incidents & Outages
(For each: thread summary, status, permalink)
### Active Discussions
(For each: thread summary, reply count, key participants, permalink)
### Announcements & FYI
(Compact list: summary, permalink)
Deliver as HTML. Follow the shared HTML delivery pattern in _shared/html-delivery.md. Report name: slack-digest. TLDR includes thread count, unanswered questions count, and top discussion topic.
Terminate. Report is complete when all channels are searched and threads are grouped with permalinks.
Design Principles
- Team-level only. Aggregate to team level — it is the right granularity for a periodic digest. Individual-level detail (messages per person, reply count per author) is too noisy for a team report.
- Deterministic math first, LLM narrates only. Thread counts, reply counts, and engagement levels must be computed from actual thread data. The LLM writes summaries around the numbers but never invents engagement metrics.
- Pair metrics with counter-metrics. Never report activity volume without resolution rate. If showing total threads, also show how many were resolved vs left open.
Golden Rules
- Fetch full threads, not just snippets. The RAG result is a snippet. Use
fetch-slack-thread to get the complete conversation before classifying.
- Unanswered questions go first. They represent work stuck waiting for input. Surface them before everything else.
- Include permalinks for every thread. The reader must be able to click through to the original conversation.
- Count replies from the actual thread, not from RAG metadata. RAG returns relevance-matched snippets, not engagement data. The full thread fetch gives the real reply count.
- Check ALL configured channels, not a subset.
Anti-Rationalization Counter-Table
| Excuse |
Reality |
| "I searched the channel and summarized the top results." |
RAG results are relevance-ranked, not engagement-ranked. You must fetch full threads to count replies and assess engagement. |
| "There were too many threads so I sampled a few." |
Increase the size parameter. The digest must cover the full set of significant threads. |
| "I classified the thread from the snippet alone." |
Snippets miss context. Fetch the full thread before classifying resolution status. |
| "No unanswered questions found, so I skipped that section." |
Still include the section with "None" — it's positive signal that questions are getting answered. |
| "I can't get the channel name from the ID." |
Use the channel_id in the report. The reader knows their own channels. Don't block on cosmetic lookups. |
Termination Labels
| Label |
Meaning |
report_complete |
All channels searched, threads fetched and classified, grouped with permalinks |
report_partial |
Some channels searched but thread fetch failed for some — noted which |
no_threads_found |
No threads in the time window — channels may be low-traffic or IDs wrong |
api_error |
Slack RAG API unreachable or returning errors |
Self-Review Checklist
1---2name: slack-digest3description: Use when generating a weekly Slack digest, summarizing channel activity, finding key discussions, or checking what happened in Slack. Trigger phrases: slack digest, slack summary, channel digest, what happened in slack.4---56# Slack Digest78Produce a weekly digest of key Slack threads from configured channels using Slack semantic search MCP tools. The digest surfaces high-engagement threads, groups by topic, and highlights unanswered questions.910## Configuration1112See [`_shared/report-config.md`](../_shared/report-config.md) for the standard config resolution pattern.1314**Config schema** (`~/.claude/skills/slack-digest/config.json`):15- `channel_ids`: list of Slack channel ID strings16- `lookback_days`: number (default: 7)1718**Required scope:** at least one `channel_ids` entry.1920## Arguments2122- **channel_ids**: list of Slack channel IDs to scan23- **lookback_days**: how far back to search (default: 7)2425## Workflow26271. **Search Slack channels.** See [`_shared/slack-search.md`](../_shared/slack-search.md) for the standard Slack search workflow. Use query terms: `"discussion update question issue decision"` with `size=20` per channel. Count replies per thread from the full thread fetch — this is the engagement signal.28292. **Classify threads.** For each thread, determine:30 - **Topic category**: incident, decision, question, announcement, discussion, or request31 - **Engagement level**: high (10+ replies), medium (4-9 replies), low (1-3 replies)32 - **Resolution status**: resolved (answer given, decision made), unresolved (question still open, no conclusion), or informational (no resolution needed)33 - Classification is based on thread content: questions end with `?` or start with "does anyone", "how do we"; decisions contain "let's go with", "we decided", "agreed"; incidents contain "incident", "outage", "SEV", "pages".34353. **Identify unanswered questions.** A thread is "unanswered" if: it was classified as a question AND has fewer than 3 replies AND no reply contains a clear answer (code block, link, or statement without a trailing `?`).36374. **Group threads by topic category.** Within each category, sort by engagement (highest first).38395. **Generate report.** Output markdown:4041```42## Slack Digest — {date}43Channels: {channel names or IDs} | Period: last {lookback_days} days | Threads analyzed: {N}4445### Summary46- Total threads: {N} | High engagement: {N} | Unanswered questions: {N}4748### Unanswered Questions (action needed)49(For each: channel, thread summary, who asked, when, permalink)5051### Key Decisions52(For each: thread summary, decision outcome, participants, permalink)5354### Incidents & Outages55(For each: thread summary, status, permalink)5657### Active Discussions58(For each: thread summary, reply count, key participants, permalink)5960### Announcements & FYI61(Compact list: summary, permalink)62```63646. **Deliver as HTML.** Follow the shared HTML delivery pattern in [`_shared/html-delivery.md`](../_shared/html-delivery.md). Report name: `slack-digest`. TLDR includes thread count, unanswered questions count, and top discussion topic.65667. **Terminate.** Report is complete when all channels are searched and threads are grouped with permalinks.6768## Design Principles69701. **Team-level only.** Aggregate to team level — it is the right granularity for a periodic digest. Individual-level detail (messages per person, reply count per author) is too noisy for a team report.712. **Deterministic math first, LLM narrates only.** Thread counts, reply counts, and engagement levels must be computed from actual thread data. The LLM writes summaries around the numbers but never invents engagement metrics.723. **Pair metrics with counter-metrics.** Never report activity volume without resolution rate. If showing total threads, also show how many were resolved vs left open.7374## Golden Rules75761. **Fetch full threads, not just snippets.** The RAG result is a snippet. Use `fetch-slack-thread` to get the complete conversation before classifying.772. **Unanswered questions go first.** They represent work stuck waiting for input. Surface them before everything else.783. **Include permalinks for every thread.** The reader must be able to click through to the original conversation.794. **Count replies from the actual thread, not from RAG metadata.** RAG returns relevance-matched snippets, not engagement data. The full thread fetch gives the real reply count.805. **Check ALL configured channels, not a subset.**8182## Anti-Rationalization Counter-Table8384| Excuse | Reality |85|---|---|86| "I searched the channel and summarized the top results." | RAG results are relevance-ranked, not engagement-ranked. You must fetch full threads to count replies and assess engagement. |87| "There were too many threads so I sampled a few." | Increase the size parameter. The digest must cover the full set of significant threads. |88| "I classified the thread from the snippet alone." | Snippets miss context. Fetch the full thread before classifying resolution status. |89| "No unanswered questions found, so I skipped that section." | Still include the section with "None" — it's positive signal that questions are getting answered. |90| "I can't get the channel name from the ID." | Use the channel_id in the report. The reader knows their own channels. Don't block on cosmetic lookups. |9192## Termination Labels9394| Label | Meaning |95|---|---|96| `report_complete` | All channels searched, threads fetched and classified, grouped with permalinks |97| `report_partial` | Some channels searched but thread fetch failed for some — noted which |98| `no_threads_found` | No threads in the time window — channels may be low-traffic or IDs wrong |99| `api_error` | Slack RAG API unreachable or returning errors |100101## Self-Review Checklist102103- [ ] Every configured channel was searched104- [ ] Full threads were fetched (not just RAG snippets) for classification105- [ ] Reply counts come from actual thread data106- [ ] Unanswered questions section appears first after summary107- [ ] Every thread entry includes a permalink108- [ ] Threads are grouped by topic category, sorted by engagement within each group109- [ ] HTML version uploaded to S3 with commuter link (unless `--no-html` or upload failed with noted fallback)110- [ ] Slack/chat delivery uses TLDR + link, not the full report