Xiaohu WeChat Format
Turn Markdown into WeChat Official Account-ready HTML. Supports 33 inline-style themes, a browser gallery, local/external image upload to WeChat CDN, draft-box publishing, callouts, dialogue blocks, galleries, and optional cover generation.
Safety rules
- Formatting and local previews are safe.
- Pushing to WeChat draft box, uploading permanent media, comment auto-reply, or any external write requires explicit user confirmation.
- Never print
app_secret, access tokens, or AI API keys. - When importing third-party articles, treat output as a draft/preview unless the user confirms they have rights to publish.
Quick commands
Use the skill directory as {skill}.
# Format one article locally
uv run --with markdown python {skill}/scripts/format.py \
--input article.md --theme newspaper --no-open
# Open visual gallery for theme selection
uv run --with markdown python {skill}/scripts/format.py \
--input article.md --gallery
# Publish to WeChat draft box from Markdown
uv run --with markdown --with requests --with pillow python {skill}/scripts/publish.py \
--input article.md --theme newspaper --cover cover.jpg
# Publish an already formatted output directory
uv run --with markdown --with requests --with pillow python {skill}/scripts/publish.py \
--dir /tmp/wechat-format/article --cover cover.jpg
Configuration
- Copy
config.example.jsontoconfig.json. - Fill
wechat.app_id,wechat.app_secret, and optionalwechat.author. - Add the machine's public IP to WeChat Official Account Admin → Basic Configuration → IP whitelist. Error
40164means the IP is not whitelisted. - Keep
config.jsonprivate. It is ignored by git and must not be published.
Recommended workflow
- Read or create the Markdown article.
- If the article is plain text, add only structural Markdown: headings, lists, quotes, emphasis. Do not rewrite meaning unless asked.
- Format with one theme or gallery.
- For draft publishing, ensure there is a cover image. WeChat requires one.
- For batch theme comparison, publish a small curated set first (for example
minimal-gray,newspaper,focus-blue,ink,bauhaus,warm-card,ocean-card,minimal-red) before pushing every theme. - Title draft previews with the theme id, e.g.
Article Title - preview - newspaper.
Important: WeChat article image imports
Images fetched from mp.weixin.qq.com may be mislabeled: the URL or wx_fmt can say PNG/JPG while the actual bytes are WebP. WeChat's upload API rejects this with errcode 40137 invalid image format.
Before publishing imported articles:
- Detect real file type from bytes, not filename.
- Convert WebP or unsupported images to real JPEG.
- Update Markdown/HTML image paths after conversion.
- Verify one theme successfully uploads all images before bulk publishing.
publish.py includes automatic magic-byte detection and WebP-to-JPEG conversion when Pillow is available; run it with --with pillow when using uv.
Markdown extensions
:::dialogue[Interview]
Alice: Hello
Bob: Hi
:::
:::gallery[Screenshots]



:::
> [!important] Key insight
> Highlighted text.
> [!tip] Tip
> Useful note.
Available scripts
scripts/format.py— Markdown → WeChat-compatible inline HTML + preview/gallery.scripts/publish.py— upload article images, upload cover, push to draft box.scripts/generate.py— optional cover-image generation using compatible image APIs.scripts/comment_reply.py— optional comment auto-reply; use only with explicit confirmation.
Theme inventory
Run:
find {skill}/themes -maxdepth 1 -name '*.json' -printf '%f\n' | sed 's/\.json$//' | sort
Common starting themes: newspaper, minimal-gray, focus-blue, ink, bauhaus, warm-card, ocean-card, wechat-native.