SuperAPI AI Directory

soia-pkm-publish

General & other

View repository

Updated 10-16 04:56

About this skill

soia-pkm-publish

The PKM loop'spublishing stage (publish): take the compose finished article drafts produced, adapt them into formats for each platform and deliver them. The core scenario is theWeChat Official Account(formatting is the most labor-intensive), followed by X thread and Xiaohongshu cards.

Reference: an archived article in the vault about the Obsidian + AI WeChat Official Account formatting workflow—this skill is its implemented realization; do not write the real paths of a personal vault into a public skill.

Client-readable description

What this skill can do

Adapt and publish finished article drafts to multiple platforms—WeChat Official Account (formatting + push to drafts), X thread, Xiaohongshu cards. The core is the WeChat Official Account: render into inline-style HTML that complies with the "WeChat platform red lines" according to the emphasis density model, and after passing mechanical validation, call the WeChat draft/add API to push to the drafts box (only create drafts, never auto mass-send)

The client wants The skill will do The client can see
Complete the work covered by this skill Read the user request, necessary context, and this skill's main workflow, and execute the minimal reliable steps The client will see Obsidian/vault file changes, terminal logs, generated artifact paths, and the final receipt.
Missing dependencies, permissions, configuration, or keys Stop actions that require external state, and clearly state what is missing Install commands, application addresses, configuration paths, or questions requiring client confirmation
Execution completed Summarize successes, skips, failures, file changes, and validation results A completion receipt that can be copied into a ticket/log

How the client uses it

  1. State the goal in natural language and provide the necessary inputs: files, URLs, repo, workspace, proposal, vault, or platform account status.
  2. The agent first determines whether this skill is triggered, then checks dependencies, configuration, permissions, and risky actions.
  3. For actions that can be dry-run or previewed, provide a preview first; for actions involving deletion, overwriting, sending, publishing, or writing remote state, seek client confirmation first.
  4. After execution, verify the real output; do not substitute "looks successful" for evidence.
  5. The final reply must give the client a visible summary: what was done, log summary, file changes, problems, and next steps.

Dependencies and installation

Install this skill (single skill):

npx skills add soia-team/soia-open-skills -g -a '*' -s soia-pkm-publish -y

Configuration conventions:

~/.config/soia-skills/soia-open-skills/soia-pkm/soia-pkm-publish/config.yml
SOIA_PKM_PUBLISH_CONFIG_FILE=<custom-config-path>
  • If this skill does not need private configuration, you may skip creating config.yml。
  • If an API key, cookie, session, provider home, or local path is needed, it can only go into a private config.yml, the process environment, or the provider's own login state; it must not be written into the repository, vault body, or logs.
  • Strong dependencies, optional dependencies, and third-party skill relationships must be based on this SKILL.md subsequent "dependencies / prerequisites / resources / boundaries" description; if it is not clearly stated, first supplement the description or ask the client, and do not guess.
  • Third-party skills may only declare dependencies and installation methods; do not directly modify third-party skill files.

Logs and completion receipt

Every execution must let the client see the process and the result. Minimum receipt format:

完成:<一句话说明本次完成了什么>。

日志摘要:
- started: <检查到的输入/配置/依赖,不打印秘密值>
- processed: <数量或范围>
- created/updated: <数量或路径>
- skipped/failed: <数量和原因>

文件变化:
- <绝对路径或“未改动文件”>

验证:
- <运行过的检查、命令或人工核对点>

问题与下一步:
- <缺 key / 缺依赖 / 需要客户确认 / 建议下一条命令;没有则写“无”>

Before writing: read personal context

Before adapting to any platform, first read 00_Obsidian系统/个人说明书.md §5 "Platform Positioning", and according to that platform'saudience and toneadjust the wording. What is built into this skill are the various platforms'formatting rules(below); what the personal specification supplements is thetone and audience positioning. The two stack together—correct format does not equal correct tone. If the personal specification lacks this file or lacks that platform's definition, fall back to the generic format.

Official account publishing (main process)

WeChat platform red lines (must be followed)

The official account's built-in editor (web paste,draft/add API) will actively filter/strip a large number of HTML/CSS constructs— once well-formatted HTML hits the red lines below, after pasting or pushing, the styles will most likely disappear entirely. Before rendering, first self-check against this list;scripts/render_wechat.py has been implemented according to this,scripts/validate_wechat_html.py is the mechanical validator for this list (hard violations directly exit 1).

What must not be done (prohibited; if present it will be eaten/stripped)

  • <div> — the WeChat editor does not recognize it; for block-level containers always use <section>(multi-line containers) or <p>(single paragraph) instead.
  • class="..." / id="..." — whether by copy-paste or API push, it will be stripped; styles can only survive via inline style="" .
  • position / float — layout-type CSS is not supported by the editor; use margin/padding/text-align and other flow layouts instead.
  • @media / @keyframes — responsive breakpoints and animation rules are discarded entirely; the official account body has neither breakpoints nor any need for animation.
  • CSS variable var(--x) usage and --x: ... declarations — custom properties are not supported; colors/sizes must be written as literal values (this skill's alternative: theme colors are defined centrally at the top of the rendering script as Python constants, rather than CSS variables).
  • <style>...</style> entire block — embedded/external stylesheet rules never take effect; styles must be inlined one by one on the tag's style="" .

What must be done this way (mandatory, otherwise styles will most likely be lost after pasting)

  • All styles are written inline in the style="" attribute, without relying on any selector.
  • Every visible text node is wrapped in a <span style="..."> layer—the editor/copy-paste often takes styles by "tag boundaries"; bare text (directly under <p>/<section>/<li> , without another <span>wrapper) is most likely to lose styles when pasted. <code>/<pre> The monospaced text inside is itself "displayed as-is" and is not forced to be wrapped again.
  • Keep punctuation style consistent (Chinese body text is recommended to use full-width; code/English use half-width), to avoid full-width and half-width mixing looking messy.
  • Images: in the body, first use <img src="..."> as a placeholder; before actual publishing, the image must be uploaded to the WeChat material library and replaced with a CDN URL (scripts/publish.py is responsible for this step); local paths/external image links most likely will not display in the official account backend.
  • Code blocks: WeChat does not support true syntax highlighting components; use an inline-styled <section> wrapper <code style="...font-family:monospace..."> to simulate the "code block" look of monospaced font + background color.

Self-check order: first manually go through the "must not be done" list above, then run validate_wechat_html.py Do a mechanical review— human + script double insurance; if there are hard violations, fix the rendered result first, and only after it passes (exit 0) proceed to the step of pushing to the draft box.

Layout rules: emphasis density model

Three levels; the further down you go, the "heavier" it gets and the more you need to control the quantity:

Level Purpose Markdown / Implementation Quantity within the length
Anchor layer Headings, the most important judgment sentences in the whole text (golden lines) #/## Headings; conclusions that stand alone as sentences Whole piece ≤5 places (headings + golden lines combined)
Marking layer Highlight keywords/phrases within paragraphs to help readers skim **加粗**(theme color),==高亮==(red bold) 1–3 places per paragraph
Container layer Content blocks that need to break out of the body text visually Quote block → golden line card, code block, image Triggered as needed; no hard upper limit but do not overuse
  • The anchor layer's "whole piece ≤5 places" is a hard constraint; headings and golden lines are counted together, not 5 places each.
  • The marking layer follows L1/L2 from the original three-level emphasis:**...** is phrase-level emphasis (theme color bold),==...== is conclusion/ warning/key number-level emphasis (red bold); the two combined are 1–3 places per paragraph, to avoid the whole piece looking like ad copy because everything is bolded.
  • The container layer is triggered by content form, not to "make up for visual richness"—only use a golden line card when there is a quote, and only use a code block when there is code.
  • The total emphasis ratio (marking layer text amount / total word count) is still recommended to be <15%. Background colors / boxes are prohibited (except for the container layer).
  • Article type: frontmatter workflow_type: tech(with code/tables) or editorial(plain text); render_wechat.py is currently a unified minimalist theme,render.py(early simplified version) retains the tech/editorial two styles.
  • Images: Alt empty → no caption is shown below the image; Alt has content → clearly state what is in the image (do not use information-free words like "illustration" or "screenshot").

6-step process

  1. Check frontmatter's workflow_type。
  2. Emphasis polishing: AI marks the whole text according to the density model with ** / == / quote blocks, and verifies that the anchor layer is ≤5 and the marking layer is 1–3 per paragraph.
  3. Render:scripts/render_wechat.py Markdown → inline-style HTML that complies with the "WeChat platform red lines".
  4. Validate:scripts/validate_wechat_html.py Mechanically review the red lines—if there are hard violations, first go back to the rendered result/ script and fix them; only after passing (exit 0) can you proceed to the next step; warnings do not block, but it is recommended to clear them along the way.
  5. Before pushing to the draft box, first confirm: by default, confirm the style, cover, and publishing account before execution—explicitly invoking this skill, hitting workflow_type default configuration, are only recommended inputs and do not constitute a reason to skip confirmation; the only skip condition is that the client's current sentence explicitly says "push directly/no need to confirm"; after skipping, state in the receipt the assumptions used this time. After confirmation passes, scripts/publish.py → call WeChat draft/add to create a draft (upload images to CDN, upload the cover).
  6. After manual confirmation of publishing → scripts/archive.py mark as published, record the link, update the log.

Script specifications (scripts/)

  • render_wechat.py [--file <in.md>] [--output <out.html>](do not pass --file then read stdin, if not passed --output then print to stdout): the currently recommended renderer, using only tags/inline styles allowed by the WeChat platform red lines;**…** → theme color bold,==…== → red bold,> quote → quote card, code block → inline style <section> simulation, each text node wrapped in <span>. The theme color is a Python constant at the top of the script, not a CSS variable.
  • validate_wechat_html.py [--file <html>] [--json](if not passed --file then read stdin): mechanically validate the above "WeChat platform red lines", reporting the line number + type of each violation; hard violations (div/class/id/ position/float/media/keyframes/css variable/<style> block) exit 1, clean exit 0; bare text nodes are downgraded to warnings and do not block. Pure html.parser implementation, no third-party dependencies.
  • render.py <in.md> <out.html> [--style tech|editorial]: early simplified renderer (tech/ editorial dual style), without red-line validation/<span> before formal publishing. validate_wechat_html.py。
  • publish.py --article <md> --cover <png> [--dry-run]: render → upload images / cover to WeChat CDN → draft/add create draft. Credentials are read from the private config.yml 's env.WECHAT_APP_ID / env.WECHAT_APP_SECRET .
  • archive.py --article <md> --url <link>: set frontmatter status: 已发布 + record date / link + append log.

Initial setup <1 hour (rules 15 min + AI-generated script 20 min + Skill documentation 10 min), afterwards each article's formatting ≈ 0.

⚠️ Security rules (must follow)

  • Only create drafts, never auto mass-send— mass-sending must be manually clicked by the user in the official account backend.
  • Store credentials in skill-specific private config.yml(WECHAT_APP_ID / WECHAT_APP_SECRET),do not commit to Git。
  • You must first enable the development API in the developers.weixin.qq.com / mp backend and configure the IP whitelist.

How to obtain and configure the WeChat official account AppID / AppSecret

  • Entry: WeChat Official Accounts Platform https://mp.weixin.qq.com,用该公众号绑定的**管理员微信扫码登录**。

  • Prerequisites:draft/add and other interfaces are only open toverified subscription/service accounts; unverified personal subscription accounts do not have permission for these interfaces, and calls will directly report something like 48001 api unauthorized。

  • Path to get AppID / AppSecret: log in to the backend → bottom of the left menu "Settings and Development" → "Development" → "Basic Configuration" (in the old menu it is "Development" → "Development Interface Management" → "Basic Configuration") → the "Official Account Development Information" section on the page:

    • Developer ID (AppID): directly visible and copyable, corresponding to the WECHAT_APP_ID。
    • Developer Password (AppSecret): click "Reset", and it is only displayed after the administrator confirms by scanning the QR code,only shown this one time, copy and save it on the spot, corresponding to WECHAT_APP_SECRET; resetting will immediately invalidate the old secret, and if it is still in use elsewhere it will be disconnected as well.
  • IP whitelist (critical, missing it means certain failure): on the same "Basic Configuration" page there is "IP Whitelist"; you must add thepublic IP of the machine that actually calls the API, otherwise when exchanging for access_token it will report 40164 invalid ip. If running locally, first check the machine's public IP (e.g. curl ifconfig.me), and remember to update it after changing networks.

  • Where to put it: keys only go in private config.yml, not in the vault, not in this open-source skill repository, and not in shell startup files.publish.py already integrated scripts/soia_env.py, when it runs it willautomatically detect and load $SOIA_PKM_PUBLISH_CONFIG_FILE(or the compatible alias $SOIA_PKM_PUBLISH_ENV_FILE) as well as the default path ~/.config/soia-skills/soia-open-skills/soia-pkm/soia-pkm-publish/config.yml,no need to source manually:

    # ~/.config/soia-skills/soia-open-skills/soia-pkm/soia-pkm-publish/config.yml
    env:
      WECHAT_APP_ID: "wx************"
      WECHAT_APP_SECRET: "********************************"
    
    # 直接跑,脚本自己会读私有 config.yml
    python3 scripts/publish.py --article xxx.md --cover xxx.png
    

    (when credentials are stored in a non-default path:SOIA_PKM_PUBLISH_CONFIG_FILE=/你的/路径/config.yml python3 scripts/publish.py ...。)

  • Self-check: once configured, you can first have the AI "use this credential to exchange for an access_token once to see if it works"; once it works, proceed to the main workflow of render → validate → push to drafts.

Other platforms (simplified adaptation)

  • X thread: split long-form content logically into (1/N), with a hook in the first post and a CTA in the last, each post ≤280 characters.
  • Xiaohongshu: distill into a card style—clickbait title (with emoji) + 3–5 short paragraphs + topic tags + image suggestions.

Post-execution receipt

After pushing the drafts, tell the user: ① the drafts are in the WeChat Official Account backend (which article, what style) ② remind them "after confirming it's correct, you manually send it to all" ③ after sending, come back and let me know, and I'll run the archive. For X / Xiaohongshu versions, similarly inform them of the output location.

Closed-loop position

clip(收) → organize(整理) → distill(点) → compose(写) → ★publish(发)

Upstream compose provides the finished draft;publish is responsible for multi-platform adaptation + delivery, and is the last link in the closed loop. Credentials and the manual gate of "manual mass sending" are controlled by the user.