Install
openclaw skills install @clarezoe/research-to-wechatA native research-first pipeline that turns a topic, notes, article, URL, or transcript into a sourced article with an evidence ledger, polished Markdown, inline visuals, cover image, WeChat-ready HTML, browser/API-ready draft assets, and optional multi-platform distribution. Use when the user wants 深度研究、改写成公众号、写作、排版、配图、HTML 转换、公众号草稿生成、多平台分发.
openclaw skills install @clarezoe/research-to-wechatUse this skill as a native, research-first article system. It does not route execution to external skills.
[text](url) into text (url) because WeChat forbids clickable links.rewriteMode: methodology-only only: capture is still mandatory, but the captured original and its images are kept privately for comparison and are excluded from the deliverable; see original-rewrite.md.Path A: research-first article
use for: topic, keyword, question, notes, transcript, subtitle file
goal: build the article from a research brief and evidence ledger
Path B: source-to-WeChat edition
use for: article text, markdown file, article URL, WeChat URL
goal: preserve the useful source core, then rebuild it for WeChat reading and distribution
Exception — rewriteMode: methodology-only only: when the user supplied readable source material and explicitly asked for a rewrite, this preservation goal is superseded — keep only the abstract methodology and write an independently researched new article. See original-rewrite.md.
Optional mode (orthogonal to the path choice):
rewriteMode: methodology-only
activate only when BOTH hold: readable source material was actually obtained, AND the user explicitly asked to rewrite / 改写 / 重写 / recreate an article from it.
do not activate for: topic only, render-only, save-only, translation-only, reference-only, voice-samples-only, or any explicit "不要改写" restriction.
ambiguous intent or failed source capture blocks the mode — ask one question, never keyword-match and never fall back to topic generation.
when inactive, everything below behaves exactly as written, no TYPESAFE_API_KEY is needed, and zero Jev calls are made.
full contract: original-rewrite.md.Default routing:
tutorialdeep-analysisnewsletterPDF policy:
imgs/source-fig-*.pngsource.mdrewriteMode: methodology-only only: extracted figures stay private comparison evidence; plan new visuals for the new article and keep imgs/source-fig-*.png out of the deliverable image set. See original-rewrite.md.Video policy:
Create one workspace per article:
research-to-wechat/YYYY-MM-DD-<slug>/
Required assets:
source.mdbrief.mdresearch.mdarticle.mdarticle-formatted.mdarticle.htmlmanifest.jsonimgs/cover.pngRequired frontmatter in final markdown:
titleauthordescriptiondigestcoverImagestyleModesourceTypestructureFramedisclosuremanifest.json must capture:
pathModestyleModestructureFramesourceTypeconfidencedraftStatusmanifest.json.outputs.wechat must include:
markdownhtmlcover_imagetitleauthordigestimagesDetermine this SKILL.md directory as SKILL_DIR, then use ${SKILL_DIR}/scripts/<name>.
| Script | Purpose |
|---|---|
scripts/fetch_wechat_article.py | WeChat article fetch (mobile UA) |
scripts/wechat_delivery.py | Native WeChat delivery entrypoint (check, design-catalog, render, upload-images, save-draft, update-cover) |
scripts/install-openclaw.sh | OpenClaw skill installer |
scripts/jev_rewrite.py | Jev rewrite screening evaluator — only under rewriteMode: methodology-only (original-rewrite.md) |
This skill executes every stage itself:
python3 "${SKILL_DIR}/scripts/wechat_delivery.py" design-catalogpython3 "${SKILL_DIR}/scripts/wechat_delivery.py" renderpython3 "${SKILL_DIR}/scripts/wechat_delivery.py" upload-imagespython3 "${SKILL_DIR}/scripts/wechat_delivery.py" save-draftUse the internal contract in capability-map.md.
Resolve WeChat draft delivery in this order:
L0 official-http: WECHAT_APPID and WECHAT_SECRET are ready, so bundled scripts call the official media and draft APIs directlyL1 assisted-browser: only use a browser when the account setup or draft inspection needs human helpL2 manual-handoff: stop with exact file paths and required API fields when official delivery cannot proceedThe renderer reads an optional EXTEND.md for author-specific CTA content and preferences. This keeps the skill generic — CTA text, QR codes, and blog URLs belong to the author, not the skill.
Lookup order: project dir → ~/.config/research-to-wechat/ → ~/.research-to-wechat/
See author-config.md for the full format and field reference.
When EXTEND.md is present with a cta section, the renderer appends a styled CTA block after the article body. When absent, no CTA is rendered.
Resolve style in this order:
Use the full style system in style-engine.md.
Visual rendering is decided by:
styleModestructureFramelight or dark output modeRun the article through these phases:
intake and route selection
source packet, brief, and strategic clarification
research architecture with structured question lattice
research merge and evidence ledger
frame-routed master draft with normalization checklist, writing self-check, and machine-verified Chinese de-AI scan (Phase 5 must not proceed without running these):
# negation-contrast patterns (must be 0 hits)
grep -n '不是.*而是\|不仅.*而且\|不只.*更\|不再.*而是\|已经不是' article-formatted.md
# em-dash count (≤5 in body)
grep -c '——' article-formatted.md
# exclamation marks (must be 0)
grep -c '!' article-formatted.md
微信敏感词合规检查(⛔ 必须通过才能继续):用 wechat-compliance-check 扫描 article-formatted.md,有命中则改写后重新扫描,直到零违规。
refinement, visual strategy, and image evaluation
⛔ Pre-delivery compliance gate (BLOCKING — must execute before Phase 8): Long sessions cause attention decay on early-loaded rules. Before proceeding to HTML rendering and draft save, you MUST:
cat the file, do not rely on memory). For WeChat projects this is ../AGENTS-wechat.md or the path specified in AGENTS.md.native WeChat HTML rendering via wechat_delivery.py render, image upload, draft save, and manifest.
Image upload rules:
imgs/cdn-urls.json already exists from a previous upload, skip re-uploading unchanged images. Only upload new or modified files (compare filename + file size/mtime).wechatqr.png (CTA QR code) must reuse the existing CDN URL from project-level images/wechatqr.png or a previous cdn-urls.json. Never re-upload the same QR code per article.cdn-urls.json (not overwrite).Draft save rules:
manifest.json already contains a media_id, pass --media-id to save-draft to update the existing draft. Never create a duplicate.draft/delete) immediately and keep only the original media_id.manifest.json is the single source of truth for media_id.Cover = the 2.35:1 cover.png, --cover-type image. Never the square crop.
The feed card and the article header both use the cover set on the draft. Use the wide cover.png (--cover-type image), not cover-thumb.png / --cover-type thumb: verified 2026-09-25, a square thumb gets center-cropped to the card's wide aspect and the bottom line of text is chopped off, so it reads as oversized and clipped. The wide cover keeps its one line of text in the visible band. cover-thumb.png is only a fallback where a square is explicitly required. Full rules — dimensions, the single-thumb_media_id two-crop reality, and crop-safe text layout — are in cover-design-guide.md.
To change ONLY the cover of an existing draft, use update-cover — not save-draft.
save-draft rewrites the whole article from local html/markdown (risking body drift and needing a re-render). update-cover reads the live body back via draft/get and re-pushes only thumb_media_id, so the body cannot move:
python3 "${SKILL_DIR}/scripts/wechat_delivery.py" update-cover \
--media-id "$MEDIA_ID" --cover-image imgs/cover.png --cover-type image
It reads the draft back after writing (same BLOCKING verification as below) and, like every write, still resets 原创/赞赏/合集 — so run it BEFORE those are set in the editor.
⛔ After every draft write, read the draft back (BLOCKING).
draft/update returning errcode:0 does not mean the content landed. Observed 2026-09-25: the API reported ok while the live draft still held the previous title and body. Never judge success from the write response, and never report success to the user from it.
python3 -c "
import json,urllib.request,sys
token=open('/tmp/wx_token.txt').read().strip()
media_id=sys.argv[1]
req=urllib.request.Request('https://api.weixin.qq.com/cgi-bin/draft/get?access_token='+token,
data=json.dumps({'media_id':media_id}).encode(),headers={'Content-Type':'application/json'})
a=json.load(urllib.request.urlopen(req,timeout=30))['news_item'][0]
print('TITLE:',a['title']); print('LEN:',len(a['content']))
for p in sys.argv[2:]: print(('OK ' if p in a['content'] else 'FAIL'),p)
" <media_id> <distinctive phrase from the new body> ...
Compare the returned title/digest against manifest.json and probe the body for phrases unique to the latest revision (not phrases that also existed in the prior version — those cannot detect a stale draft). Any mismatch means re-push and re-verify.
Backend-only fields the draft API cannot set.
原创声明 (original declaration), 赞赏 (reward), and 合集 (album) are not in the articles schema — it accepts only article_type, title, author, digest, content, content_source_url, thumb_media_id, need_open_comment, only_fans_can_comment, image_info, cover_info, product_info. Setting them requires driving the mp.weixin.qq.com editor in a logged-in browser. Order within the editor matters: declare 原创 first (赞赏 stays disabled until it is), then 赞赏, then 合集, then click 保存为草稿 or everything is lost. Saving in the editor rewrites the draft author field to the 赞赏 account name. Check the project AGENTS file for the account's specific values.
A later draft/update silently wipes all three. Verified 2026-09-25: re-pushing content after setting them reset 原创 to 未声明, disabled 赞赏, and cleared 合集. Set them only once the body is final, and never call draft/add/draft/update afterwards. If the body must change again, the order is: edit → draft/update → read back → re-set all three in the editor → 保存为草稿.
Before draft save, run HTML compliance check (must all pass):
grep -c 'class=' article.html # must be 0
grep -c '<style' article.html # must be 0
grep -c '<a href' article.html # must be 0
# outermost <section> must have background
python3 -c "import re;h=open('article.html').read();m=re.search(r'<section[^>]*>',h);print('OK' if m and 'background' in m.group() else 'FAIL')"
Known issue: render collapses newlines inside <code> blocks.
The renderer converts markdown fenced code blocks into single-line <code> content, stripping all \n characters. Multi-line code will display as one long line.
Detection: python3 -c "import re;h=open('article.html').read();codes=[c for c in re.findall(r'<code>(.*?)</code>',h,re.DOTALL) if len(c)>80 and '<br' not in c];print(f'{len(codes)} collapsed code blocks' if codes else 'OK')"
Fix: extract code blocks from the source markdown (which preserves newlines), HTML-escape them, replace \n with <br/>, and substitute back into the rendered HTML. WeChat ignores literal \n in HTML — only <br/> produces visible line breaks. When HTML-escaping code content, only escape &, <, >, and ". Do NOT escape single quotes (' → ') — WeChat renders the entity literally as ' instead of '. This must run after render and before save-draft.
Known issue: render outputs <thead> without dark background.
In dark mode, table headers render with browser-default white/transparent background, making header text invisible. Fix: add background:#1E293B (or the design's surface color) to <tr> and <th> inside <thead>. Also ensure <td> has explicit background matching the page background.
Known issue: render duplicates ordered list numbering.
Markdown 1. 2. 3. becomes <ol><li>1. text</li> — the <ol> auto-numbers AND the literal 1. prefix remains. Fix: strip the leading N. from each <li> content.
Known issue: render keeps the H1/H2 title in the HTML body.
WeChat article titles are set via the draft API title field, not in the HTML body. The renderer copies the markdown # title into an <h2>. Per WeChat typography rules, this must be removed. Fix: delete the <section> containing the <h2> that matches the draft title.
Known issue: --upload-map may not replace all image paths.
After rendering with --upload-map, verify that zero src="imgs/" local paths remain. If any survive, do a string replace pass in post-processing. Detection: grep -c 'src="imgs/' article.html must be 0.
Known issue: reference link section has oversized letter-spacing on mobile.
The body line-height:1.9 and font-size:15px cause long URLs in the reference section to spread out on mobile. Fix: override the reference section <p> tags with font-size:13px;line-height:1.6;word-break:break-all;text-align:left.
File path rule: always follow the project's AGENTS file for output directory.
This skill defaults to research-to-wechat/YYYY-MM-DD-<slug>/. If the project AGENTS specifies a different convention (e.g. YYYY-MM-DD-<slug>/ at project root), the project rule overrides this skill's default. Check the project AGENTS before creating the workspace directory.
optional multi-platform content generation and distribution
Phase 9 only executes when the user explicitly requests it.
Use the execution contract in execution-contract.md. Use the platform copy specs in platform-copy.md for Phase 8.
The skill is complete only when all of these hold:
class= attributes, zero <style> tags, zero <a href> links, and outermost <section> has explicit backgroundmanifest.json agrees with the actual output set and draft statedraft/get and its title, digest, and revision-specific body phrases match the local files — the write call's errcode:0 alone does not satisfy thiswechat-compliance-check returned zero violations on the final markdown