Markdown for agents
There is no new syntax to teach your model. slackmark accepts the markdown LLMs already write, CommonMark plus the GitHub extensions (tables, task lists, strikethrough, autolinks, footnotes), and adds Slack-native behavior on top: raw Slack mention tokens pass through as real mentions, mermaid charts become native visualizations, and GitHub admonitions become styled quotes.
Let the model write naturally and convert the output verbatim. The supported markdown reference has the complete matrix.
A typical agent answer
## Incident summary Root cause was a stale cache key in `billing-api`. Paging <!here>, details below. | Service | Errors | Status | | --- | ---: | --- | | billing-api | 412 | degraded | | checkout | 3 | ok | - [x] Cache key rotated - [ ] Postmortem scheduled > [!WARNING] > Retries are still elevated in `us-east-1`.
Block Kit JSON
…
Everything above is stock GFM plus one Slack token (<!here>), and every part
renders natively: a header block, a table block, a checkbox list, a styled
warning quote, and an @here that notifies the channel. Content that cannot
render natively falls back to the closest supported form, reported in
result.degradations. See
Validating output for the pattern
and known gaps.
What each construct becomes
| Your model writes | Slack renders |
|---|---|
# H1 … #### H4 | Native header block |
##### H5, ###### H6 | Bold rich text (Slack headers stop at level 4) |
Paragraphs, **bold**, *em*, ~~strike~~, `code` | Rich text with native styling |
[label](https://…) | Native link |
<@U…>, <#C…>, <!here>, :emoji: | Real mentions, channel links, broadcasts, emoji (details) |
| Bullet / numbered lists (nested) | Native rich text lists with indentation |
- [x] task lists | Checkbox list (markdown block) |
| GFM tables | Native table or data_table by size (details) |
| Code fences with a language tag | Configured image renderer, otherwise native code block with syntax highlighting |
mermaid pie / xychart fences | Native data_visualization charts (details) |
> quote and > [!NOTE] admonitions | Rich text quote, admonitions with emoji + bold title |
 | Native image block (public http(s) png/jpg/gif) |
--- | divider block |
Footnotes [^1] | Numbered markers with a trailing context block |
<details><summary> HTML | Collapsible container block (title and body as plain text) |
$…$ / $$…$$ math (opt-in) | Inline code-styled text; display math uses a configured renderer or preformatted fallback |
Prompting tips
You rarely need markdown instructions in your system prompt, since models default to GFM. Two additions pay off:
- Mentions. Tell the model the raw Slack token forms when it should ping
people: "To mention a user write
<@U0123456789>; for the channel write<!here>." IDs must come from your own context (e.g. the incoming event), since slackmark passes them through without lookup. - Charts. Mention that
mermaidpieandxychart-betafences render as native charts. A Node bot can also rasterize flowcharts and display math as uploaded images.
Ask models to avoid raw block HTML: tags may be stripped. A diagram or display formula without a matching renderer degrades to readable text.
Long answers
A Slack message holds at most 50 blocks. By default convert() truncates
overflowing content; convertToMessages() with { overflow: "split" } turns
long answers into multiple messages instead. See
Long content and splitting.