# xiaohu-wechat-format turns Markdown into styled WeChat HTML

> xiaohu-wechat-format is a Claude Code skill that converts Markdown into inline-styled HTML that survives WeChat's editor, with a theme gallery, container syntax for dialogue and callouts, and a script that pushes the result to the drafts box. The trade is that the tool is opinionated about Chinese-language typography and publishes through the official account API, so your public IP has to be whitelisted.

**xiaohuailabs/xiaohu-wechat-format** — Claude Code 公众号一键排版+发布技能 | Markdown → 微信兼容 HTML → 推送草稿箱 | 30 套主题 + 可视化画廊

- Repository: https://github.com/xiaohuailabs/xiaohu-wechat-format
- Stars: 705 · Forks: 96
- Language: Python
- License: not declared
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/xiaohuailabs-xiaohu-wechat-format

## WeChat strips style tags, so every rule has to be inline

The problem is a specific quirk of the WeChat Official Account editor. It strips style tags and CSS classes, so a document built with a stylesheet arrives at the editor as unstyled paragraphs. This project works around that by writing all styles as inline style attributes on every element, and it applies a set of fixes for the resulting damage. It auto-adds spaces between Chinese and English or numbers, and it moves Chinese punctuation outside bold markers so that a bold span ending in a full-width comma no longer swallows the punctuation. It converts ul and ol elements to a section with flexbox, because WeChat mangles native lists. It transforms external links into footnotes, because WeChat blocks external links, and it processes both Obsidian wiki-links in the form of an image reference and standard image references. Callout blocks with tip, important and warning markers are rendered with distinct colors, and dialogue blocks become chat-bubble layouts.

## The theme count differs between the header and the catalogue

The theme system is the part a user actually picks from, and the numbers in the documentation do not quite agree, which is worth knowing before you plan around them. The opening description says 85 themes, from newspaper-style serif to neon cyberpunk, with card, timeline and hero layouts included. The themes section is headed Themes (30) and breaks the list into standalone styles, curated styles and a template series. The standalone group has nine entries, Terracotta, ByteDance, Chinese, Newspaper, GitHub, SSPAI, Bauhaus, Ink and Midnight, each with an identifier and a one line description of its look. The curated group has seven, including WeChat Native, and the template series is described as four layouts, Minimal, Focus, Elegant and Bold, each in several colour variants. The gallery feature says it previews 34 curated themes across 10 categories. The repository description also says 30 themes. So the catalogue is at least thirty and the gallery shows more than that, and the exact number depends on which part of the README you read.

## A gallery picker that renders your article before you commit

The gallery is the part that makes the theme list usable, because the README describes it as a preview of curated themes with your actual article, where you can switch font size between 15, 16 and 17 pixels and the font family between serif, Song, Kai and rounded, live, and then pick one. The three font families matter for Chinese typography specifically, since Song and Kai are conventional choices for different registers of Chinese text. The formatting command opens the gallery in a browser, which means the loop is: format, look, decide, format again. When the tool runs under Claude Code the same loop happens in conversation, since the README shows the request that triggers it and the resulting sequence of steps, where Claude reads and analyses the article, auto-enhances the content with dialogue containers and callout blocks, opens the gallery, and then formats and optionally publishes once you name a theme.

## Container syntax gives you dialogue and callouts before formatting

Before the formatting step, you can mark up the Markdown with a small set of containers, and this is where the AI content enhancement fits in. The tool auto-detects dialogue, key quotes and image sequences and wraps them in styled containers, and the explicit syntax is also supported directly:```markdown
:::dialogue[Interview Title]
Alice: Hello there
Bob: Hi, how are you?
:::

:::gallery[Screenshots]
![](img1.jpg)
![](img2.jpg)
![](img3.jpg)
:::

> [!important] Key Insight
> This is the important takeaway

> [!tip] Pro Tip
> A useful tip for readers
``` The dialogue container takes a title, and the gallery container takes a list of images, and there are further container types for byline, stat and longimage. The README also shows Obsidian style callout syntax with tip, important and warning markers, which is rendered with distinct colours. The point of the enhancement step is that a plain transcript in Markdown looks like a transcript, and a transcript with a dialogue container looks like an interview, and the difference is a few lines of syntax rather than a redesign.

## Publishing pushes to the drafts box, not straight to subscribers

The publish step uploads the images to the WeChat CDN and pushes the article to your drafts, and that distinction is deliberate in the design. Nothing goes to your readers from the tool; you still review the draft in the WeChat editor before it goes live, which is also how you get around the fact that the output is inline-styled HTML rather than a first-class WeChat document. The command takes a directory and an optional cover image. Credentials come from the config file, and the shape of the wechat section is:```json
  "output_dir": "/tmp/wechat-format",
  "vault_root": "/path/to/your/obsidian/vault",
  "settings": {
    "default_theme": "newspaper",
    "auto_open_browser": true
  },
  "wechat": {
    "app_id": "YOUR_APP_ID",
    "app_secret": "YOUR_APP_SECRET",
    "author": "Author Name"
  },
  "cover": {
    "output_dir": "~/Documents/covers",
    "image_generation_script": ""
``` and the README states plainly that the wechat section is only needed for publishing since formatting works without it, and that the cover section is only needed for cover image generation. The app_id and app_secret come from the WeChat Official Account admin area under Settings and Basic Configuration. There is one operational gotcha the README flags as important: you have to add your public IP to the WeChat IP whitelist, otherwise the API calls fail with error 40164.

## Cover images come from a Gemini call you configure yourself

The cover generator lives in its own cover/ directory and calls the Gemini Image API, or a compatible third-party gateway, to produce the cover at the 2.35 to 1 ratio WeChat expects, in a Notion illustration style. Setting it up is a config file with a base_url, a model name and an api_key, and the README names the model as gemini-3-pro-image-preview. Generating a cover is a Python command taking a config path, a prompt file and an output path, and the prompt template and the full workflow are in cover/SKILL.md. The separation is deliberate in the layout, because the top level holds scripts/, templates/, themes/ and cover/ as distinct directories, so a formatting-only user never has to touch the image generation path or hand it an API key.

## A skill directory, not a package, with a minimal dependency list

The installation model is a skill folder rather than a Python package, which is why the quick start is a clone into a directory. The README puts the repository under the skills directory, and the whole sequence is:```bash
# Install
cd ~/.claude/skills/
git clone https://github.com/xiaohuailabs/xiaohu-wechat-format.git
cp xiaohu-wechat-format/config.example.json xiaohu-wechat-format/config.json
pip3 install markdown requests

# Format an article (opens gallery in browser)
python3 scripts/format.py --input article.md --gallery

# Format with a specific theme
python3 scripts/format.py --input article.md --theme newspaper

# Publish to WeChat drafts
python3 scripts/publish.py --dir /tmp/wechat-format/article-name/ --cover cover.jpg
``` copies the example configuration to config.json, and installs the two Python libraries it needs with pip. The runtime requirements are listed as Python 3, the markdown library and the requests library for publishing, and that is the whole dependency list, which is a fair point in a project that also drives an image generation API. The repository root holds SKILL.md, the two READMEs in English and Chinese, the example config, and the cover, docs, scripts, templates and themes directories. The licence is stated as MIT at the end of the README, though the licence field in the repository metadata is left as unknown, so the file in the repository is the one to check.

## Conclusion

xiaohu-wechat-format suits a Chinese-language WeChat Official Account author who writes in Markdown, wants to pick a visual theme from a gallery rather than hand-write inline styles, and wants the article pushed to the drafts box without opening the WeChat editor. It does not suit a writer outside the WeChat ecosystem, since the output is specifically built around WeChat's editor constraints, and it does not suit an account that cannot expose a public IP to the WeChat API. Before adopting, create config.json from config.example.json and fill in the app_id and app_secret, and note that the last push to the repository was on 2026-06-12 with no GitHub releases published.

## FAQ

### How do I install xiaohu-wechat-format?

Clone the repository into your Claude skills directory, copy config.example.json to config.json, and install the dependencies with `pip3 install markdown requests`. The README gives the exact sequence, which also creates the config file the later commands read.

### How do I publish a formatted article to WeChat?

Run `python3 scripts/publish.py --dir /tmp/wechat-format/article-name/ --cover cover.jpg`. The script uploads the images to the WeChat CDN and pushes the article to your drafts. You need the app_id and app_secret in the wechat section of config.json, and your public IP must be in the WeChat IP whitelist or the calls fail with error 40164.

### Why does xiaohu-wechat-format write inline styles instead of a stylesheet?

The WeChat editor strips style tags and CSS classes, so a stylesheet would arrive unstyled. The tool writes all styles as inline style attributes on every element, and it works around the damage by fixing CJK spacing, moving Chinese punctuation outside bold markers, converting lists to section with flexbox, and turning external links into footnotes.

### What container syntax does xiaohu-wechat-format support?

It supports explicit containers for dialogue, byline, stat, gallery and longimage, plus callout blocks with tip, important and warning markers. The README shows the dialogue container with a title and the gallery container with a list of images, and notes that the tool also auto-detects dialogue, key quotes and image sequences and wraps them in styled containers.

### Do I need WeChat credentials to format an article?

No. The README states that the wechat section is only needed for publishing since formatting works without it, and the cover section is only needed for cover image generation. The theme gallery, the container syntax and the HTML output all work from a config file with no WeChat fields filled in.

## Sources

- [Issues](https://github.com/xiaohuailabs/xiaohu-wechat-format/issues)
- [README](https://github.com/xiaohuailabs/xiaohu-wechat-format/blob/main/README.md)
- [xiaohuailabs/xiaohu-wechat-format on GitHub](https://github.com/xiaohuailabs/xiaohu-wechat-format)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/xiaohuailabs-xiaohu-wechat-format
