Install
openclaw skills install @bill492/slack-block-kitCreate and send native Slack Block Kit messages, including tables, code cards, structured layouts, buttons, inputs, and rich Slack blocks.
openclaw skills install @bill492/slack-block-kitUse this skill when Slack needs formatting beyond plain mrkdwn.
Use OpenClaw message(..., presentation=...) for portable rich replies:
Use native Slack Block Kit samples or Slack API calls for Slack-specific layouts:
child_blockspresentation.blocksUse plain Slack mrkdwn for ordinary prose. Use native Block Kit when structure matters.
Use the OpenClaw message tool with presentation for portable rich messages: text, context, dividers, buttons, and selects. Slack renders those as Block Kit where supported, and other channels can degrade them.
Do not put raw Slack Block Kit JSON inside OpenClaw portable presentation.blocks. The presentation schema is semantic and only accepts text, context, divider, buttons, and select blocks; it is not a Slack block pass-through. For raw or experimental Slack blocks such as tables, containers, charts, rich code cards, Markdown blocks, images, inputs, and agent-only blocks, call Slack chat.postMessage directly or use a Slack-specific plugin path.
Always include text as the notification/accessibility fallback when posting blocks.
Copy from the smallest matching sample first, then customize.
samples/blocks/header.jsonsamples/blocks/section.jsonsamples/blocks/divider.jsonsamples/blocks/image.jsonsamples/blocks/context.jsonsamples/blocks/actions.jsonsamples/blocks/input.jsonsamples/blocks/markdown.jsonsamples/blocks/agents/plan.jsonsamples/blocks/agents/task_card.jsonsamples/blocks/agents/message_feedback.jsonsamples/blocks/rich_text.jsonsamples/blocks/table.jsonsamples/blocks/data_table/basic.jsonsamples/blocks/data_table/paginated.jsonsamples/blocks/data_table/numeric_sort.jsonsamples/blocks/data_visualization/line_single.jsonsamples/blocks/data_visualization/line_multi.jsonsamples/blocks/data_visualization/line_negative.jsonsamples/blocks/data_visualization/bar_single.jsonsamples/blocks/data_visualization/bar_multi.jsonsamples/blocks/data_visualization/bar_negative.jsonsamples/blocks/data_visualization/area_single.jsonsamples/blocks/data_visualization/area_multi.jsonsamples/blocks/data_visualization/area_negative.jsonsamples/blocks/data_visualization/pie_multi_segment.jsonsamples/blocks/data_visualization/pie_dominant_segment.jsonsamples/blocks/video.jsonsamples/blocks/callout.jsonsamples/blocks/contact_card.jsonsamples/blocks/container/standard.jsonsamples/blocks/container/full_width.jsonsamples/blocks/container/collapsible.jsonsamples/blocks/container/icon_subtitle.jsonsamples/blocks/container/media_preview.jsonsamples/blocks/container/with_callout.jsonsamples/blocks/container/with_image.jsonsamples/elements/button.jsonsamples/elements/selects.jsonsamples/elements/overflow.jsonsamples/elements/date_time.jsonsamples/elements/checkboxes_radios.jsonsamples/elements/plain_text_input.jsonFor complete Slack API details, prefer the official docs for the specific block or element after choosing a local sample.
After adding or editing samples, run:
node <skill_dir>/scripts/validate-samples.mjs
This walks samples/**/*.json, parses each file, and runs lightweight local checks for common mistakes: malformed raw_text and rich_text, table/data-table row shape, minimum data-visualization fields, duplicate block_id/action_id, wrapped or HTML-encoded URL fields, and missing container/image essentials. It is not a full Slack schema validator.
Use type: "markdown" for Slack's newer Markdown block when the content needs common Markdown features such as headings, horizontal rules, fenced code blocks, tables, blockquotes, and inline formatting.
This is distinct from legacy mrkdwn text objects used inside section and context blocks. Use samples/blocks/markdown.json for a compact mixed example.
Use samples/blocks/agents/ for agent-facing Slack blocks such as plans, task cards, and feedback controls.
Common blocks:
plan: groups multiple task steps under a shared goaltask_card: shows one task with status, details, output, and sourcesmessage_feedback: compact feedback controls; the underlying Slack block type is context_actionsNormalize source and link URLs to plain strings before posting.
Containers are wrapper blocks with child_blocks. Use them for grouped layouts that need a title, subtitle, icon, width control, or collapsible body.
Common fields:
type: "container"title: plain text titlesubtitle: optional plain text subtitleicon: optional image iconwidth: standard or fullis_collapsible: true when the container can collapsedefault_collapsed: initial collapsed statechild_blocks: nested Slack blocksNested child blocks still need valid block_id values when they are referenced by interactions or diagnostics.
Use data_visualization for native Slack charts.
Common fields:
type: "data_visualization"block_id: stable chart block idtitle: chart title stringchart.type: chart type, such as line, bar, area, or piechart.series: one or more named series for axis-based chartschart.series[].data: label/value points for axis-based chartschart.axis_config.categories: x-axis category order for axis-based chartschart.axis_config.x_label and chart.axis_config.y_label: axis labels for axis-based chartschart.segments: label/value segments for pie chartsUse separate samples for single-series, multi-series, and negative-value charts. Negative values are valid for line, bar, and area examples. Pie charts use segments, not series or axis_config.
For portable rich replies, use message(action="send", presentation=...). Current OpenClaw docs describe Slack message tool sends with presentation as Slack-rendered Block Kit sends.
For raw Slack Block Kit JSON, use Slack chat.postMessage directly. The OpenClaw message tool schema accepts presentation, not a top-level raw blocks array.
curl -s -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg channel "$CHANNEL_ID" \
--arg thread "$THREAD_TS" \
--arg text "JavaScript code block" \
--argjson blocks "$(cat samples/blocks/rich_text.json)" \
'{
channel: $channel,
thread_ts: $thread,
text: $text,
blocks: $blocks
}')"
Resolve the Slack bot token from the configured Slack account. OpenClaw supports channels.slack.botToken, per-account channels.slack.accounts.<accountId>.botToken, SecretRefs, and the default-account SLACK_BOT_TOKEN env fallback. The token needs chat:write, and the bot must be in the channel.
Do not print token values while copying or debugging the curl sample.
For portable Slack thread replies through the message tool, pass threadId or replyTo. Add replyBroadcast: true only when the thread reply should also appear in the parent channel; it maps to Slack reply_broadcast and is not supported for media uploads. Use topLevel: true or threadId: null to opt out of inherited Slack thread routing. For raw chat.postMessage, use Slack's thread_ts and reply_broadcast fields directly.
After sending, verify with Slack readback when this is a test or incident investigation. Prefer the OpenClaw message action read when available; otherwise use Slack API readback with the same channel and thread identifiers.
scripts/table.mjs for non-trivial tablestable for compact rich-text tablesdata_table for larger datasets, paginated-style tables, or typed numeric valuesraw_number cells inside data_table when Slack should sort numbers by value instead of textGenerate table JSON from headers + rows:
node <skill_dir>/scripts/table.mjs \
--headers '["Source","Amount","Status"]' \
--rows '[["Mochary","$11K","Pending"],["MHC","$13.4K","Invoiced"]]' \
--align '1:right' \
--compact --blocks-only
Options:
--headers '["H1","H2"]' - first row, bold by default--rows '[["a","b"],["c","d"]]' - data rows--json '{"headers":[...],"rows":[...]}' - single JSON input--stdin - read JSON from stdin--align '<col>:<left|center|right>,...' - column alignment, 0-indexed--wrap '<col>,...' - columns to wrap text--bold-headers - bold headers; this is the default--no-bold-headers - plain text headers--compact - minified JSON--blocks-only - output just the blocks array for API callsGenerated empty cells are converted to zero-width space automatically. For manual JSON, raw_text.text must be non-empty.
scripts/table.mjs emits 1 table block per payloadraw_text plain cells or rich_text rich cellsdata_table rows can mix raw_text, rich_text, and typed values such as raw_numberPost your text message first via the message tool, then post the table in the same thread via Slack API. Or include a section block before the table in the native blocks array.
chat.postMessage.text is the notification/accessibility fallback; always include it even when sending blocks.table, data_table, or scripts/table.mjs for non-trivial tables.thread_ts explicitly; do not rely on inherited routing.block_id and action_id values when interactivity matters.&; JSON payloads should use plain URL strings.For non-table blocks or custom layouts, construct the JSON directly from the samples.
Cell with bold text:
{"type":"rich_text","elements":[{"type":"rich_text_section","elements":[{"type":"text","text":"Bold","style":{"bold":true}}]}]}
Plain text cell:
{"type":"raw_text","text":"Plain"}