From nanoclaw-skills
Converts Claude's Markdown output to native text syntax for WhatsApp, Telegram, Slack (marker substitution), Discord (passthrough), and Signal (rich-text helper). Ensures responses render properly in messaging channels without literal markdown artifacts.
npx claudepluginhub nanocoai/nanoclaw-skills --plugin nanoclaw-skillsThis skill uses the workspace's default tool permissions.
This skill wires channel-aware Markdown conversion into the outbound pipeline so Claude's
Formats Markdown to Slack rich HTML for copy-paste or mrkdwn for API/webhooks. Generates previews, copies to clipboard, supports tables, lists, emojis, mentions.
Converts Markdown and plain text to Google Chat-compatible formatting syntax, transforming headers to bold, lists to bullets, bold/italic/strikethrough, and preserving code. Use for Google Chat messages or documents.
Formats messages for WhatsApp using platform syntax: *bold*, _italic_, ~strikethrough~, ```monospace```, *bullets*, avoiding headers/tables/markdown bloat for clean mobile display.
Share bugs, ideas, or general feedback.
This skill wires channel-aware Markdown conversion into the outbound pipeline so Claude's
responses render natively on each platform — no more literal **asterisks** in WhatsApp or
Telegram.
| Channel | Transformation |
|---|---|
**bold** → *bold*, *italic* → _italic_, headings → bold, links → text (url) | |
| Telegram | same as WhatsApp, but [text](url) links are preserved (Markdown v1 renders them natively) |
| Slack | same as WhatsApp, but links become <url|text> |
| Discord | passthrough (Discord already renders Markdown) |
| Signal | passthrough for parseTextStyles; parseSignalStyles in src/text-styles.ts produces plain text + native textStyle ranges for use by the Signal skill |
Code blocks (fenced and inline) are always protected — their content is never transformed.
test -f src/text-styles.ts && echo "already applied" || echo "not yet applied"
If already applied, skip to Phase 3 (Verify).
git remote -v
If an upstream remote pointing to https://github.com/qwibitai/nanoclaw.git is missing,
add it:
git remote add upstream https://github.com/qwibitai/nanoclaw.git
git fetch upstream skill/channel-formatting
git merge upstream/skill/channel-formatting
If there are merge conflicts on package-lock.json, resolve them by accepting the incoming
version and continuing:
git checkout --theirs package-lock.json
git add package-lock.json
git merge --continue
For any other conflict, read the conflicted file and reconcile both sides manually.
This merge adds:
src/text-styles.ts — parseTextStyles(text, channel) for marker substitution and
parseSignalStyles(text) for Signal native rich textsrc/router.ts — formatOutbound gains an optional channel parameter; when provided
it calls parseTextStyles after stripping <internal> tagssrc/index.ts — both outbound sendMessage paths pass channel.name to formatOutboundsrc/formatting.test.ts — test coverage for both functions across all channelsnpm install
npm run build
npx vitest run src/formatting.test.ts
All 73 tests should pass and the build should be clean before continuing.
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
# Linux: systemctl --user restart nanoclaw
Send a message through any registered WhatsApp or Telegram chat that will trigger a response from Claude. Ask something that will produce formatted output, such as:
Summarise the three main advantages of TypeScript using bullet points and bold headings.
Confirm that the response arrives with native bold (*text*) rather than raw double
asterisks.
tail -f logs/nanoclaw.log
If you have the Signal skill installed, src/channels/signal.ts can import
parseSignalStyles from the newly present src/text-styles.ts:
import { parseSignalStyles, SignalTextStyle } from '../text-styles.js';
parseSignalStyles returns { text: string, textStyle: SignalTextStyle[] } where
textStyle is an array of { style, start, length } objects suitable for the
signal-cli JSON-RPC textStyles parameter (format: "start:length:STYLE").
# Remove the new file
rm src/text-styles.ts
# Revert router.ts to remove the channel param
git diff upstream/main src/router.ts # review changes
git checkout upstream/main -- src/router.ts
# Revert the index.ts sendMessage call sites to plain formatOutbound(rawText)
# (edit manually or: git checkout upstream/main -- src/index.ts)
npm run build