Send LLM Markdown to chat channels without it breaking
mdwire does not turn Markdown into finished output. It tailors the Markdown an agent wrote to each channel: repaired, rewritten into the syntax that channel accepts, and split within its length limit. Rendering is still the channel’s job.
npm install @minjun0219/mdwire
LLM markdown → normalize → render for channel → split safely → send- Normalize. Agent-written Markdown may not render correctly through a standard
Markdown converter: unpaired
**, emphasis that spans a line break in wrapped prose, unclosed code fences. Repair before rendering. - Render. Emit the syntax the channel accepts. Telegram HTML allows nine tags; Slack
markdown_texttakes standard Markdown directly. - Split. Respect the channel’s limit and never cut through markup — including while
streaming, where a chunk boundary must not land inside
**bold**.
One answer, five channels
A real bot answer, as the model wrote it — and what mdwire sends to each channel.
**상품 상세 화면**은 `web-app` 에 있어요. **첫 줄 설명이 둘째 줄까지** 이어져요. **영향 범위: 세 화면 예시: ```ts const a = 1; | 화면 | 경로 | |---|---| | 상품 상세 | /items/[id] |
- bold next to a particle
- bold across a line break
- unclosed bold
- unclosed fence
<b>상품 상세 화면</b>은 <code>web-app</code> 에 있어요. <b>첫 줄 설명이 둘째 줄까지</b> 이어져요. <b>영향 범위: 세 화면 예시:</b> <pre><code class="language-ts">const a = 1; | 화면 | 경로 | |---|---| | 상품 상세 | /items/[id] |</code></pre>
telegram-html
**상품 상세 화면**은 `web-app` 에 있어요. **첫 줄 설명이 둘째 줄까지** 이어져요. **영향 범위: 세 화면 예시:** ```ts const a = 1; | 화면 | 경로 | |---|---| | 상품 상세 | /items/[id] | ```
slack-markdown
**상품 상세 화면**은 `web-app` 에 있어요. **첫 줄 설명이 둘째 줄까지** 이어져요. **영향 범위: 세 화면 예시:** ```ts const a = 1; | 화면 | 경로 | |---|---| | 상품 상세 | /items/[id] | ```
github-markdown
**상품 상세 화면**은 `web-app` 에 있어요. **첫 줄 설명이** **둘째 줄까지** 이어져요. **영향 범위: 세 화면** **예시:** ```ts const a = 1; | 화면 | 경로 | |---|---| | 상품 상세 | /items/[id] | ```
notion-markdown
상품 상세 화면은 web-app 에 있어요. 첫 줄 설명이 둘째 줄까지 이어져요. 영향 범위: 세 화면 예시: const a = 1; | 화면 | 경로 | |---|---| | 상품 상세 | /items/[id] |
plain
Test case: chat-bot-answer
Why another one
We found three gaps in existing tools: emphasis that spans lines, Korean notation that collides with Markdown, and chat-channel converters that ignore streaming. Why another one goes into each, and Cases shows the real failures.
Targets
Telegram HTML, Slack markdown_text, GitHub comments (GFM), Notion pages, plain
text, and HTML for the browser. A Rust core, a CLI, an npm package (WASM) and a Go implementation, all held to
the same test cases.
- Telegram
telegram-htmlparse_mode HTML, nine tagslimit 4,096 - Slack
slack-markdownmarkdown_text, repaired and splitlimit 12,000 - GitHub
github-markdowncomments and PR bodies (GFM)limit 65,536 - Notion
notion-markdownNotion-flavored Markdownlimit 65,536 - Plain text
plainevery marker removedlimit 12,000 - Browser
htmlsafe for innerHTMLno limit
Try it
The demos run the npm package in your browser.
- Telegram vs. Slack
One agent answer rendered for Telegram and for Slack side by side. - Streaming
The same answer streamed into five renderers. - Before and after repair
Broken agent output next to what mdwire sends.
Install
npm install @minjun0219/mdwire # npm — bundlers, Node, Bun
cargo add mdwire-core # Rust library (`use mdwire::…`)
cargo install mdwire-cli # the `mdwire` CLI
go get github.com/minjun0219/mdwire/go@latest
The docs cover the shared concepts and the API of each: npm, Rust, Go and the CLI.