Agent Skills: Slack mrkdwn

Proactively apply when generating any Slack text content, chat.postMessage text fields, or text objects with type "mrkdwn". Triggers on mrkdwn, Slack formatting, Slack markdown, Slack bold, Slack italic, Slack link syntax, Slack mentions, Slack date formatting, Slack escaping, Slack text object, verbatim, plain_text, Slack mrkdwn vs markdown, markdown_text, Slack blockquote, Slack code block, Slack strikethrough, Slack user mention, Slack channel mention, Slack emoji, link_names, auto-parsing, unfurl_links, mrkdwn_in. Use when formatting Slack message text, writing mrkdwn strings, constructing text objects, escaping user content for Slack, adding mentions or date formatting to messages, streaming markdown to Slack, or debugging text rendering issues. Slack mrkdwn text formatting syntax for messages, text objects, and attachments.

UncategorizedID: ccheney/robust-skills/slack-mrkdwn

Install this agent skill to your local

pnpm dlx add-skill https://github.com/ccheney/robust-skills/tree/HEAD/skills/slack-mrkdwn

Skill Files

Browse the full folder contents for slack-mrkdwn.

Download Skill

Loading file tree…

skills/slack-mrkdwn/SKILL.md

Skill Metadata

Name
slack-mrkdwn
Description
Proactively apply when generating any Slack text content, chat.postMessage text fields, or text objects with type "mrkdwn". Triggers on mrkdwn, Slack formatting, Slack markdown, Slack bold, Slack italic, Slack link syntax, Slack mentions, Slack date formatting, Slack escaping, Slack text object, verbatim, plain_text, Slack mrkdwn vs markdown, markdown_text, Slack blockquote, Slack code block, Slack strikethrough, Slack user mention, Slack channel mention, Slack emoji, link_names, auto-parsing, unfurl_links, mrkdwn_in. Use when formatting Slack message text, writing mrkdwn strings, constructing text objects, escaping user content for Slack, adding mentions or date formatting to messages, streaming markdown to Slack, or debugging text rendering issues. Slack mrkdwn text formatting syntax for messages, text objects, and attachments.

Slack mrkdwn

Slack's custom text formatting syntax for messages and text objects. Not standard Markdown.

CRITICAL: Two Markup Systems

Slack has two completely different markup syntaxes. Using the wrong one is the most common formatting mistake.

| System | Used In | Bold | Link | Heading | |--------|---------|------|------|---------| | Slack mrkdwn | text field, text objects (type: "mrkdwn"), section fields, attachment fields via mrkdwn_in | *bold* | <url\|text> | Not supported | | Standard Markdown | markdown block, markdown_text argument | **bold** | [text](url) | # Heading |

Standard Markdown syntax (**bold**, [text](url), # Heading) renders as literal text in mrkdwn contexts. Slack mrkdwn syntax (*bold*, <url|text>) renders as literal text in markdown blocks. Never mix them.

Standard Markdown surfaces (both designed for passing LLM output through unmodified):

  • The markdown block (type: "markdown") accepts standard Markdown and translates it for Slack rendering. Supports: headings (all render at the same size), bold, italic, strikethrough, lists, links, blockquotes, code blocks with optional syntax highlighting, horizontal rules/dividers, tables, task lists, images (rendered as link text), and backslash escaping. A single input block may expand into multiple output blocks; block_id is not retained. Cumulative limit across all markdown blocks in one payload: 12,000 characters.
  • The markdown_text argument on chat.postMessage and streaming methods (chat.startStream, chat.appendStream) accepts standard Markdown directly. It cannot be combined with blocks or text (error: markdown_text_conflict). Limit: 12,000 characters.

mrkdwn Syntax

| Format | Syntax | Notes | |--------|--------|-------| | Bold | *bold* | Not **bold** | | Italic | _italic_ | Not *italic* | | Strikethrough | ~strikethrough~ | Not ~~strikethrough~~ | | Inline code | `code` | Same as standard Markdown | | Code block | ```code``` | No syntax highlighting in mrkdwn; use a markdown block with language-tagged fences for highlighting | | Blockquote | > quoted text | Prefix each line | | Link | <https://example.com\|display text> | Not [text](url) | | Emoji | :emoji_name: | Standard or custom. Direct Unicode also works; Slack stores and returns emoji in colon format | | Newline | \n | Literal newline in string | | Ordered list | 1. item | Plain text, no special rendering | | Bullet list | - item | Rendered properly in rich_text blocks only |

Inline code disables all other formatting within it — use it to display literal text like *not bold*.

Nested Formatting

Combining adjacent format markers without spaces (e.g., *bold*_italic_) is unreliable and may not render correctly. Always add a space between differently-formatted segments:

*bold* _italic_              ← works reliably
*bold*_italic_               ← may fail to render

For reliable combined formatting on a single word, use rich_text blocks with explicit style objects ({"bold": true, "italic": true}).

Links

<https://example.com>                            Auto-detected URL
<https://example.com|Display Text>               URL with custom text
<mailto:user@example.com|Email Link>             Email link

URLs posted in text are auto-linked by Slack. Use <url|text> for custom display text. Spaces in URLs will break parsing — remove them. mrkdwn formatting inside link labels (e.g., <url|*bold*>) works for basic styles.

Link Unfurling

Slack previews ("unfurls") linked content. By default Slack unfurls links in messages posted by users and apps. Control this per message:

| Parameter | Controls | |-----------|----------| | unfurl_links | Text-based content previews | | unfurl_media | Media (images, video, audio) previews |

Set both to false to suppress all previews. These are chat.postMessage parameters, not mrkdwn syntax.

Mentions and References

User Mentions

<@U0123ABC456>

Triggers a notification for the mentioned user. Auto-converts to display name.

Channel References

<#C0123ABC456>

Auto-converts to channel name. Users without access see "private channel".

User Group Mentions

<!subteam^SAZ94GDB8>

Notifies all members of the user group.

Special Mentions

| Syntax | Scope | Caution | |--------|-------|---------| | <!here> | Active members in channel | Use sparingly | | <!channel> | All channel members, active or not | Triggers notifications for everyone | | <!everyone> | Every non-guest workspace member (via #general) | Very disruptive |

Best Practice

Always use IDs, not names. IDs are stable; names change:

<@U0123ABC456>       user ID — works
@chris               name — not parsed as a mention
<#C0123ABC456>       channel ID — works
#general             name — not parsed as a link

The link_names parameter now only finds and links user groups — it no longer links individual users. Don't rely on it; use <@USERID> and <#CHANNELID> syntax directly.

Date Formatting

Displays dates/times localized to the reader's device timezone (not their Slack preference timezone).

Syntax

<!date^{unix_timestamp}^{token_string}^{optional_link}|{fallback_text}>

Tokens

| Token | Example Output | |-------|---------------| | {date_num} | 2014-02-18 (leading zeros; developer-friendly) | | {date} | February 18th, 2014 | | {date_short} | Feb 18, 2014 | | {date_long} | Tuesday, February 18th, 2014 | | {date_pretty} | Yesterday / February 18th, 2014 | | {date_short_pretty} | Yesterday / Feb 18, 2014 | | {date_long_pretty} | Yesterday / Tuesday, February 18th, 2014 | | {time} | 6:39 AM (12h) or 06:39 (24h) | | {time_secs} | 6:39:42 AM (12h) or 06:39:42 (24h) | | {ago} | 3 minutes ago / 4 hours ago / 2 days ago |

{date}, {date_short}, and {date_long} omit the year when the date is less than six months in the past or future. _pretty variants use relative terms ("yesterday", "today", "tomorrow") when applicable.

Examples

<!date^1392734382^{date} at {time}|February 18th, 2014 at 6:39 AM PST>
<!date^1392734382^{date_short_pretty} {time}|Feb 18, 2014 6:39 AM>
<!date^1392734382^{ago}|February 18th, 2014>

Tokens can be mixed with literal text in the token string. The optional link (third ^-separated parameter) makes the date a clickable hyperlink. Fallback text (after |) is required and displays for clients that cannot render date formatting — include timezone information in it, since the fallback cannot be localized.

Escaping

Only three characters require escaping in mrkdwn:

| Character | Escape Sequence | |-----------|----------------| | & | &amp; | | < | &lt; | | > | &gt; |

Do NOT encode other characters as HTML entities. Only these three are control characters in Slack's markup system.

When displaying user-generated content that may contain these characters, always escape them to prevent unintended formatting or link injection.

Text Object

The text object is the most common composition object in Block Kit. It determines how text is rendered.

[
  { "type": "mrkdwn", "text": "*bold* and _italic_", "verbatim": false },
  { "type": "plain_text", "text": "No formatting", "emoji": true }
]

mrkdwn supports Slack mrkdwn syntax. plain_text renders literally. emoji: true converts :emoji: to rendered emoji (plain_text only). Min 1 char, max 3000 chars (section fields max 2000 chars each, max 10 fields). For the top-level message text field, keep it under 4,000 chars for best results; Slack truncates messages over 40,000 chars.

Where Each Type Is Allowed

| Context | Allowed Types | |---------|--------------| | Header block text | plain_text only | | Section text / fields | mrkdwn or plain_text | | Context elements | mrkdwn or plain_text | | Button text | plain_text only | | Placeholder | plain_text only | | Input label / hint | plain_text only | | Modal title / submit / close | plain_text only | | Option text (select, multi-select, overflow) | plain_text only | | Option text (checkboxes, radio buttons) | mrkdwn or plain_text | | Option description | plain_text; mrkdwn allowed in checkboxes/radio buttons |

Verbatim Behavior

When verbatim: false (default):

  • URLs auto-convert to clickable links
  • Channel names auto-convert to channel links
  • Mentions auto-parse

When verbatim: true:

  • Markdown formatting still processes
  • No auto-linking or mention parsing
  • Useful for displaying raw URLs or text containing @ or # that aren't mentions
{ "type": "mrkdwn", "text": "Check the log at http://example.com/debug", "verbatim": true }

Auto-Parsing Behavior

The parse Parameter (chat.postMessage)

| Value | Effect | |-------|--------| | Unset (default) | mrkdwn formatting enabled; URLs auto-hyperlinked | | "none" | mrkdwn formatting enabled; URL auto-hyperlinking disabled | | "full" | mrkdwn formatting ignored; aggressive auto-parsing of names/URLs |

Disabling Auto-Parsing

In text objects: Set verbatim: true (see above).

In message payloads:

  • Omit link_names argument (or set to 0)
  • Set parse: "none" to also disable URL auto-linking

Disabling auto-parsing matters for safety: if you pass third-party user input straight into published text, a string like @everyone could be auto-parsed and notify the whole workspace.

Disabling Formatting Entirely

| Context | Method | |---------|--------| | Text objects | Set type to "plain_text" | | Top-level message text | Set mrkdwn: false | | Attachments | Exclude field from mrkdwn_in array |

Anti-Patterns

| Anti-Pattern | Problem | Fix | |--------------|---------|-----| | **bold** in mrkdwn | Renders literally | Use *bold* | | [text](url) in mrkdwn | Renders literally | Use <url\|text> | | # Heading in mrkdwn | Renders as plain text | Use header block or markdown block | | *bold* in markdown block | Renders as italic | Use **bold** | | link_names: 1 for user mentions | No longer links users, only user groups | Use <@USERID> directly | | markdown_text alongside blocks/text | API error markdown_text_conflict | Send one or the other | | HTML-encoding beyond &<> | Renders literally | Only escape &, <, > | | Spaces in URLs | Breaks link parsing | URL-encode spaces as %20 | | Combining *bold*_italic_ without space | Rendering unreliable | Add space: *bold* _italic_ |

Secondary Attachments (Legacy)

The attachments array adds secondary content below the main message. One of fallback or text is required (unless using blocks).

| Field | Description | |-------|-------------| | fallback | Plain-text summary for limited clients (always plain text) | | color | Hex color or "good" / "warning" / "danger" | | pretext | Text above the attachment block | | author_name, author_link, author_icon | Small author line (16px icon) | | title, title_link | Large heading with optional hyperlink | | text | Main body (auto-collapses at 700+ chars or 5+ line breaks) | | fields | Array of { title, value, short } objects | | image_url | Full-width image (GIF, JPEG, PNG, BMP) | | thumb_url | Thumbnail (75px max) | | footer, footer_icon, ts | Footer metadata (footer max 300 chars) | | mrkdwn_in | Array of fields to format with mrkdwn: "text", "pretext", "fields" |

Only "text", "pretext", and "fields" are accepted values in mrkdwn_in. Fields not listed render as plain text. fallback is always plain text.

Prefer Block Kit blocks over attachments for new development.

Reference Documentation

| File | Purpose | |------|---------| | references/CHEATSHEET.md | Quick reference: mrkdwn syntax, mentions, dates, escaping at a glance |

Sources