agentsclimarketplace

Slack block kit

Skill ccheney/robust-skills/skills/slack-block-kit

Robust skills for Agents

Install
npx -y skills add ccheney/robust-skills --skill slack-block-kit

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

Proactively apply when generating Slack API payloads with blocks, chat.postMessage calls with structured content, streaming AI responses, or views.open/views.publish calls. Triggers on Block Kit, Slack blocks, section block, actions block, header block, context block, alert block, card block, carousel block, container block, table block, data table block, data visualization block, Slack chart, markdown block, rich text block, image block, input block, video block, context_actions block, plan block, task_card block, chat.startStream, chat.appendStream, chat.stopStream, Slack modal, Slack App Home, Slack surfaces, Slack interactive elements, Slack button, select menu, overflow, datepicker, checkboxes, radio buttons, Work Objects, Slack link unfurl, views.open, views.update, views.push, views.publish, Slack composition objects. Use when building Block Kit payloads, blocks arrays, modals, App Home views, interactive elements, link unfurling, streaming agent output, or rich message layouts.

SKILL.md

22.4 KB, as published. Nobody here has run it

Slack Block Kit

UI framework for building rich, interactive layouts in Slack messages, modals, and App Home.

CRITICAL: Two Markup Systems

Text inside Block Kit text objects uses Slack mrkdwn syntax (*bold*, <url|text>), NOT standard Markdown. The only exception is the markdown block, which accepts standard Markdown (**bold**, [text](url)). Mixing these up is the single most common Block Kit generation error.

Quick Decision Trees

"Should I use blocks?"

Response type?
├─ Conversational reply, short answer, <3 lines   → text only (no blocks)
├─ Multi-section summary, report, dashboard        → blocks
├─ Two-column key-value data                       → blocks (section fields)
├─ Tabular data                                    → blocks (table / data_table)
├─ Charts or metrics visualization                 → blocks (data_visualization)
├─ Code with heading or surrounding context        → blocks
├─ Visual separation needed between topics         → blocks
└─ Feedback buttons or interactive elements        → blocks

"Which block type?"

What am I rendering?
├─ Large section title                → header (plain_text, 150 chars max)
├─ Body text or key-value pairs       → section (text + fields + accessory)
├─ Small metadata or secondary info   → context (images + text, 10 max)
├─ Horizontal separator               → divider
├─ Buttons, menus, date pickers       → actions (25 elements max)
├─ Status callout in a MODAL          → alert (modals only, 200 chars)
├─ Compact entity or summary preview  → card (optional image/actions)
├─ Multiple comparable cards/options  → carousel (1-10 cards)
├─ Grouped/collapsible block set      → container (title + ≤10 child blocks)
├─ Standalone image                   → image (image_url or slack_file)
├─ Formatted text with lists, quotes  → rich_text (nested sub-elements)
├─ Simple static table                → table (100 rows, 20 cols)
├─ Sortable/paginated table           → data_table (caption + 100 data rows)
├─ Pie/bar/area/line chart            → data_visualization (native charts)
├─ LLM-generated markdown content     → markdown (standard MD, messages only)
├─ Embedded video player              → video (requires links.embed:write)
├─ Remote file reference              → file (read-only, source: "remote")
├─ Feedback thumbs up/down            → context_actions (messages only)
├─ Collecting user input              → input (label + element)
├─ AI agent task steps                → plan (sequential tasks, messages only)
└─ Single task with status            → task_card (inside plan or standalone)

"mrkdwn or markdown block?"

Content source?
├─ Short formatted text, labels, fields     → mrkdwn in section/context
├─ Long-form LLM-generated content          → markdown block (standard MD)
├─ LLM-generated tables/task lists/code     → markdown block
├─ Programmatic tabular data                → table or data_table block
├─ Need headings                            → markdown block or header blocks
└─ Mixed: structured layout + prose         → section/header blocks + markdown block

"table, data_table, or markdown table?"

├─ LLM already emitted a Markdown table          → markdown block
├─ Static data, no interaction needed            → table
└─ Users need sorting, paging, or clickable cells → data_table (caption required)

Block Types Overview

Full property tables for all 21 blocks: references/BLOCKS.md. Highlights and sharp edges below.

header

Large bold text. plain_text only — mrkdwn is silently ignored. Max 150 chars.

{ "type": "header", "text": { "type": "plain_text", "text": "Section Title", "emoji": true } }

section

Primary content block. Supports text (3000 chars), two-column fields (10 items, 2000 chars each), and one accessory element. Either text or fields is required. Set expand: true to prevent "see more" truncation on long AI responses.

{
  "type": "section",
  "fields": [
    { "type": "mrkdwn", "text": "*Status:*\nActive" },
    { "type": "mrkdwn", "text": "*Owner:*\nChris" }
  ]
}

Compatible accessories: button, overflow, datepicker, timepicker, select menus, multi-select menus, checkboxes, radio buttons, image.

divider

{ "type": "divider" }

context

Small, muted text for metadata. Elements: mrkdwn text objects or image elements. Max 10 elements.

{ "type": "context", "elements": [{ "type": "mrkdwn", "text": "Last updated: Feb 9, 2026 • deploy-bot" }] }

actions

Interactive elements: buttons, select menus, overflow menus, date pickers. Max 25 elements.

{
  "type": "actions",
  "elements": [
    { "type": "button", "text": { "type": "plain_text", "text": "Approve" }, "style": "primary", "action_id": "approve_action", "value": "approved" }
  ]
}

Button styles: primary (green), danger (red), or omit for default. Use primary sparingly — one per set. Action IDs must be unique within the message.

alert

Callout for status, risk, or urgency. Modals only — putting an alert in a message payload is invalid. Text accepts plain_text or mrkdwn, max 200 chars. level: default, info, warning, error, or success. For message-surface callouts, use a section block with an emoji or a card instead.

{
  "type": "alert",
  "text": { "type": "mrkdwn", "text": "*Dependency conflict detected* before deploy." },
  "level": "warning"
}

card

Compact, scannable preview for entities, summaries, records, or agent results. At least one of hero_image, title, actions, or body is required.

{
  "type": "card",
  "title": { "type": "mrkdwn", "text": "Daily Standup Reminder" },
  "subtitle": { "type": "mrkdwn", "text": "Runs every weekday at *9:00 AM*" },
  "body": { "type": "mrkdwn", "text": "Last run: Today at 9:00 AM. Status: Success" },
  "actions": [
    { "type": "button", "text": { "type": "plain_text", "text": "View Logs" }, "action_id": "view_logs" }
  ]
}

Fields: icon/hero_image (image elements), slack_icon (built-in icon, mutually exclusive with icon), title/subtitle (150 chars), body/subtext (200 chars), actions (max 3 buttons; danger left-aligns, primary/unstyled right-align). No size attribute.

carousel

Horizontal, scrollable group of card blocks for options, recommendations, search results, or next steps. Must contain 1-10 cards.

{
  "type": "carousel",
  "elements": [
    { "type": "card", "title": { "type": "mrkdwn", "text": "Option A" } },
    { "type": "card", "title": { "type": "mrkdwn", "text": "Option B" } }
  ]
}

container

Groups up to 10 child blocks under a required plain_text title (150 chars). Optional subtitle, icon, width (narrow/standard/wide/full), and collapsing (is_collapsible, default_collapsed). Child blocks: actions, context, divider, file, header, image, input, rich_text, section, table, video — no nested containers, cards, or plan blocks.

{
  "type": "container",
  "title": { "type": "plain_text", "text": "Bulk update: 2 records" },
  "is_collapsible": true,
  "child_blocks": [
    { "type": "section", "text": { "type": "mrkdwn", "text": "*DCW-1024*\nStatus: Open → Closed" } }
  ]
}

image

Standalone image with required alt text. Provide either image_url (public, max 3000 chars) or slack_file object. Formats: png, jpg, jpeg, gif.

{ "type": "image", "image_url": "https://example.com/chart.png", "alt_text": "Deployment success rate chart" }

rich_text

Advanced formatted text with nested elements: styled text, lists, code blocks, quotes. See references/RICH-TEXT.md before writing nested lists or inline mentions — the nesting rules are easy to get wrong.

{
  "type": "rich_text",
  "elements": [
    { "type": "rich_text_section", "elements": [{ "type": "text", "text": "Key findings:", "style": { "bold": true } }] },
    {
      "type": "rich_text_list",
      "style": "bullet",
      "elements": [
        { "type": "rich_text_section", "elements": [{ "type": "text", "text": "Latency reduced by 40%" }] }
      ]
    }
  ]
}

Sub-element types: rich_text_section (paragraph), rich_text_list (style: "bullet" or "ordered"), rich_text_preformatted (code block), rich_text_quote (blockquote). Inline types: text, link, emoji, user, channel, usergroup, broadcast, date, color.

table

Simple tabular data. Each row is a flat array of cell objects (NOT an object with a cells property). There is no columns property — the first row is the header. Cell types: raw_text, raw_number, rich_text. Max 100 rows, 20 columns, 10,000 chars across all cells (per table AND aggregate per message).

{
  "type": "table",
  "rows": [
    [{ "type": "raw_text", "text": "Service" }, { "type": "raw_text", "text": "Status" }],
    [{ "type": "raw_text", "text": "API" }, { "type": "raw_text", "text": "Healthy" }]
  ],
  "column_settings": [{ "align": "left" }, { "align": "center" }]
}

data_table

Interactive table: pagination, sorting, filtering, clickable cells. Same row shape as table, plus a required caption string. Rows: header + 1–100 data rows; all rows need equal cell counts; header cells cannot be rich_text. Optional page_size (1–100, default 5) and row_header_column_index (default 0). Numeric sorting when a column is all raw_number cells.

{
  "type": "data_table",
  "caption": "Service health",
  "rows": [
    [{ "type": "raw_text", "text": "Service" }, { "type": "raw_text", "text": "Latency (ms)" }],
    [{ "type": "raw_text", "text": "API" }, { "type": "raw_number", "value": 12, "text": "12" }]
  ]
}

data_visualization

Native pie, bar, area, or line charts. Required: title (≤50 chars) and chart. Pie: segments (1–12, labels ≤20 chars, values > 0). Bar/area/line: series (1–12; names ≤20 chars, unique) plus axis_config.categories — every data point label must exactly match a category, and no series may omit a category.

{
  "type": "data_visualization",
  "title": "Weekly Sales",
  "chart": {
    "type": "bar",
    "series": [
      { "name": "Online", "data": [{ "label": "Week 1", "value": 32000 }, { "label": "Week 2", "value": 41000 }] }
    ],
    "axis_config": { "categories": ["Week 1", "Week 2"], "y_label": "USD" }
  }
}

markdown

Standard Markdown rendering for AI app output. Messages only.

{ "type": "markdown", "text": "**Bold**, *italic*, [link](https://example.com)\n\n## Heading\n\n- List item" }

Supports bold, italic, strikethrough, links, headers (all levels render the same size), lists, code (inline and fenced with syntax highlighting), block quotes, dividers, tables, task lists, and escaping. Images render as hyperlink text. Cumulative 12,000-char limit across all markdown blocks per payload. block_id is ignored. One markdown block may translate into multiple Slack blocks.

context_actions

Feedback and icon buttons for message-level actions. Messages only. Max 5 elements. Compatible elements: feedback_buttons, icon_button (only icon: trash).

video

Embedded video player. Requires links.embed:write scope and a publicly accessible URL in the app's unfurl domains.

input

Collects user data in modals, messages, and Home tabs. Requires label (plain_text, 2000 chars) and one compatible element. See references/ELEMENTS.md for all input element types.

plan

Container for sequential task cards, designed for AI agent output. Messages only.

{
  "type": "plan",
  "title": "Thinking completed",
  "tasks": [
    { "task_id": "t1", "title": "Fetched data", "status": "complete" },
    { "task_id": "t2", "title": "Generating report", "status": "in_progress" }
  ]
}

Task status values: pending, in_progress, complete, error. Each task is a task_card block with optional details, output (rich_text), and sources (url elements).

file

Remote file reference. Read-only — cannot be directly added to messages by apps.

Streaming Agent Output

Use chat.startStream, chat.appendStream, and chat.stopStream for live AI responses (all require chat:write). Start requires channel and thread_ts — streamed messages should reply to a user request. When streaming to channels, recipient_user_id and recipient_team_id are also required.

chunks (accepted by all three methods) can include:

  • markdown_text chunks — standard Markdown text
  • task_update chunks — timeline-style task progress (same shape as task_card; id not task_id)
  • plan_update chunks — update a plan title
  • blocks chunks — arrays of Block Kit blocks (max 50 per array; extras are dropped with a warning)

task_update and plan_update chunk fields are limited to 256 characters.

Set task_display_mode on chat.startStream:

  • timeline (default): tasks appear individually in sequence
  • plan: tasks grouped in one plan; first task placement determines plan placement
  • dense: consecutive tool calls collapse into a single summarized task card

chat.stopStream can add final blocks rendered after streamed content. Its 50-block limit is separate from streamed blocks chunks, allowing up to 100 total finalized blocks. Rate limits: start/stop Tier 2 (20+/min), append Tier 4 (100+/min).

Composition Objects

Option object (used in selects, overflow, checkboxes, radio buttons):

{
  "text": { "type": "plain_text", "text": "Option 1" },
  "value": "opt_1",
  "description": { "type": "plain_text", "text": "Detailed description" }
}

Text max 75 chars, value max 150 chars, description max 75 chars.

Confirmation dialog (add to any interactive element via confirm):

{
  "title": { "type": "plain_text", "text": "Are you sure?" },
  "text": { "type": "plain_text", "text": "This action cannot be undone." },
  "confirm": { "type": "plain_text", "text": "Yes, do it" },
  "deny": { "type": "plain_text", "text": "Cancel" },
  "style": "danger"
}

Others: conversation filter (include: im/mpim/private/public), dispatch action config (on_enter_pressed, on_character_entered), Slack file, Slack icon (card blocks), trigger/workflow (workflow buttons). Full property tables: references/COMPOSITION.md.

Limits

ConstraintLimit
Blocks per message50
Blocks per modal/Home tab100
Section text3000 chars
Section fields10 items, 2000 chars each
Header text150 chars
Context elements10
Actions elements25
Context actions elements5
Alert text (modals only)200 chars
Card title/subtitle150 chars
Card body/subtext200 chars
Card action buttons3
Carousel cards1-10
Container child blocks10
Container title/subtitle150 chars
Table rows / columns100 / 20
Table chars (per table and per message)10,000
Data table rowsheader + 100 data rows
Data viz series/segments1-12 (labels/names 20 chars)
Data points per series1-20
Markdown block text12,000 chars cumulative per payload
Streaming chunk fields (task/plan update)256 chars
Modal title / submit / close24 chars each
Modal views in stack3
Modal private_metadata3000 chars
Button text75 chars (displays ~30)
Button value2000 chars
action_id / block_id255 chars
Overflow options5
Select options100
Option text75 chars
Placeholder text150 chars
File input max file size10MB per file

Anti-Patterns

Anti-PatternProblemFix
Blocks without text fallbackEmpty notifications, no accessibility fallbackAlways provide text in chat.postMessage
text and blocks divergeNotification says one thing, chat shows anotherKeep semantically aligned
Blocks for simple repliesVisual noise for short responsesUse text only for simple replies
alert block in a messageAlerts are modal-only; payload rejectedUse section + emoji or card in messages
Huge tables in one message10,000-char cell limit exceededSplit across multiple messages
Rows as { "cells": [...] } objectsInvalid — rows are flat arrays of cellsEach row = array of cell objects
columns property on tableNo such propertyFirst row of rows is the header
Chart labels not matching categoriesRuntime validation failureEvery data point label must match axis_config.categories
mrkdwn in header textIgnored — headers only accept plain_textUse plain_text type
Standard Markdown in mrkdwn fields**bold** and [links](url) render literallyUse *bold* and <url|text>, or a markdown block
Long header textSilently truncated at 150 charsKeep under 150
Missing alt_text on imagesAccessibility failure, API may rejectAlways include alt_text

Best Practices

Use blocks when: the response has multiple distinct sections; two-column key-value layouts improve readability; a table or chart presents data more clearly than prose; visual separation helps; code needs surrounding context; interactive elements are needed.

Don't use blocks when: the response is conversational ("sure, done"), under ~3 lines, or a simple answer to a direct question.

Always:

  • Provide a complete text field as the accessible fallback (notifications, threads, search, screen readers)
  • Keep the text and blocks semantically aligned
  • Use mrkdwn syntax in text objects, not standard Markdown (except in markdown blocks)
  • Escape &, <, > in user-generated content

Surfaces Overview

SurfaceMax BlocksKey MethodsNotes
Messages50chat.postMessage, chat.updatePrimary output surface
Modals100views.open, views.update, views.pushRequires trigger_id (3s expiry), up to 3 stacked views
App Home100views.publishPrivate per-user view, Home/Messages/About tabs
CanvasesN/Acanvases.create, canvases.editMarkdown only — no Block Kit support
ListsN/Alists.* API methodsTask tracking and project management
Split ViewN/AAgents & AI Apps configAI chat surface with Chat + History tabs

Modals collect input via input blocks and return view_submission payloads. private_metadata (3000 chars) persists context between views. Read references/SURFACES.md before building modal flows or App Home views — it covers the view object schema, response actions, and view.state.values extraction paths.

Work Objects

Work Objects render rich entity previews when links are shared in Slack. They extend link unfurling with structured data, flexpane details, editable fields, and actions.

TypeEntity IDPurpose
Fileslack#/entities/fileDocuments, spreadsheets, images
Taskslack#/entities/taskTickets, to-dos, work items
Incidentslack#/entities/incidentService interruptions, outages
Content Itemslack#/entities/content_itemArticles, pages, wiki entries
Itemslack#/entities/itemGeneral-purpose entity

Work Objects use chat.unfurl with a metadata parameter containing entity type, external reference, and entity payload. Read references/WORK-OBJECTS.md before implementing — Slack silently drops the whole payload if any required field is missing.

Reference Documentation

Read thisBefore doing this
references/CHEATSHEET.mdQuick lookup of any block/element/limit at a glance
references/BLOCKS.mdBuilding any block payload — all 21 blocks with full property tables
references/ELEMENTS.mdAdding buttons, selects, inputs, or pickers — all 20 elements
references/COMPOSITION.mdWriting text objects, options, confirm dialogs, filters, Slack icons
references/RICH-TEXT.mdWriting rich_text blocks — nesting, inline types, styles
references/SURFACES.mdBuilding modals, App Home, canvases, or split view flows
references/WORK-OBJECTS.mdImplementing link unfurls, flexpanes, editable fields

Sources

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.