Slackbot Builder
Use this skill when creating or hardening Slack apps, Slack bots, agent-in-Slack
workflows, or production Slack integrations.
This skill has two routing modes:
- Lifecycle work: use the maturity ladder for greenfield builds, broad audits,
or upgrades that change the bot's operating level.
- Bounded capability work: load only the reference for the named behavior and
any lower-level contract the change actually touches. Do not read the whole
maturity ladder for a search bug, rendering fix, or isolated tool integration.
The one rule that survives every level
Keep Slack as a thin adapter: verify and acknowledge requests, acquire
Slack-scoped context, call the Slack Web API, render bounded Slack UI, and
delegate application behavior to a channel-agnostic core.
The ladder
| Level |
Theme |
What you add |
Reference |
| L0 |
Skeleton — it responds |
/health, /events, signature verify, url_verification, fast 200 |
level-0-skeleton.md |
| L1 |
Responsive Q&A (MVP) — a working bot |
3s ack + async work, event_id dedupe, ignore bots, strip mentions, threaded chat.postMessage, thin fetch wrappers, JSON logs + trace id |
level-1-mvp.md |
| L2 |
Context-aware — feels conversational |
shared thread sessions, root + newest causally-prior tail, merged persisted state, DMs, empty-mention nudge, 👀 reaction + assistant.threads.setStatus |
level-2-context.md |
| L3 |
Interactive / agentic — acts, human in the loop |
/interactions (signed), state-aware approvals that resolve in place, remaining-draft bulk actions, dry-run validation, stateful routing + owned-resource resolution, rich/actionable drafts, file/media controls + settings modal, live status streaming |
level-3-interactive.md |
| L4 |
Native agent surface — first-class agent UX |
Agents & AI Apps container, assistant_thread_started greeting + suggested prompts, thread titles, native text streaming (chat.startStream/appendStream/stopStream) mapping your emit stream to a typed answer + tool-call timeline, graceful fallback to the message flow |
level-4-native-agent.md |
| L5 |
Hardened — won't page you at 2am |
per-thread durable serialization, long-running signed callbacks + durable URL, App Home prefs/dashboard, rate-limit backoff + ok:false handling, sanitized errors, storage TTLs, service-user attribution + audit, full observability, security/testing checklists |
level-5-hardened.md |
| L6 |
Multi-surface / scale — polished platform |
one core across web/Slack/cron, multi-workspace/tenancy, queues + backpressure for heavy work, target caching, usage analytics + answer-quality feedback, break-glass/degraded config |
level-6-scale.md |
| Specialized contract |
Reference |
| Slack search, files, PDFs, or requester-scoped retrieval |
search-and-retrieval.md |
| Native charts/tables or hosted analytical artifacts |
analytical-visualizations.md |
| Mixed Slack evidence plus deterministic application/provider data |
Read both search-and-retrieval.md and analytical-visualizations.md |
| Slack rendering of typed follow-up controls or execution receipts |
answer-quality-and-receipts.md |
| Generated images and iteration controls |
image-generation.md |
| Thread persistence, ordering, resource routing, or mutations |
stateful-agent-workflows.md |
| Cloudflare ingress, dispatch, dedupe, or durable acceptance |
cloudflare-durable-ingress.md |
When diagnosing an existing bot, inspect its current code and tests before
choosing a level. A production bot can have an L2 retrieval defect without the
task becoming an L5 hardening project.
Strong opinions
Universal invariants — true at every level (the level-specific opinions live in
their level files so they load only when needed):
- Verify every request from the raw body before parsing, including URL
verification and interactive requests.
- Acknowledge within Slack's deadline. Authenticate, deduplicate, durably
dispatch slow work, and guarantee a terminal answer or sanitized error.
- Ignore bot-authored events and preserve event/message idempotency.
- Treat workspace + channel +
thread_ts as the conversation boundary. Load
only causally prior messages, paginate before trimming, and preserve
file/image-only context when the feature is multimodal.
- Serialize stateful or mutating turns per thread through shared storage.
- Keep application behavior and canonical state outside the Slack adapter;
cards and reactions are presentation, not authority.
- Construct Block Kit from validated typed data. Keep top-level message text
useful for notifications and accessibility; use native table blocks rather
than Markdown tables.
- Disable both link and media unfurls when replies should not generate previews.
- Treat cosmetic enrichment such as reactions and status updates as best
effort. Fail closed when identity, authorization, or required evidence cannot
be established.
- Record structured safe telemetry for ingress, provider calls, fallbacks, and
terminal delivery. Never silently substitute a fallback. Requester-visible
receipts expose only allowlisted fields, never hidden reasoning, raw private
context, or unrestricted provider payloads.
Level-specific opinions (full rationale + war stories in the linked file): mutations
require a human, inline flags configure the core, route on the raw request not the
context, interactive actions ack the click instantly + batch ops show a started
state and terminal summary (plus incremental progress when practical), artifacts
get iterate-button + settings-modal affordances → L3;
instrument every model call (not just text), slow work runs in durable execution not a
background promise, every entry surface protected equally, every job ends in a guaranteed
result-or-error delivered by the right surface mechanism → L5;
image-gen specifics → image-generation.md.
Implementation bias: start boring
TypeScript; a small HTTP framework (Hono, Fastify, Express, or native route
handlers); shared KV/Redis/Postgres for state; raw Slack Web API fetch wrappers
unless an SDK is already established; a queue or platform-native background
execution for work over 1–2s; a web page for long output. Add slash commands,
modals, Socket Mode, or workflow steps only when the product need is clear.
1---2name: slackbot-builder3description: Design or harden Slack bot transport and interaction architecture: signed Events API ingress, fast acknowledgement, idempotency, causal thread context, Block Kit actions, durable agent execution, multi-workspace operation, or Slack-specific delivery of typed follow-up controls and privacy-bounded execution receipts. Use for new Slack bots, broad Slack architecture audits, or changes to these Slack contracts. Do not use for deployment or visual testing, cosmetic copy/layout, general answer quality, channel-agnostic transcript or receipt schemas, core suggestion generation, or merely operating Slack.4license: MIT5---6# Slackbot Builder78Use this skill when creating or hardening Slack apps, Slack bots, agent-in-Slack9workflows, or production Slack integrations.1011This skill has two routing modes:1213- **Lifecycle work:** use the maturity ladder for greenfield builds, broad audits,14 or upgrades that change the bot's operating level.15- **Bounded capability work:** load only the reference for the named behavior and16 any lower-level contract the change actually touches. Do not read the whole17 maturity ladder for a search bug, rendering fix, or isolated tool integration.1819## The one rule that survives every level2021Keep Slack as a thin adapter: verify and acknowledge requests, acquire22Slack-scoped context, call the Slack Web API, render bounded Slack UI, and23delegate application behavior to a channel-agnostic core.2425## The ladder2627| Level | Theme | What you add | Reference |28|---|---|---|---|29| **L0** | Skeleton — *it responds* | `/health`, `/events`, signature verify, `url_verification`, fast `200` | [level-0-skeleton.md](level-0-skeleton.md) |30| **L1** | Responsive Q&A (MVP) — *a working bot* | 3s ack + async work, `event_id` dedupe, ignore bots, strip mentions, threaded `chat.postMessage`, thin `fetch` wrappers, JSON logs + trace id | [level-1-mvp.md](level-1-mvp.md) |31| **L2** | Context-aware — *feels conversational* | shared thread sessions, root + newest causally-prior tail, merged persisted state, DMs, empty-mention nudge, 👀 reaction + `assistant.threads.setStatus` | [level-2-context.md](level-2-context.md) |32| **L3** | Interactive / agentic — *acts, human in the loop* | `/interactions` (signed), state-aware approvals that resolve in place, remaining-draft bulk actions, dry-run validation, stateful routing + owned-resource resolution, rich/actionable drafts, file/media controls + settings modal, live status streaming | [level-3-interactive.md](level-3-interactive.md) |33| **L4** | Native agent surface — *first-class agent UX* | Agents & AI Apps container, `assistant_thread_started` greeting + suggested prompts, thread titles, native text streaming (`chat.startStream`/`appendStream`/`stopStream`) mapping your `emit` stream to a typed answer + tool-call timeline, graceful fallback to the message flow | [level-4-native-agent.md](level-4-native-agent.md) |34| **L5** | Hardened — *won't page you at 2am* | per-thread durable serialization, long-running signed callbacks + durable URL, App Home prefs/dashboard, rate-limit backoff + `ok:false` handling, sanitized errors, storage TTLs, service-user attribution + audit, full observability, security/testing checklists | [level-5-hardened.md](level-5-hardened.md) |35| **L6** | Multi-surface / scale — *polished platform* | one core across web/Slack/cron, multi-workspace/tenancy, queues + backpressure for heavy work, target caching, usage analytics + answer-quality feedback, break-glass/degraded config | [level-6-scale.md](level-6-scale.md) |3637| Specialized contract | Reference |38|---|---|39| Slack search, files, PDFs, or requester-scoped retrieval | [search-and-retrieval.md](search-and-retrieval.md) |40| Native charts/tables or hosted analytical artifacts | [analytical-visualizations.md](analytical-visualizations.md) |41| Mixed Slack evidence plus deterministic application/provider data | Read both [search-and-retrieval.md](search-and-retrieval.md) and [analytical-visualizations.md](analytical-visualizations.md) |42| Slack rendering of typed follow-up controls or execution receipts | [answer-quality-and-receipts.md](answer-quality-and-receipts.md) |43| Generated images and iteration controls | [image-generation.md](image-generation.md) |44| Thread persistence, ordering, resource routing, or mutations | [stateful-agent-workflows.md](stateful-agent-workflows.md) |45| Cloudflare ingress, dispatch, dedupe, or durable acceptance | [cloudflare-durable-ingress.md](cloudflare-durable-ingress.md) |4647When diagnosing an existing bot, inspect its current code and tests before48choosing a level. A production bot can have an L2 retrieval defect without the49task becoming an L5 hardening project.5051## Strong opinions5253**Universal invariants — true at every level** (the level-specific opinions live in54their level files so they load only when needed):5556- Verify every request from the raw body before parsing, including URL57 verification and interactive requests.58- Acknowledge within Slack's deadline. Authenticate, deduplicate, durably59 dispatch slow work, and guarantee a terminal answer or sanitized error.60- Ignore bot-authored events and preserve event/message idempotency.61- Treat workspace + channel + `thread_ts` as the conversation boundary. Load62 only causally prior messages, paginate before trimming, and preserve63 file/image-only context when the feature is multimodal.64- Serialize stateful or mutating turns per thread through shared storage.65- Keep application behavior and canonical state outside the Slack adapter;66 cards and reactions are presentation, not authority.67- Construct Block Kit from validated typed data. Keep top-level message text68 useful for notifications and accessibility; use native table blocks rather69 than Markdown tables.70- Disable both link and media unfurls when replies should not generate previews.71- Treat cosmetic enrichment such as reactions and status updates as best72 effort. Fail closed when identity, authorization, or required evidence cannot73 be established.74- Record structured safe telemetry for ingress, provider calls, fallbacks, and75 terminal delivery. Never silently substitute a fallback. Requester-visible76 receipts expose only allowlisted fields, never hidden reasoning, raw private77 context, or unrestricted provider payloads.7879**Level-specific opinions** (full rationale + war stories in the linked file): mutations80require a human, inline flags configure the core, route on the raw request not the81context, interactive actions ack the click *instantly* + batch ops show a started82state and terminal summary (plus incremental progress when practical), artifacts83get iterate-button + settings-modal affordances → [L3](level-3-interactive.md);84instrument *every* model call (not just text), slow work runs in durable execution not a85background promise, every entry surface protected equally, every job ends in a guaranteed86result-or-error delivered by the right surface mechanism → [L5](level-5-hardened.md);87image-gen specifics → [image-generation.md](image-generation.md).8889## Implementation bias: start boring9091TypeScript; a small HTTP framework (Hono, Fastify, Express, or native route92handlers); shared KV/Redis/Postgres for state; raw Slack Web API `fetch` wrappers93unless an SDK is already established; a queue or platform-native background94execution for work over 1–2s; a web page for long output. Add slash commands,95modals, Socket Mode, or workflow steps only when the product need is clear.