| name | slack-bridge |
| description | Warm reference for the @pinet/slack-bridge Slack dispatcher. Use when building Slack Block Kit messages, modals, canvases, uploads, schedules, pins/bookmarks, or when you need per-action usage patterns beyond slack action=help schemas. |
Slack Bridge Warm Reference
Use this skill when the compact slack dispatcher schema is not enough. The
hot path stays small: slack_inbox receives work, slack_send replies in the
current assistant thread, and slack handles the cold action surface.
Dispatcher contract
Call the dispatcher with an action and action-specific args:
{
"action": "help",
"args": { "topic": "canvas_update" }
}
Every dispatcher response has this envelope in tool details, while the default
visible content is compact CLI-style text:
{
"status": "succeeded",
"data": {},
"errors": [],
"warnings": []
}
Pass args.format="json" when you need the envelope in visible content, and
args.full=true when you need full structured details instead of compact
defaults. If an action already owns a format argument, such as export, use
args.response_format="json" for response presentation.
On failure, inspect errors[0].class, retryable, and hint. Prefer
slack({"action":"help","args":{"topic":"..."}}) before guessing an action
schema.
Guardrails match cold actions as slack:<action> (for example
slack:upload, slack:delete, slack:canvas_update). Legacy
slack_<action> patterns may be accepted during migration, but new configs
should use the colon form.
Action quick map
- Thread/channel messaging:
post_channel, read, read_channel, export
- Lightweight acknowledgement:
react
- Files/snippets:
upload, file; slack_send.files and post_channel.files for text plus attachments in one message
- Time-based follow-up:
schedule
- People/timing:
presence
- Durable channel affordances:
pin, bookmark
- Channel/project setup:
create_channel, project_create
- Canvases:
canvas_comments_read, canvas_create, canvas_update
- Modals:
modal_open, modal_push, modal_update
- Guardrail approvals:
confirm_action
- Destructive cleanup:
delete
Block Kit patterns
No Block Kit builder tool is registered. Build the JSON inline and pass it to
slack_send or slack action post_channel as blocks.
Status report
[
{
"type": "header",
"text": { "type": "plain_text", "text": "Deploy complete" }
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": "*Branch*\n`main`" },
{ "type": "mrkdwn", "text": "*Checks*\n✅ lint/typecheck/test" }
]
},
{
"type": "context",
"elements": [{ "type": "mrkdwn", "text": "PR #123 is ready for review." }]
}
]
Use with:
{
"text": "Deploy complete — branch main, checks passed.",
"thread_ts": "1712345678.000100",
"blocks": []
}
Action buttons
Stable action_id values make incoming slack_block_action metadata easy to
route. Put machine-readable context in value as plain text or JSON.
[
{
"type": "section",
"text": { "type": "mrkdwn", "text": "Approve the production deploy?" }
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": { "type": "plain_text", "text": "Approve" },
"style": "primary",
"action_id": "deploy.approve",
"value": "{\"deployId\":\"2026-04-24-main\",\"decision\":\"approve\"}"
},
{
"type": "button",
"text": { "type": "plain_text", "text": "Reject" },
"style": "danger",
"action_id": "deploy.reject",
"value": "{\"deployId\":\"2026-04-24-main\",\"decision\":\"reject\"}"
}
]
}
]
Diff/code snippet
For long diffs or logs, prefer upload over huge inline blocks. For short
snippets:
[
{
"type": "section",
"text": { "type": "mrkdwn", "text": "```ts\nconst ok = true;\n```" }
}
]
File workflows
For outbound local files, attach them to the message-posting surface you are
already using. Use slack_send.files for owned assistant-thread replies, and
slack action post_channel with args.files for explicit channel/thread
posts. Both use the same file object shape and send text plus files in one Slack
message:
{
"text": "Here is the report and the raw capture.",
"thread_ts": "1712345678.000100",
"files": [
{ "path": "./out/report.pdf", "title": "Report" },
{ "path": "/tmp/capture.bin", "filename": "capture.bin" }
]
}
{
"action": "post_channel",
"args": {
"channel": "#deployments",
"text": "Here is the deploy evidence.",
"files": [{ "path": "/tmp/evidence.png", "filename": "evidence.png" }]
}
}
Local path guardrails still apply: paths must resolve inside the current working
directory or the system temp directory. Binary files are supported.
For inbound Slack-hosted files, slack action read downloads attached files to
the local temp cache by default and returns safe descriptors alongside the
message metadata. Use args.download_files=false when you only need message text
and file metadata.
Use the explicit file action when you have a specific file ID to retry,
validate, or fetch outside a normal read flow:
{
"action": "file",
"args": {
"op": "download",
"file_id": "F0123456789",
"thread_ts": "1712345678.000100",
"message_ts": "1712345678.000200"
}
}
Both read-time downloads and the explicit file action download Slack-hosted user
content into the local temp cache and return safe descriptors: file ID,
filename/type, local temp path, size, SHA-256, cache directory, expiry, and
residual risk notes. They must not print private Slack download URLs or raw file
contents.
Modal patterns
Modal actions require a fresh Slack trigger_id from a recent interaction. The
window is short (about three seconds), so do not spend an extra human turn after
receiving a trigger; call modal_open or modal_push immediately.
Confirmation modal
{
"type": "modal",
"callback_id": "deploy.confirm",
"title": { "type": "plain_text", "text": "Deploy approval" },
"submit": { "type": "plain_text", "text": "Approve" },
"close": { "type": "plain_text", "text": "Cancel" },
"private_metadata": "{\"workflow\":\"deploy\"}",
"blocks": [
{
"type": "section",
"text": { "type": "mrkdwn", "text": "Ready to deploy `main` to production." }
},
{
"type": "input",
"block_id": "confirm_phrase",
"element": {
"type": "plain_text_input",
"action_id": "confirm_phrase",
"placeholder": { "type": "plain_text", "text": "Type CONFIRM" }
},
"label": { "type": "plain_text", "text": "Confirmation" }
}
]
}
Open it:
{
"action": "modal_open",
"args": {
"trigger_id": "fresh-trigger-id",
"thread_ts": "1712345678.000100",
"view": { "type": "modal", "blocks": [] }
}
}
When thread_ts is provided, slack-bridge embeds routing metadata in
private_metadata so modal submissions return to the original thread.
Simple form input
{
"type": "modal",
"callback_id": "incident.update",
"title": { "type": "plain_text", "text": "Incident update" },
"submit": { "type": "plain_text", "text": "Submit" },
"close": { "type": "plain_text", "text": "Cancel" },
"blocks": [
{
"type": "input",
"block_id": "summary",
"element": {
"type": "plain_text_input",
"action_id": "summary",
"multiline": true
},
"label": { "type": "plain_text", "text": "Summary" }
}
]
}
Canvas patterns
Create a standalone canvas:
{
"action": "canvas_create",
"args": { "title": "Launch plan", "markdown": "# Launch plan\n\n## Goals" }
}
Create/update a channel canvas:
{
"action": "canvas_create",
"args": { "kind": "channel", "channel": "#proj-alpha", "title": "Alpha RFC" }
}
If Slack returns canvas_tab_creation_failed, canvas_create creates a
standalone fallback attached to the channel, attempts to add a channel bookmark,
and returns the fallback canvas_id. Use that canvas_id for later
canvas_update calls if Slack still does not expose a channel canvas ID.
Append to a canvas:
{
"action": "canvas_update",
"args": { "canvas_id": "F0123", "mode": "append", "markdown": "\n## Update\nDone." }
}
Replace a section by lookup text:
{
"action": "canvas_update",
"args": {
"canvas_id": "F0123",
"mode": "replace",
"section_contains_text": "## Rollout",
"section_type": "h2",
"markdown": "## Rollout\nPhase 1 complete."
}
}
Read comments only for verified canvases:
{
"action": "canvas_comments_read",
"args": { "canvas_id": "F0123", "limit": 20 }
}
Upload, schedule, pin, bookmark examples
Upload inline content:
{
"action": "upload",
"args": {
"content": "test log contents",
"filename": "test.log",
"filetype": "text",
"thread_ts": "1712345678.000100"
}
}
Upload local paths only when the file is inside the current working directory
or the system temp directory. Otherwise read the file content explicitly and use
content.
Schedule a follow-up:
{
"action": "schedule",
"args": { "text": "Checking back in.", "thread_ts": "1712345678.000100", "delay": "1h" }
}
Pin a decision:
{
"action": "pin",
"args": { "action": "pin", "message_ts": "1712345678.000200", "thread_ts": "1712345678.000100" }
}
Add a bookmark:
{
"action": "bookmark",
"args": {
"action": "add",
"channel": "#proj-alpha",
"title": "Runbook",
"url": "https://example.com/runbook"
}
}
Confirmation and destructive actions
If guardrails require confirmation, request it in the same Slack thread. The
action value must be the exact action string required by the guarded tool;
the safest flow is to copy it from the requires confirmation for action ...
error and retry the guarded call unchanged after approval:
{
"action": "confirm_action",
"args": {
"thread_ts": "1712345678.000100",
"tool": "slack:delete",
"action": "channel=#proj-alpha | thread_ts=1712345678.000100 | ts=1712345678.000200 | thread=false"
}
}
Wait for slack_inbox to deliver the approval before retrying the guarded
action. Every destructive delete also needs confirm: true after verifying the
target; whole-thread deletion additionally needs thread: true and only works
when every message in the target thread was posted by the current bot:
{
"action": "delete",
"args": { "ts": "1712345678.000200", "thread_ts": "1712345678.000100", "confirm": true }
}