Convert LLM Markdown into Slack Block Kit markdown/table messages
Project description
slack-markdown-parser
slack-markdown-parser is a Python library that converts standard Markdown generated by LLMs into Slack Block Kit messages built from markdown and table blocks.
Why this library exists
Many Slack AI bots have traditionally converted model output into Slack-specific mrkdwn, but that approach creates a few recurring problems:
- Conversion overhead: LLMs naturally generate standard Markdown, so
mrkdwnusually requires extra transformation logic or prompt constraints. - Unstable formatting in languages without word spacing: in Japanese and similar scripts, Slack can fail to interpret
*,~, and related markers correctly, exposing the raw punctuation. - No table syntax in
mrkdwn: Markdown tables need custom fallback rendering if you stay in the old format.
Design approach
This library leans on Slack Block Kit's markdown block for standard Markdown and table block for tables.
| Problem | Approach |
|---|---|
| Conversion overhead | Send standard Markdown through Slack markdown blocks without rewriting it into mrkdwn. |
| Formatting instability | Insert zero-width spaces (ZWSP, U+200B) around formatting tokens when needed so Slack parses inline styling more reliably without visible extra spaces. |
No table syntax in mrkdwn |
Detect Markdown tables and convert them into Slack table blocks, including repair of common LLM-generated table inconsistencies. |
Features
- Convert standard Markdown into Slack
markdownblocks - Convert Markdown tables into Slack
tableblocks - Repair common LLM table issues such as missing outer pipes, missing separator rows, mismatched column counts, and empty cells
- Split output into multiple Slack messages when needed to satisfy Slack's "one table per message" constraint
- Sanitize ANSI/control characters and neutralize invalid Slack angle-bracket tokens before block generation
- Add ZWSP around inline formatting tokens to reduce rendering issues outside fenced code blocks
- Support Markdown and Slack-style links inside table cells
- Build fallback text for
chat.postMessage.textfrom generated blocks - Accept raw LLM Markdown without tightly constraining the model prompt, using best-effort sanitize and table repair before Slack delivery
Requirements
- Your Slack integration must support Block Kit payloads with
markdownandtableblocks. - This library does not help when your delivery path only accepts plain
textormrkdwnstrings.
Installation
pip install slack-markdown-parser
Quick start
from slack_markdown_parser import (
convert_markdown_to_slack_payloads,
)
markdown = """
# Weekly Report
| Team | Status |
|---|---|
| API | **On track** |
| UI | *In progress* |
"""
for payload in convert_markdown_to_slack_payloads(markdown):
print(payload)
convert_markdown_to_slack_messages automatically splits output into multiple messages when the input contains multiple tables.
Rendering example
Example input:
# Weekly Product Update
This week we worked on **search performance** and *UI polish*. The old flow is ~~scheduled for removal~~.
The detailed log ID is `run-20260305-02`.
Reference: https://example.com/changelog
- Improved **API response time**
- Increased *cache hit rate*
- Adjusted timeout settings
- Stabilized batch processing
- Unified retry counts
- Updated documentation
Category | Status | Owner
API | **In progress** | Team A
UI | *Under review* | Team B
QA | ~~On hold~~ | Team C
> Note: production rollout is scheduled for 2026-03-08 10:00 JST
1. Finalize release notes
1. Unify change labels
2. Add impact notes
2. Tune monitoring alert thresholds
1. Update the `warning` threshold
3. Re-check QA
```bash
./deploy.sh production
```
Example Slack bot rendering (markdown + table blocks):
Public API
Main functions
| Function | Description |
|---|---|
convert_markdown_to_slack_messages(markdown_text) -> list[list[dict]] |
Convert Markdown into Slack messages already split around table blocks. |
convert_markdown_to_slack_payloads(markdown_text) -> list[dict] |
Convert Markdown into Slack-ready payloads with both blocks and fallback text. |
convert_markdown_to_slack_blocks(markdown_text) -> list[dict] |
Convert Markdown into a flat Block Kit block list. |
build_fallback_text_from_blocks(blocks) -> str |
Build fallback text suitable for chat.postMessage.text. |
blocks_to_plain_text(blocks) -> str |
Convert blocks into plain text. |
Utility functions
| Function | Description |
|---|---|
normalize_markdown_tables(markdown_text) -> str |
Normalize Markdown table syntax before conversion. |
add_zero_width_spaces_to_markdown(text) -> str |
Insert ZWSP around formatting tokens where Slack needs stronger boundaries. |
decode_html_entities(text) -> str |
Decode HTML entities before parsing. |
sanitize_slack_text(text) -> str |
Remove ANSI/control noise and neutralize invalid Slack angle-bracket tokens. |
strip_zero_width_spaces(text) -> str |
Remove ZWSP (U+200B) and BOM (U+FEFF) while preserving join-control characters such as ZWJ. |
Lower-level exported helpers
These are also part of the public package surface:
add_zero_width_spacesconvert_markdown_text_to_blocksextract_plain_text_from_table_cellmarkdown_table_to_slack_tableparse_markdown_tablesplit_blocks_by_tablesplit_markdown_into_segments
Specification and scope
- Behavior spec: docs/spec.md
- Japanese behavior spec: docs/spec-ja.md
- Non-goals:
- Generating Slack
mrkdwnstrings - Supporting clients or MCP tools that can only send
mrkdwn
- Generating Slack
Contributing
Contributions, bug reports, and documentation improvements are welcome. Please read CONTRIBUTING.md before opening an issue or pull request.
Changelog
Version history is maintained in CHANGELOG.md.
Contact
- GitHub Issues / Pull Requests
- X: @darkgaldragon
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file slack_markdown_parser-2.2.1.tar.gz.
File metadata
- Download URL: slack_markdown_parser-2.2.1.tar.gz
- Upload date:
- Size: 28.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
97df206da9fb35b480abfe6bf8f35bd502089048285270c53b9fd26098305e0f
|
|
| MD5 |
0f16b5fb11f907fd44cef546c16b3452
|
|
| BLAKE2b-256 |
683222b664b14360cce7f3cb258c351a9f4abec5f536bb4c7ae9713ac335bed2
|
Provenance
The following attestation bundles were made for slack_markdown_parser-2.2.1.tar.gz:
Publisher:
publish.yml on darkgaldragon/slack-markdown-parser
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
slack_markdown_parser-2.2.1.tar.gz -
Subject digest:
97df206da9fb35b480abfe6bf8f35bd502089048285270c53b9fd26098305e0f - Sigstore transparency entry: 1056447940
- Sigstore integration time:
-
Permalink:
darkgaldragon/slack-markdown-parser@8bee338f3533d99b67e59ebb0ca30bff4ee201fc -
Branch / Tag:
refs/tags/v2.2.1 - Owner: https://github.com/darkgaldragon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8bee338f3533d99b67e59ebb0ca30bff4ee201fc -
Trigger Event:
push
-
Statement type:
File details
Details for the file slack_markdown_parser-2.2.1-py3-none-any.whl.
File metadata
- Download URL: slack_markdown_parser-2.2.1-py3-none-any.whl
- Upload date:
- Size: 12.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
518e6a64715feb901c4da28759cb03cdf63d6144b13690cf92ea3acf82c449a4
|
|
| MD5 |
6d1f4f66e9bcc5e7c11ecb2bb154a89f
|
|
| BLAKE2b-256 |
aa96be3774567d0c163e04d0e24e362fb462461d80c0259fe6089e44cf3eaef8
|
Provenance
The following attestation bundles were made for slack_markdown_parser-2.2.1-py3-none-any.whl:
Publisher:
publish.yml on darkgaldragon/slack-markdown-parser
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
slack_markdown_parser-2.2.1-py3-none-any.whl -
Subject digest:
518e6a64715feb901c4da28759cb03cdf63d6144b13690cf92ea3acf82c449a4 - Sigstore transparency entry: 1056448379
- Sigstore integration time:
-
Permalink:
darkgaldragon/slack-markdown-parser@8bee338f3533d99b67e59ebb0ca30bff4ee201fc -
Branch / Tag:
refs/tags/v2.2.1 - Owner: https://github.com/darkgaldragon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8bee338f3533d99b67e59ebb0ca30bff4ee201fc -
Trigger Event:
push
-
Statement type: