How to Handle Consistent Markdown Across Chat Channels
I have spent too many hours fixing broken formatting when a bot sends a long message. It is frustrating to see a bold tag get split in half by a character limit or a table turn into unreadable text on a mobile screen.
OpenClaw solves this by using an Intermediate Representation (IR). Instead of sending raw Markdown to every platform, I parse it once and then render it specifically for the destination. This ensures that formatting like bolding or code blocks stays intact, even when messages need to be split into chunks.
What You’ll Need
Section titled “What You’ll Need”- Access to OpenClaw outbound adapters.
- A target channel (Slack, Telegram, or Signal).
Quick Start
Section titled “Quick Start”I recommend following these four steps to get your Markdown rendering correctly across different channels.
- Parse to IR: Convert your Markdown string into the shared IR format. This keeps the text and the styles separate.
- Configure Tables: Decide how you want tables to look. You can set this in your
config.yaml. - Chunk the IR: Split the text based on channel limits before you render. This prevents styles from breaking.
- Render for the Channel: Use the specific renderer for Slack, Telegram, or Signal.
Here is what the IR looks like under the hood:
{ "text": "Hello world — see docs.", "styles": [{ "start": 6, "end": 11, "style": "bold" }], "links": [{ "start": 19, "end": 23, "href": "https://docs.openclaw.ai" }]}If you want to control how tables appear in Discord or specific accounts, use this configuration:
channels: discord: markdown: tables: code accounts: work: markdown: tables: offHow It Works
Section titled “How It Works”The pipeline is straightforward. I use a single parse step to create the IR. This IR uses UTF-16 code units for offsets, which is exactly what the Signal API requires.
When it comes to chunking, the system is smart. It slices the style spans per chunk so that a bold sentence that spans two messages will be reopened and closed correctly in both. Slack gets mrkdwn tokens, Telegram gets HTML tags like <b>, and Signal receives plain text with style ranges.
For tables, you have three options. You can render them as code blocks, convert them to bullets, or turn them off to let the raw text pass through.
Troubleshooting
Section titled “Troubleshooting”- Broken Telegram Markup: If your Telegram messages fail to send, ensure you are escaping text outside of the HTML tags.
- Signal Formatting Misalignment: Signal style ranges depend on UTF-16 offsets. If your styles are shifted, check that you are not using code point offsets.
- Fenced Code Blocks: If the closing markers are appearing on the same line as your code, make sure you preserve the trailing newlines in the IR.
- Double-linked Slack URLs: If URLs are showing up twice, ensure autolink is disabled during the parse step to prevent Slack from adding its own links.
If you have specific questions about your configuration, check the AI Setup Assistant.
What’s Next
Section titled “What’s Next”OpenClaw Expert
Still stuck?
If this page didn't answer your case, ask OpenClaw Expert for step-by-step guidance.