| name | wxmp-draft |
| description | End-to-end pipeline to turn a Markdown research report into a WeChat Official Account (公众号) rich-graphics article, upload images, and save as a Draft (草稿) via WeChat APIs. Never publishes. |
| compatibility | opencode |
| metadata | {"language":"zh-CN","output":"wxmp-draft","safety":"no-publish"} |
| license | MIT |
What This Skill Does
Turn a .md research report into a WeChat Official Account rich article and save it as a Draft:
- Rewrite into a WeChat-friendly narrative (70% hardcore tech, 30% sharp metaphors; precise, entrepreneurial).
- Produce image plan + image captions.
- (Optional) Generate a cover image and “data card” images locally.
- Call WeChat APIs to:
- get
access_token
- upload cover as permanent material and obtain
thumb_media_id
- upload in-article images and obtain URLs
- create draft via
draft/add
Hard rule: DO NOT publish / mass-send. Only draft.
Key Behavior (Per H2 Images + Typography)
- One web-sourced image per H2: with
--auto-web-images, the script searches Wikimedia Commons, downloads a suitable image, uploads to WeChat via uploadimg, then inserts it right after each H2 section heading.
- No captions under images: inserted images are
<img> only (no visible attribution/caption text).
- Attribution kept in metadata: source/license is stored in cache JSON (not rendered in the article).
- WeChat-stable formatting: headings are rendered as
<p style=...> blocks (not relying on <h1>/<h2>/<h3>), so Markdown hierarchy is obvious in the WeChat editor.
- Tech heading styles: Chapter (章) headings use a dark "terminal" panel style; section (节, like 2.1) headings use a light "blueprint" card style; tertiary headings remain minimal.
- Title behavior (from-markdown): WeChat draft title is auto-shortened to ~10 tokens (LLM) while the body keeps the full original Markdown H1 (including bold emphasis).
- No auto subtitle injection (from-markdown): digest is used for WeChat
digest field only; it is not inserted under the H1 to avoid duplicating the first paragraph.
- Tables (default): Markdown tables are kept as real HTML
<table> and restyled with WeChat-safe inline CSS for mobile readability.
- Tables (legacy image mode): use
--table-mode image to convert Markdown tables into {{IMG:table-*}} placeholders (optionally render/upload as images with --gen-images).
Inputs
- Markdown file path (required)
- Example:
/Users/wangweiyang/Downloads/游戏运维监控工具推荐.md
- WeChat config file path (required for live run)
- Default:
~/Downloads/wxmpdev.config
- Format supported:
- env style:
APPID=...
APPSECRET=...
AUTHOR=... (optional)
ACCESS_TOKEN=... (optional; temporary token override)
PROXY=http://user:pass@host:port (optional; route traffic via whitelisted egress)
HTTPS_PROXY=... / HTTP_PROXY=... (optional)
- JSON style:
{ "appid": "...", "appsecret": "...", "author": "...", "access_token": "..." }
Safety Rules (Non-negotiable)
- Never log or print secrets:
AppSecret, access_token, request bodies containing tokens.
- Do not call publish endpoints:
- No
/cgi-bin/freepublish/*
- No
/cgi-bin/message/mass/*
- WeChat constraints:
- In-article images must be uploaded via
media/uploadimg and use returned URL.
- Cover must use permanent material
media_id as thumb_media_id (commonly uploaded via material/add_material).
Operational Notes (WeChat IP Whitelist)
If your Official Account has IP whitelist enabled, WeChat will reject cgi-bin/token with errcode=40164.
Two ways to proceed:
- Add this machine's public egress IP to the WeChat IP whitelist.
- Use
ACCESS_TOKEN=... in config (obtain the token from a whitelisted environment).
You can print best-effort public IP via:
wxmp-draft --draft-only --print-egress-ip
Expected Output
- A local result JSON (includes the created
draft_media_id on success)
- A local manifest/cache for idempotency (avoid duplicate uploads/drafts)
- A readable
out/last_render.html for human inspection
Recommended Execution
1) Draft the article content (LLM rewrite)
Read the input Markdown and produce a structured article spec (JSON) with:
title (<= 32 chars)
digest (<= 128 chars)
author (<= 16 chars, optional)
content_html (WeChat-safe HTML)
images: list of assets to upload
- cover asset:
{ "id": "cover", "kind": "cover", "path": "...", "alt": "...", "caption": "..." }
- inline assets:
{ "id": "table-1", "kind": "inline", "path": "...", "alt": "...", "caption": "..." }
In content_html, reference inline assets using placeholders:
The uploader will replace placeholders with WeChat-hosted image URLs.
2) Run the uploader (draft-only)
Use the helper script:
wxmp-draft \
--input "/Users/wangweiyang/Downloads/游戏运维监控工具推荐.md" \
--config "~/Downloads/wxmpdev.config" \
--mode from-markdown \
--table-mode html \
--gen-images \
--auto-web-images \
--web-image-source auto \
--image-query-mode llm \
--draft-get-verify \
--draft-only
Notes:
- To preserve deep-research content, prefer
--mode from-markdown and use --image-query-mode llm to let the model generate better image queries only.
--mode llm rewrites the article body; avoid it if you want the Markdown content kept verbatim.
--gen-images generates a cover image and renders any remaining non-table placeholders (e.g. diagrams/checklists) into image cards.
- For table images specifically, you must use
--table-mode image.
--inline-cover (optional) inserts the cover image into the body; default is off to keep the strict "one image per H2" rule.
Test Command (No Publish)
After config exists, verify the end-to-end draft save:
wxmp-draft \
--input "/Users/wangweiyang/Downloads/游戏运维监控工具推荐.md" \
--config "~/Downloads/wxmpdev.config" \
--mode from-markdown \
--gen-images \
--auto-web-images \
--draft-get-verify \
--draft-only
This must print a final line containing: Draft created: media_id=....