Model "prepare content", "write to remote draft", "submit for publishing", and "platform publishing complete" as distinct states. All WeChat Official Account API requests are sent by default through api.lovstudio.ai unified gateway, with the backend using a fixed egress to communicate with WeChat; the local machine does not need to be added to the WeChat IP whitelist.
Triggers
Activate when
- The user asks to import, sync, or save Markdown, HTML, or plain text to the WeChat Official Account draft box.
- The user asks to set the original declaration, recommendation text, author, read original link, or brand cover for an Official Account draft, and verify the saved result.
- The user asks to submit an existing
media_idfor formal publishing, or query the publishing status of an existingpublish_id. - The user asks to read the current draft, replace the cover, insert or modify a clearly defined section, and confirm the saved result.
- English triggers include “Publish this article to WeChat”, “Save this as a WeChat Official Account draft”, “Read this existing draft”, and “Verify that this edit persisted”.
Do not activate when
- The user only asks to design a cover, the first image of the body, or a unified brand component; use the corresponding article brand or cover Skill.
- The user only asks to generate local article content and does not ask to write it to the WeChat Official Account; use the article creation or layout Skill.
- The user only asks to analyze local Markdown but does not read the Official Account's remote state; use the article creation or audit capability.
Input Contract
Collect and confirm:
- Body: one Markdown, HTML, or plain text file. When the user provides the body only in the session, first save it as a temporary
.mdor.txtfile for this task. Regular draft creation must first calllovpen-cli, and receive the WeChat copy-state HTML it writes via--format wechat; do not receive the--format standaloneoutput and then rebuild the layout.compact-markdownis reserved only for explicitly diagnosing the old pipeline. - Content quality handoff: the publisher consumes canonical Markdown that has already completed content proofreading, and is not responsible for changing academic-style sections into catchy titles. When an article contains research, reviews, benchmarks, rankings, total scores, or radar charts, the precheck must see "Test Method", "Prompt", "Evaluation Metrics", "Scoring Method", "Scoring Example", and "Reproduction Method" before the results, and must see "Limitations" after the results; the
Promptsection must disclose at least one actually executed text. If missing, fail closed before any remote write. - Table of contents and small text: canonical Markdown provides stable H2/H3 headings and does not hard-code a presentational TOC; Lovpen generates the table of contents and reading time in the WeChat HTML based on the final sections, avoiding drift between the body and the two sets of TOC headings. Interspersed materials, sources, and extended links use understated small text in place; multiple items are split line by line or point by point, not squeezed into one paragraph, and not piled up at the bottom. See the complete convention at Lovpen Editing and Rendering Handoff。
- First image of the body: the first block of content in the Markdown for regular publishing must be an independent
4:3horizontal first image, located before the lead, and must be a different file from the share cover.3:4Vertical images, missing images, remote placeholder images, or directly reusing the finished share cover must not pass the precheck. - Body image captions: before Lovpen rendering, determine image by image whether readers need supplementary evidence, attribution, or explanation. Images that need captions must call
lov-image-decorator, use an explicit Caption to generate a derived file that does not overwrite the original image and a JSON receipt, then change the image references in the article copy to the derived file; images that do not need a Caption remain as-is, without usingPowered by ...fallback padding. - Publishing components: read the current official account brand Profile each time. Permanent
blocks.endcapmust include the approved bio, links, and enabled personal card;blocks.campaignsevents that are still open, not full, and not expired must be placed before the endcap. For detailed status and fields, see Profile-driven publishing components。 - Title: an explicit title takes precedence; Markdown can infer it from the first level-one heading. The final title must not exceed 32 characters.
- Cover: regular draft creation must first call
lov-wechat-branding-cover-composition, upload the JPG pointed to bycover-composition.jsonin itsshareCoverUpload, and pass in this receipt at the same time. The publisher will verify the schema, the official Logo SHA-256,publisherLogoPresentand the uploaded file path; art base images without a Logo, old covers, or other product assets must not be treated as the uploaded file. - Originality declaration: for new articles independently created by the current publishing account, the default is
true; when there is reposting, compilation, co-authorship, or unclear rights, do not guess and check it. - Article recommendation: by default, write a short recommendation of 8–24 Chinese characters, giving readers a memorable point first; do not repeat the title, do not write "this article will", and do not use the summary as the recommendation.
- Other optional fields: author (within 16 characters), summary (within 120 characters), Read Original URL, comment settings. When the user says "other defaults", keep the platform's current defaults and do not proactively flip unspecified switches.
- Target account and action: save as draft only, publish publicly immediately, or query an existing
publish_id。
Only hand the reader-facing body text to the platform. Supplementary background, character relationships, concerns, and other privateContext stay local.
Run the precheck first:
python3 <skill-dir>/scripts/preflight_article.py ARTICLE \
--cover COVER \
--cover-composition-receipt COVER_DIR/cover-composition.json \
--lovpen-wechat-html ARTICLE.lovpen.wechat.html \
--brand-profile BRAND_PROFILE \
--title "TITLE" \
--transport gateway \
--json
--allow-unverified-body-hero is only for explicitly diagnosing the old pipeline and must not be used for normal delivery.
When omitting optional parameters, do not pass empty strings. When the script exits non-zero, first fix errors;warnings needs to be handled when selecting the transport. When the body contains local or remote images, read references/transport-routing.md。
Status semantics
Always use the following statuses, and do not blur them with the word "publish":
prepared
-> draft_reading -> draft_read
-> draft_editing -> draft_saved
-> draft_creating
-> draft_created
-> draft_enriching
-> draft_ready
-> publish_submitted
-> publishing
-> published | publish_failed
draft_read: a comparable snapshot of the existing draft has been obtained, and no write was performed.draft_saved: the authorized modification of the existing draft has been saved, reloaded, and the before/after diff verification passed.draft_created:draft/addhas returnedmedia_id; the article is still in the official account draft box.draft_enriching: saving and reading back, through the logged-in editor's web private API, the originality declaration not covered by the public OpenAPI, or filling in other explicit fields.draft_ready: the draft has been saved and reloaded, and the originality declaration, recommendation, final cover, and other user-specified fields have all been read back.publish_submitted:freepublish/submithas returnedpublish_id; the task has just been accepted.publishing:freepublish/getreturns status 1, status 0 but no article identifier yet, or the task is still in progress when the waiting window ends.published: the status query returns 0, andarticle_idor the article URL is read back.publish_failed: the status query returns 2, 3, 4, 5, or 6; retain the status code, failed article number, and official details.
For the complete receipt fields, see references/result-contract.md。
Workflow
1. Identify the user's intent
- "Sync, import, save to draft box, generate draft" stops at
draft_created。 - "Official publish, public release, publish immediately" continues to submit and poll until the terminal state.
- When the user only provides
publish_id, query the status directly without rebuilding the draft. - When the user requests to read or modify an existing article, use this Skill's
existing-draftflow; do not rebuild the article package, and do not create duplicate drafts. - When creating a new draft, first read the brand Profile, write the permanent endcap and the currently active campaign into the canonical Markdown; then call
lov-wechat-branding-cover-compositionto generate the final cover and receipt, according to Image Caption preparation contract calllov-image-decoratorto process body images that need captions; finally calllovpen-clito generate the WeChat copy-ready HTML, then return to this flow. Caption decoration applies only to images that explicitly need captions, and does not mechanically apply a uniform bottom bar to all images.
2. Read or locally edit an existing draft
Fully read existing draft operations and article status contract:
- Use
media_id、appmsgidor the current edit page to uniquely locate the target, and read the before snapshot. - A read task stops at
draft_read, and must not perform a save just because of "check it". - For a modification task, first declare the fields allowed to change and the fields that must remain unchanged, then perform the minimal modification.
- Save and reload the same draft, and record the after snapshot.
- Use
scripts/verify_article_state.pyto verify the differences; report only after it passesdraft_saved。
If an existing draft needs a full rewrite or branding, first have lov-article-creator generate a local prepared version, then return to this flow to perform an explicit replacement. Deletion, overwriting the entire article, or changing permissions still requires a precise target and explicit authorization.
3. Choose the draft transport
Choose in the following order; for the detailed contract see references/transport-routing.md:
- By default, use the LovStudio unified gateway: body images, cover, draft creation, draft readback, official publishing, and status queries are all handled by the backend calling WeChat.
- When originality needs to be declared, use the logged-in editor session to call
mp.weixin.qq.com/cgi-bin/operate_appmsg; when visible formatting is needed or other fields need to be handled, use the logged-in browser. - Use OneShot direct connection or other direct transport only when explicitly diagnosing the old pipeline; it must not be used as the default publishing path.
AppSecret and the gateway API Key must be resolved by the locator of lov-env-management . Do not copy secrets into the article directory, command parameters, environment files, logs, screenshots, or receipts.
4. Create and verify the draft
Unified gateway path:
- First verify the content handoff of the canonical Markdown: the research review method chain is complete, the first block of the body is an independent
4:3horizontal lead image, H2/H3 are stable and there is no hardcoded presentational TOC; then use--brand-profileto verify the permanent endcap, personal card, and campaigns that are still open and not full. If any item is missing, duplicated, or misplaced, fail closed before writing to the remote. - Verify the Caption preparation result: all selected images have
lov-image-decoratorreceipts, the article references derived files, unselected images have not been rewritten, and Captions do not duplicate adjacent body text or captions. - Use
preflight_article.py --transport gatewayto verify the title, body, Lovpen WeChat copy-ready HTML, brand cover composition receipt, images, and extension fields. - Use
publish_via_gateway.pyto pass in the AppID, brand Profile, and two managed secret locators; do not pass secret plaintext. - The script uploads body images one by one via
material/uploadimg, then callsdraft/add。 - The script checks 20,000 characters against the rendered visible body, and checks 1,000,000 bytes against UTF-8 HTML; the raw HTML character count must not be treated as the 20,000-character limit.
- The script immediately calls
draft/getto verify the remote title, image count, cover asset, and body length. The Lovpen path must also compare the remote body node by node: WeChat is allowed to remove external-link<a>wrappers andpositionattributes, but the remaining tag order, class, CSS properties, and visible text must be preserved. - Only after read-back passes is
mediaIdrecorded, with status written asdraft_created。
First render through the real WeChat copy chain of lovpen-cli :
python3 <lovpen-skill-dir>/scripts/run_lovpen_cli.py \
--project-root LOVPEN_PROJECT_ROOT \
-- --json render ARTICLE.md \
--output ARTICLE.lovpen.wechat.html \
--format wechat \
--template-kit typora-newsprint
Only when the JSON receipt shows renderer_mode=wechat-browser-copy、clipboard_source pointing to extractWechatClipboardHTML, and the artifact root node is section.lovpen-rendererwith body styles inlined, is it handed to the publish script. Native mp-common-videosnap Shadow DOM may retain component isolation <style>; elsewhere in the article body, <style>:
python3 <skill-dir>/scripts/publish_via_gateway.py ARTICLE.md \
--lovpen-wechat-html ARTICLE.lovpen.wechat.html \
--app-id APP_ID \
--wechat-secret-locator WECHAT_SECRET_LOCATOR \
--gateway-key-locator GATEWAY_KEY_LOCATOR \
--brand-profile BRAND_PROFILE \
--cover COVER_DIR/share-cover-wide-logo.jpg \
--cover-composition-receipt COVER_DIR/cover-composition.json
The script does not parse and rebuild the body, nor does it strip class、style、span or tables; it only replaces the src of local JPG/PNG in the raw HTML string with upload placeholders, then replaces them with WeChat HTTPS addresses. Before and after upload, it must verify that the inline styles, class, span, table, and img counts are exactly identical, and compare the full-text SHA-256 after ignoring image src .--lovpen-html is retained as a compatibility alias, but the input contract likewise only accepts --format wechat artifacts.--allow-compact-markdown and --allow-unverified-cover are only for explicitly diagnosing the legacy chain and must not be used for normal delivery. The receipt also records the Lovpen artifact and brand cover composition evidence.
When a long article has multiple stable H2s or H2/H3s, manually read back the Lovpen HTML before delivery: the table of contents is located between the lead and the first chapter, includes a restrained estimated reading time, its entries match the final chapters, and there is no second Markdown table of contents; small-print references appear in place in the corresponding body text, with multiple items on separate lines. The font size, color, and spacing of the table of contents and reference notes must not overpower the body text.
The browser or explicit direct transport must also return the remote media_id or provide evidence of a draft-box reload. A single button click, progress completion, or local HTML generation is not evidence of a remote draft.
5. Fill in and read back editor fields
When a task requires an originality declaration or other fields not currently supported by the public OpenAPI,draft_created is not a deliverable final state.digest is a summary/recommendation field that the public draft API can write and that can be read back in the backend; do not rewrite the already verified digest。
- Use this Skill's existing-draft internal flow to open the draft corresponding to the just-created
media_idand obtain the editor pageappmsgid. Before writing, record the title, recommendation, originality status, cover, and other visible toggles; unspecified fields go into the keep-unchanged set. - Do not stuff undisclosed fields such as
api.weixin.qq.com/cgi-bin/draft/addordraft/update; the API may return success but silently discard them.copyright_type、original_article_typeinto - When content rights have been explicitly confirmed by the user, call the web private API script. The script reads the body and cover in the logged-in page context, writes numbered fields to
operate_appmsg, and does not write cookies or tokens into parameters, logs, or receipts:
python3 <skill-dir>/scripts/enrich_via_wechat_web_api.py \
--appmsg-id APPMSG_ID \
--title "TITLE" \
--author "AUTHOR" \
--digest "RECOMMENDATION" \
--source-url "SOURCE_URL" \
--original-category "艺术文化" \
--confirm-original-rights \
--receipt RECEIPT.json
--confirm-original-rightsis a required rights declaration gate and must not be guessed on the user's behalf. Private interfaces carry no stability commitment; when the page structure or fields drift, stop immediately and do not degrade to "request succeeded means done".- After saving, re-fetch the same edit page and it must be observed that
copyright_type=1and the requestedoriginal_article_type; at the same time, read back the recommendation text, cover asset, and non-target fields. - Only after all of them match, record
draft_ready。ret=0but when the originality status is unobservable, retaindraft_enriching, andverificationPending=true。
For the detailed hybrid chain, see references/editor-enrichment.md。
6. Formally publish an existing draft
When the user has explicitly requested public publication, use the just-verified media_id. If the task requires editor fields, it must first reach draft_ready:
python3 <skill-dir>/scripts/publish_existing_draft.py submit \
--media-id MEDIA_ID \
--app-id APP_ID \
--wechat-secret-locator WECHAT_SECRET_LOCATOR \
--gateway-key-locator GATEWAY_KEY_LOCATOR \
--wait-seconds 300 \
--receipt RECEIPT.json
The script is executed by default through the unified gateway, and parses the two keys from lov-env-management .--transport direct is retained for diagnostics only; the script does not output AppSecret, gateway Key, or access token.
If it is still publishing after the wait ends, retain publish_id, then query:
python3 <skill-dir>/scripts/publish_existing_draft.py status \
--publish-id PUBLISH_ID \
--app-id APP_ID \
--wechat-secret-locator WECHAT_SECRET_LOCATOR \
--gateway-key-locator GATEWAY_KEY_LOCATOR \
--receipt RECEIPT.json
If transport already provides a verified formal publication and status readback, its implementation may be reused, but it must still be reported according to this Skill's status and receipt contract.
7. Handle recoverable errors
40164: in the default chain, only check whether the backend's fixed egress is still on the official account whitelist; adding the local machine IP is not required; after recording the backend deployment and WeChat return details, fix the gateway configuration.40013: re-verify the AppID beginning withwx.40001/40125: re-obtain or reset the AppSecret.48001: check the account verification status and draft/publish interface permissions.- Body images were filtered out: save the images locally as JPG/PNG, rewrite the URLs via
media/uploadimg, then rebuild the draft. - Draft creation failed midway: check whether the permanent assets have already been uploaded; before retrying, avoid piling up cover assets repeatedly without basis.
Error replies must retain the stage, error code, interface details, request ID, time, and shortest recovery action, and provide copyable content.
Pre-completion checks
- Precheck has no
errors, and the title, Lovpen WeChat copy-state HTML, branded cover composition receipt, and body come from this input. - The target official account has been verified, and the AppSecret has not entered project files or output.
- The transport selected for body images can genuinely upload and rewrite URLs.
media_idis reported only as a remote draft;publish_idis reported only as a submitted task.- Only when
freepublish/getstatus is 0 and the article identifier is read back, report public publication as complete. - The receipt includes the input summary, actions, remote identifiers, status, time, and copyable error details.
- The Lovpen path also records the pre-submission
lovpenFidelityVerified=trueand the remoteremoteFidelityVerified=true; the latter must list the tags/attributes actually cleaned by WeChat and prove that the remaining tags, classes, CSS, and text are unchanged. standalone HTML is explicitly rejected rather than silently degraded. - The share cover of the branded article is read back as the final composite with
publication.logo; the first block of the body is an independent4:3horizontal lead image, which is not the same file as the share cover, and the platform title is not written again in the body. - The methods, actual prompts, metrics, scoring rules, scoring examples, reproduction methods, and limitations of research evaluation articles have passed precheck in the canonical Markdown; the publisher did not package content issues as formatting issues or mask them with remote success.
- When an originality statement is required, the receipt transport is
wechat-web-private-api、originalVerified=true、editorFieldsVerified=true, and the read-back after saving and reloading has been stored forcopyright_type=1and the target category; obtaining onlyoperate_appmsg ret=0does not count as complete. Recommendation text, cover image, and other specified fields must likewise be read back consistently, and unspecified settings remain at platform defaults. - All body images that require a reader-visible Caption have had derived files generated by
lov-image-decoratorand receipts read back; the Caption only handles evidence explanation, necessary attribution, or explanatory tasks, does not repeat the alt text, body text, or internal production notes, and does not imply unauthorized brand endorsement. publicationComponentsVerified=true; the permanent brand footer and personal card have appeared, currently open, not full, and not expired campaigns are located before them, and full or ended campaigns have not been mistakenly included.lovpenEditorialRenderingVerified=true; the long-form table of contents is generated by the final HTML based on H2/H3 and is located before the first chapter , and the canonical Markdown has no duplicate TOC; small-print materials are in place, low-key, with multiple items on separate lines, and are not piled up at the end of the document.
Official endpoints, field limits, and status codes are in references/official-api.md。