agentsclimarketplace

Wechat autopublish

Skill TyrantLucifer/awesome-skills/skills/wechat-autopublish

Use when the user wants to publish a WeChat personal-subscription article from a topic, Feishu doc, notes, or existing draft. Turn research or source material into a ready-to-publish WeChat article and, when credentials allow, push it to the WeChat Official Account draft box with title/digest/cover/author prepared.From its SKILL.md

Install
npx -y skills add TyrantLucifer/awesome-skills --skill wechat-autopublish

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • 14 days oldThe repository was created 14 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

57.9 KB, ~12.8k tokens by cl100k_base, as published. Nobody here has run it

WeChat Autopublish

Overview

This skill turns source material into a polished WeChat Official Account article for a personal subscription account.

The core value is not generic writing advice. The skill is designed as a professional publishing pipeline for the owner's personal brand, with a strong bias toward:

  • Feishu doc → WeChat article conversion
  • topic → ready-to-publish WeChat article
  • practical / technical content rather than empty thought-leadership copy

It should:

  1. Accept one of these inputs:

    • a topic
    • a Feishu/Lark document
    • local Markdown/notes
    • reference links
    • an existing draft
  2. Produce one of these final outputs:

    • WeChat draft box article (preferred)
    • ready-to-paste publishing package (fallback)
    • draft review package (when explicitly requested)
  3. Default to a professional technical blog workflow instead of generic content generation.

  4. Support explicit copy-transfer mode when the source article is already strong enough to be published as a mostly intact WeChat copy, especially when the user asks to preserve both the detailed content and the original images.

The skill should keep the workflow stable, reusable, and focused on publishing, not brainstorming.

When to Use

Use this skill when:

  • the user wants to publish or convert a Feishu doc into a WeChat article
  • the user gives a topic and wants a publish-ready WeChat article
  • the user asks to push content into the WeChat draft box
  • the user says things like "公众号", "推文", "公号稿", "草稿箱", "发布文章"
  • the user wants a repeatable publishing workflow rather than one-off writing help
  • the user provides an internal document, design note, or technical summary and wants it transformed into external-facing WeChat content
  • the user wants the agent to handle the full publishing job rather than just write a draft

The three most important trigger patterns are:

  • Feishu doc publishing mode: publish this Feishu doc as a WeChat article
  • Topic content-building mode: take this topic and build a publish-ready WeChat article for me
  • Copy-transfer mode: the source article is already detailed and should be published as a near-complete copy with images retained, not condensed into a fresh rewrite

Do not use this skill for:

  • general article writing without WeChat publishing intent
  • enterprise service-account publishing workflows
  • short social posts unrelated to the WeChat Official Account
  • lightweight brainstorming that clearly does not need a publishing pipeline

Default Profile

This is a personal-brand publishing skill, not a generic content generator.

Personal voice baseline

The default writing style should follow the owner's blog voice at https://tyrantlucifer.com/ .

Based on representative posts such as 笔记工作流的最佳实践 and Fluss - 面向分析的实时流存储初探, the blog's recurring style has these traits:

  • writes in first person, but keeps the focus on the topic rather than self-dramatization
  • opens by stating the real background, problem, or motivation in a few sentences
  • prefers a clean problem-oriented or evaluation-oriented structure instead of fluffy narrative
  • often uses a flow like: motivation/context → concept/objective → architecture or selection criteria → concrete examples or setup notes → verification/takeaways
  • uses comparison, step reasoning, and decision explanation when introducing a new tool or workflow
  • keeps paragraphs short and readable, usually 2-4 sentences
  • frequently uses section titles that directly describe the current stage or question
  • uses concrete nouns, real components, and real scenarios instead of abstract inspirational language
  • preserves important English names exactly when discussing open-source projects, systems, or technical terms
  • uses first-person observation to add practical judgment, not to perform emotion
  • prefers clear lists, structured evaluation points, architecture breakdowns, and workflow summaries
  • values clarity, practicality, reproducibility, and reader utility over rhetorical flourish
  • tends to explain choices and trade-offs rather than just stack buzzwords

Style fingerprint: Write like the blog owner: a senior big-data / infrastructure engineer who explains things in a calm, practical, structured, example-aware, and opinionated way. The article should feel like a real practitioner's technical blog post, not AI promotional copy.

Source posts sampled for this profile:

  • 笔记工作流的最佳实践
  • Fluss - 面向分析的实时流存储初探
  • SeaTunnel连接器V1到V2的架构演进与探究

User-operating preferences for this skill (hard-won corrections from live use):

  • One canonical copy of publishing scripts lives inside this skill, under scripts/wechat_publisher/. Do not propose wrapper shells that merely call an external checkout.
  • When the user asks for “搬运” / copy / migration mode, preserve the source document's structure and detail first. Do not aggressively rewrite into a short editorial unless the user explicitly asks for that mode.
  • When migrating Feishu docs to WeChat, treat callout blocks and whiteboard figures as first-class content, not decorative noise. They must be converted or migrated explicitly.
  • When figures exist, migrate unique images intentionally. Avoid naive duplication that inflates figure count and produces messy layout.
  • Publishing output should be actionable and concrete: title, digest, author, cover, migrated images, HTML quality, fallback path, and next action. Avoid long theoretical explanations when the user wants execution.
  • Quality gate comes after migration completeness, not before. First make the copy faithful; then polish for publishing readability.
  • The user expects active review of the HTML conversion path whenever rich Feishu content is involved, especially callouts, figures, tables, and appendix image placement.

Publishing defaults

Unless the user overrides:

  • account: main
  • preferred publishing mode: draft box
  • article scale: roughly 2500-5000 words for long-form
  • output language: Chinese
  • structure: problem-oriented or workflow-oriented
  • style: professional technical blog, not marketing copy
  • translation rule: if source material is in English, publish in Chinese with original terms preserved where useful

Execution backend

This skill manages its own publishing scripts internally:

  • scripts/wechat_publisher/

This is the correct integration shape for this user. Do not vendor the entire upstream project tree, do not create a wrapper shell that merely calls an external checkout, and do not leave publishing scripts split across two unrelated locations.

The required integration pattern is:

  1. extract only the necessary publishing scripts into scripts/wechat_publisher/
  2. keep required publishing assets together with those scripts when the scripts depend on them
  3. keep wechat-publisher.yaml with the extracted scripts, not at unrelated outer paths
  4. expose thin shell entrypoints under scripts/wp-*.sh that call the internal scripts directly

If the underlying publishing code expects its config at parent.parent / wechat-publisher.yaml, adjust the internal copy so the config lookup matches the skill's actual layout instead of assuming the old upstream directory shape.

Known converter pitfalls

lark-cli table output missing pipe delimiters

When fetching Feishu docs via lark-cli docs +fetch, exported Markdown tables may be missing leading/trailing |. Normalize them before gzh-design rendering so table structure is unambiguous and source fidelity can be checked.

Fix: After fetching, normalize table rows by adding | at start and end:

lines = content.split('\n')
new_lines = []
for line in lines:
    if '|' in line and not line.strip().startswith('```'):
        if line.count('|') >= 2:
            if not line.strip().startswith('|'):
                line = '|' + line
            if not line.strip().endswith('|'):
                line = line + '|'
    new_lines.append(line)
### Known converter pitfalls

#### Use `gzh-design` as the canonical Markdown → HTML renderer

`gzh-design` is the **default and mandatory renderer** for new publishing runs. The internal `html_converter.py` is retained only as a legacy emergency fallback; do not choose it merely because it is deterministic or already wired into `publish.py`.

Canonical path:
1. normalize Feishu/Word/PDF/notes into clean WeChat-ready Markdown;
2. load `gzh-design` and read its `theme-index.md`, the selected theme library, and `common-components.md`;
3. render a pure `<section>…</section>` body fragment with inline styles and `<span leaf="">` text wrappers;
4. run `gzh-design/scripts/validate_gzh_html.py` until **ERROR=0 and WARNING=0**;
5. run `scripts/wp-html.sh <rendered.html>` for the copy-ready preview;
6. publish the rendered HTML with `scripts/wp-publish.sh <rendered.html> --title ...`, which uploads local/external HTML images to WeChat CDN before draft creation.

Theme behavior:
- if the user specifies a gzh-design theme, use it directly;
- otherwise recommend from the article type; in full-auto publishing, choose automatically and report the reason;
- do not mix components from different gzh-design themes;
- preserve the normalized Markdown as the content source of truth and the gzh-design HTML as the publishing artifact.

Legacy fallback is allowed only when `gzh-design` is unavailable or its component assets are damaged. The fallback must be explicit in the final report and uses `wp-html-legacy-md.sh` / `wp-publish-legacy-md.sh`.

**Mandatory HTML quality gate before publishing:**
1. gzh-design validator reports 0 ERROR and 0 WARNING;
2. no literal `**` remains in HTML;
3. no `src=""` appears;
4. no raw `<grid>`, `<callout>`, `<whiteboard>`, Mermaid code, or `flowchart`/`mindmap` remains;
5. expected links retain `href="https://..."`;
6. every expected figure has a non-empty local/CDN image source;
7. after draft creation, `draft/get` confirms content and figures survived WeChat sanitization.

### Table rows MUST start and end with `|`

`html_converter.py` detects table rows by checking `stripped.startswith("|")`. Markdown tables like:

维度传统数据湖多模态数据湖
数据类型结构化/半结构化任意模态

will NOT be recognized as tables. They must be:

维度传统数据湖多模态数据湖
数据类型结构化/半结构化任意模态

Always normalize table rows to start/end with `|` before passing to the HTML converter.

### Table cells: `flush_table()` must call `process_inline()` on cell contents

The original `flush_table()` in `html_converter.py` inserted raw cell text into `<th>`/`<td>` tags without processing inline Markdown (`**bold**`, links, etc.). Fix: call `process_inline(c)` on each cell value.

### Table headers: strip `**bold**` markers to avoid yellow highlight

`process_inline()` converts `**text**` to `<strong>` with yellow highlight background (`#fff18a`). In table headers (`<th>` with dark blue background), this creates unreadable text. Fix: strip `**` markers from header cells before calling `process_inline()`:

```python
def clean_th_text(t):
    t = re.sub(r'\*\*([^*]+)\*\*', r'\1', t)
    return process_inline(t)

Table rows must start AND end with | (critical)

html_converter.py detects table rows via stripped.startswith("|"). Rows without leading | are treated as plain paragraphs and break the entire table.

See "Markdown tables MUST start and end with |" section above for the fix script, or references/table-format-fix.md for a standalone fixer script.

Table cell inline markdown needs explicit process_inline() call

Fixed in 2026-07-01: flush_table() now calls process_inline() on both <th> and <td> cell contents. Previously, **bold** in table cells rendered as literal asterisks.

Table header **bold** causes yellow highlight on dark background

Fixed in 2026-07-01: Table headers now strip **bold** markers before processing, since the strong style's yellow #fff18a background clashes with the dark blue #0b1530 header background.

Feishu <grid> / <column> blocks need manual preprocessing

The strong style in html_converter.py includes background: #fff18a (yellow highlight). When table header cells contain **bold** markers, the yellow highlight appears on the dark blue #0b1530 th background, making text unreadable.

Fix: In flush_table(), strip **bold** markers from table header (th) cells before passing to process_inline(), since <th> already has font-weight: 600:

def clean_th_text(t):
    t = re.sub(r'\*\*([^*]+)\*\*', r'\1', t)
    return process_inline(t)

Apply to the i == 0 (header row) branch only. Body <td> cells should still use process_inline() to preserve inline markdown formatting.

Table cell markdown not rendered

The original flush_table() passed cell content directly into <td> without calling process_inline(), so **bold** markers appeared as raw text. The fix is to call process_inline(c) on all non-header cell content.

Cover image: picsum.photos seeds produce irrelevant images

Using picsum.photos/seed/<word>/900/383 does NOT guarantee the seed word relates to the image content. Seeds like datalake, technology, database all produce random photos (vegetables, landscapes, etc.).

Better approach:

  1. Use a known-good tech image URL (e.g., from Pixabay/Unsplash with direct link)
  2. If needed, resize with ffmpeg -i input.jpg -vf "scale=900:383" output.jpg
  3. Or generate with image_generate tool when available

Feishu <grid>/<column>` blocks need manual preprocessing

normalize_for_wechat.py handles <callout>, <whiteboard>, <title>, <p> blocks — but not <grid> / <column> layout blocks that Feishu exports for multi-column content (e.g. pros/cons comparison).

Preprocessing pattern:

import re
grid_re = re.compile(r'<grid>(.*?)</grid>', re.S | re.I)
col_re = re.compile(r'<column[^>]*>(.*?)</column>', re.S | re.I)

def replace_grid(m):
    cols = col_re.findall(m.group(1))
    return "\n\n---\n\n".join(c.strip() for c in cols) + "\n" if cols else m.group(1)

text = grid_re.sub(replace_grid, text)

Run this before normalize_for_wechat.py.

Markdown tables MUST start and end with |

html_converter.py detects table rows via stripped.startswith("|"). When converting Feishu docs or writing markdown manually, every table row (including the header and separator) must start and end with |:

|列A|列B|列C|
|---|---|---|
|值1|值2|值3|

Without leading |, rows render as plain paragraphs. Use a fixer script:

# fix_table_pipes.py — add missing leading/trailing | to table rows
import re
lines = content.split('\n')
for i, line in enumerate(lines):
    if '|' in line and not line.strip().startswith('```'):
        if line.count('|') >= 2:
            if not line.strip().startswith('|'):
                lines[i] = '|' + line
            if not line.strip().endswith('|'):
                lines[i] = lines[i] + '|'

flush_table() must call process_inline() on cell contents

The original html_converter.py passed raw cell text into <td>/<th> tags without inline markdown processing. **bold** in table cells rendered as literal asterisks.

Fix applied (2026-07-01): flush_table() now calls process_inline(c) for both <th> and <td> cells.

Table headers: strip **bold** to avoid yellow highlight conflict

When process_inline() processes **text**, it applies the strong style which includes background: #fff18a (yellow highlight). In table headers (<th> with background: #0b1530; color: #ffffff), this yellow highlight makes text unreadable.

Fix applied (2026-07-01): Table header cells use clean_th_text() that strips **bold** markers before process_inline(), since <th> is already bold by default.

def flush_table():
    ...
    if i == 0:  # header row
        def clean_th_text(t):
            t = re.sub(r'\*\*([^*]+)\*\*', r'\1', t)
            return process_inline(t)
        cells_html = "".join(f'<th ...>{clean_th_text(c)}</th>' for c in cells)
    else:  # body rows
        cells_html = "".join(f'<td ...>{process_inline(c)}</td>' for c in cells)

Cover image generation: use the skill's built-in pipeline (FIRST CHOICE)

⚠️ CRITICAL ORDER: Always try generate_image.py FIRST.

Do NOT try image_generate tool (FAL), picsum, pixabay, or any external image source before checking the skill's own generate_image.py script. The script reads API credentials directly from wechat-publisher.yaml and works even when image_generate tool reports missing keys.

Correct cover image priority:

  1. User-supplied cover image
  2. generate_image.py script (reads config from wechat-publisher.yaml)
  3. If that configured provider/model is unavailable, use the active image_generate tool when available
  4. Article inline images (reuse the most representative one)
  5. Branded placeholder template
  6. Last resort: stock photo (warn user it's temporary)

After generation, always inspect the image visually, then inspect the actual file dimensions before resizing or cropping. Do not trust a tool's reported nominal size: backends may return a different aspect ratio. For WeChat covers, verify the final 900×383 artifact again after conversion.

Do NOT jump to picsum/pixabay/random images just because image_generate tool reports FAL_KEY missing — the skill has its own image generation backend configured in wechat-publisher.yaml.

Sensitive info masking — do NOT assume values are truncated

Hermes tools (read_file, terminal output, session_search) automatically mask sensitive values like API keys. A displayed value like sk-701...2b99 is NOT truncated — it is the full key being masked at the display layer for security.

Do NOT:

  • Assume the key in the config file is broken or incomplete
  • Ask the user to "provide the full key" when it's already there
  • Waste rounds trying to "fix" a value that is already correct

Do:

  • Just call the script that reads the config directly (generate_image.py, wp-token.sh, etc.) — they read the actual file, not the masked display
  • If the script fails with 401, then investigate the key — but trust the file, not the display

Do not infer that a credential file is incomplete from masked tool output. Let the local script read the file directly, then diagnose only from the real API response.

The skill has a complete image generation pipeline:

  1. generate_image.py — unified entry point, reads wechat-publisher.yaml
  2. openai_image_gen.py — OpenAI-compatible API backend
  3. Config keys in wechat-publisher.yaml:
    • image_generation.generator (set to "openai")
    • image_generation.openai.api_key
    • image_generation.openai.base_url
    • image_generation.openai.image_model

Usage:

cd scripts/wechat_publisher
python3 generate_image.py --generator openai \
  -p "描述封面图内容的详细prompt" \
  --image /tmp/cover.jpg \
  --size "1792x1024" \
  --quality "high"

Pitfall: If the API key in wechat-publisher.yaml is truncated or invalid, the script will return 401. Always verify the key is complete before attempting generation. If generation fails, report the error clearly and ask the user to provide the correct key — do NOT silently fall back to unrelated stock images.

--html mode cover behavior

publish.py --html <gzh-fragment> always requires --title. --cover is optional only when the HTML contains a resolvable first image, which the publisher can reuse as cover; otherwise provide a real cover explicitly. Never download a random Picsum image silently.

⚠️ Lorem Picsum random images are often irrelevant — seeds like database, technology return random photos (vegetables, landscapes, architecture) that have nothing to do with the topic. Random Picsum is acceptable only as a "won't crash" fallback. When the user sees an irrelevant cover, they will complain.

Better fallback strategies (in priority order):

  1. Ask the user to supply a cover image
  2. If the article has inline images, reuse the most representative one
  3. Generate a cover via the configured image backend (OpenAI / Gemini)
  4. Use a solid-color SVG or a simple branded template image
  5. Last resort: Picsum random — but warn the user it's a placeholder

html_converter.py table cells must call process_inline() for markdown rendering

The flush_table() function in html_converter.py originally inserted table cell content raw — without calling process_inline(). This meant **bold**, [links](url), and other inline markdown inside table cells rendered as literal text.

Fix applied (2026-07): Changed flush_table() to call process_inline() on every cell:

# Before (broken):
cells_html = "".join(f'<th style="...">{c}</th>' for c in cells)
# After (fixed):
cells_html = "".join(f'<th style="...">{process_inline(c)}</th>' for c in cells)

Same for <td> cells. The patch is applied to the skill's copy of html_converter.py. If you replace or update the file, verify this fix is present.

Validation: after conversion, check the HTML output — if **text** appears as literal asterisks inside <td> or <th> tags, the fix was lost.

Mermaid / flowchart code blocks must be rendered to images before gzh-design

Before publishing any article containing Mermaid blocks:

  1. search the normalized Markdown for fenced mermaid blocks or flowchart/mindmap syntax;
  2. render each diagram to a PNG;
  3. replace the fenced block with ![流程图说明](/absolute/path/to/diagram.png);
  4. render the resulting Markdown with gzh-design and verify no Mermaid source remains in the HTML;
  5. publish the clean HTML through wp-publish.sh; it uploads the local image source to WeChat CDN.

If the server lacks Chinese fonts, download/use a local CJK font and reference it via @font-face when rendering diagrams with Playwright; otherwise Chinese labels become square glyphs in the generated image.

html_converter.py requires tables to start and end with |

The table detection in html_converter.py uses this check:

if "|" in stripped and stripped.startswith("|"):

Markdown tables that lack leading/trailing | (e.g. **维度** | **传统** | **多模态** instead of |**维度** | **传统** | **多模态**|) will not be detected as tables — they pass through as plain <p> text.

This commonly happens when:

  • Feishu doc exports produce bare pipe-separated rows without | boundaries
  • Content is hand-written with | as separator but no leading |

Fix: normalize table rows before normalize_for_wechat.py:

import re
def fix_table_pipes(text: str) -> str:
    """Ensure markdown table rows start and end with |."""
    lines = text.split('\n')
    result = []
    for line in lines:
        if '|' in line and not line.strip().startswith('```'):
            if line.count('|') >= 2:
                if not line.strip().startswith('|'):
                    line = '|' + line
                if not line.strip().endswith('|'):
                    line = line + '|'
        result.append(line)
    return '\n'.join(result)

This fix is available as scripts/fix_table_pipes.py.

Validation: after conversion, grep the HTML for <table — if absent and the source had tables, the pipe fix was missed.

Use the skill's wrapper scripts for operations:

  • scripts/wp-list-accounts.sh
  • scripts/wp-token.sh
  • scripts/wp-html.sh
  • scripts/wp-ai-score.sh
  • scripts/wp-publish.sh
  • scripts/wp-bootstrap.sh
  • scripts/wp-run.sh

Cover image generation

When image_generate tool is unavailable (no FAL_KEY), use the skill's built-in generate_image.py script:

cd ~/.hermes/skills/social-media/wechat-autopublish/scripts/wechat_publisher
python3 generate_image.py --generator openai \
  -p "A modern data lake architecture diagram..." \
  --image /tmp/cover.jpg \
  --size "1792x1024" --quality "high"

The script reads API config from wechat-publisher.yaml (image_generation.openai.*). If the API key is truncated or invalid, the script will fail with 401 — check the key before retrying.

When image generation is unavailable (no API key, API errors), fall back to a stock image from pixabay/picsum. Always inform the user about the fallback.

Image-generation integration notes are in references/wechat-image-generation.md.

Rendering, integration shape, and next-upgrade research are in references/wechat-rendering-and-integration-notes.md.

WeChat justified text stretches Chinese spacing

Do not use text-align: justify for normal WeChat article paragraphs. In WeChat preview/WebView, Chinese-English mixed lines can be expanded aggressively, creating large gaps between Chinese characters and English terms. Use:

text-align: left;
letter-spacing: 0.15px;
word-spacing: 0;

This applies to the default converter styles and the refined-blue theme. Verify the actual draft HTML returned by draft/get, not only the pre-upload HTML.

WeChat sanitizes multi-line blockquotes

Do not render Feishu callouts as one <blockquote> joined by <br>. WeChat's draft sanitizer can keep only the first line, silently deleting the callout body. Render each callout as a styled <section> containing one <p> per source line. After draft creation/update, call draft/get and verify that every callout still contains its body text.

List rendering strategy

WeChat Official Account HTML does not reliably support nested list indentation via ul/ol/li + CSS.

Therefore:

  • use a standard Markdown renderer for correctness
  • then convert nested lists into WeChat-safe list components using p + span
  • preserve indentation through explicit left padding
  • preserve numbering/bullets through explicit styled spans

This avoids duplicated numbering and unstable nested-list rendering.

Preconditions

Before attempting draft-box publishing, confirm:

  1. the WeChat account is a personal subscription account
  2. AppID is available
  3. AppSecret is available
  4. the server/public IP is added to the WeChat IP whitelist
  5. the publishing toolchain is configured inside scripts/wechat_publisher/wechat-publisher.yaml
  6. image generation configuration is understood: image_generation.openai.* is used for OpenAI-compatible image backends, image_generation.gemini_proxy.* for Gemini-style backends, and image_generation.generator selects the active path
  7. if a generated cover is required, the active image backend is configured before publishing

If any precondition fails, fall back to the publishing package workflow rather than stopping completely.

Operational lesson from actual use:

  • when the user asks how to configure YAML, answer in execution-project terms first
  • clarify that secrets / provider keys / account credentials belong in the execution project config
  • clarify whether image generation is currently wired into this skill's publishing flow before giving configuration advice

If any precondition fails, fall back to the publishing package workflow rather than stopping completely.

Core Principle

This skill should always separate content production from account-specific publishing mechanics.

A stronger publishing principle should also be enforced:

  • all inputs must first be normalized into WeChat-ready Markdown
  • Markdown → HTML is the single main rendering path
  • source-specific preprocessing (Feishu docs, rich exports, mixed tags) belongs in the Markdown normalization layer, not inside the HTML renderer
  • preserve source value where appropriate; do not blindly compress detailed source documents when the user wants publication-grade content

This keeps the publishing pipeline stable and makes the rendering core reusable across different input types.

Two primary operating modes should be supported explicitly:

  1. Feishu doc publishing mode

    • Use when the user gives a Feishu doc URL/token and wants it published as a WeChat article.
    • The Feishu doc is treated as the main source of truth.
    • The skill should extract, restructure, de-internalize, and convert the doc into publishable WeChat content.
    • This mode should be used when the user wants a publishing-grade rewrite or restructure.
  2. Copy-transfer mode

    • Use when the user wants the source article transferred to WeChat as faithfully as possible.
    • Prefer preserving original structure, detail density, figures, and appendices over aggressive rewriting.
    • This mode is especially appropriate when the source article is already mature and the user says things like “搬运一下”“图也得搬一下”“不能太精简”.
    • The goal is publishable fidelity, not fresh content reconstruction.
  3. Topic content-building mode

    • Use when the user gives only a topic, outline, or rough idea.
    • The skill should build the article end-to-end: define the job, research, outline, draft, humanize, format, and package for publishing.

Support files for execution:

  • references/gzh-design-integration.md — canonical renderer contract and artifact boundary
  • references/wechat-publisher-execution.md
  • references/feishu-wechat-conversion.md
  • references/html-publishing-quality-gate.md — renderer failure signatures and the pre/post-publish verification gate
  • templates/wechat-publisher.yaml.example
  • templates/feishu-doc-intake.md
  • templates/topic-intake.md
  • templates/final-package.md

Recommended abstraction:

  1. Source intake
  2. Research / evidence gathering
  3. Structuring
  4. Drafting
  5. Humanization / anti-AI flattening
  6. WeChat formatting
  7. Publishing execution via wechat-publisher
  8. Output packaging / fallback packaging

This skill should treat wechat-publisher as the execution backend, not duplicate its publishing logic.

Copy-transfer mode: Feishu doc → WeChat copy

Use this mode when the source article should remain close to the original, especially when the user wants the original detail and diagrams preserved.

Default behavior:

  • preserve section hierarchy and detail density
  • preserve figures, appendices, tables, code blocks, callouts, and examples
  • perform only necessary publishing cleanup instead of fresh rewriting
  • rewrite only where internal phrasing, internal context, or platform formatting needs adjustment
  • export embedded Feishu whiteboard/diagram/media content as images when possible and include them in the article

Important copy-transfer rules:

  1. do not compress a detailed document into a summary just because it is long
  2. do not strip diagrams unless they truly cannot be recovered or published
  3. do not replace an already-strong structure with a generic article skeleton
  4. treat user signals like “搬运一下” and “图也得搬一下” as explicit instructions to preserve content volume and figures
  5. if the user criticizes a version as “太精简”, the next version must restore detail and figures first

Completion criteria:

  • the published WeChat draft is a faithful transfer of the source article
  • figures are migrated wherever technically possible
  • the article retains the original depth unless the user explicitly asks for condensation

When the source is a Feishu document:

  • load the document first
  • identify the original goal, audience, and structure
  • convert internal phrasing into public-facing WeChat phrasing where needed
  • preserve technical accuracy, original names, diagrams or examples worth keeping, and practical substance
  • do not over-summarize; reshape the document into a publishable article instead of reducing it to a shallow overview

Feishu conversion rules

When loading a Feishu document, the feishu_doc_read tool will fail with "Feishu client not available" outside of Feishu comment contexts. Reliable fallback:

~/.local/bin/lark-cli docs +fetch --doc <token-or-url> --doc-format markdown --format json -q '.data.document.content'

Note: The feishu_doc_read tool is only available when Hermes is running inside a Feishu gateway context. In all other contexts (terminal, cron jobs, Desktop), use the lark-cli fallback above.

  1. preserve the technical spine of the document, not the internal presentation order
  2. keep real components, real flows, real constraints, and real examples whenever they are valuable to an external reader
  3. remove internal assumptions that an outside reader cannot understand or does not care about
  4. rewrite internal system names, internal project references, or internal shorthand unless they are essential to the story
  5. convert note-like or memo-like structure into a deliberate article structure
  6. if the document is too linear, too flat, or too internal, rebuild it into a stronger skeleton before drafting
  7. avoid flattening the document into a summary; the goal is publishing reconstruction, not compression
  8. make the final article feel like the author deliberately wrote it for WeChat readers, not like a sanitized internal export
  9. if the source Feishu doc contains <callout> blocks, convert them explicitly to WeChat-safe structures before HTML conversion; do not leave raw Feishu-specific tags in the publishing payload
  10. if the source Feishu doc contains embedded whiteboard/export figures, migrate them explicitly as images and deduplicate references before publishing

Feishu structural rebuilding heuristics

Rebuild the skeleton when the source doc shows any of these patterns:

  • the document is essentially raw notes or bullet-heavy internal thinking
  • the structure is too chronological without a clear publishing payoff
  • the internal ordering buries the most publishable points
  • the document mixes audience types or mixes unrelated concerns
  • the original structure would make a WeChat reader drop off early

Preferred rebuilt shapes:

  • problem → background → core approach → practical examples → pitfalls → conclusion
  • objective → design/workflow → implementation notes → lessons → next steps
  • question/context → architecture → execution details → verification → recommendation

Completion criteria:

  • the Feishu doc has been processed as primary source material
  • internal phrasing has been converted where needed without destroying technical value
  • the final article reads like an intentional WeChat article rather than a raw internal doc repost

Topic → content building

When the source is only a topic:

  • define the publishing job before generating content
  • search for current and reliable material only as much as needed
  • choose an article structure deliberately
  • build a skeleton before long-form writing
  • draft the article with real technical substance
  • then humanize and package it

Cover image prompt strategy

When generating cover images, the prompt must extract specific structural information from the article content, not use generic abstract descriptions.

Bad prompt (generic):

"A minimalist technical architecture diagram cover image. Dark navy blue background with abstract glowing network nodes..."

Good prompt (content-specific):

Extract the article's core structure — layer names, component names, design pillars, key concepts — and describe them explicitly in the prompt. For example, for an architecture article, describe the actual layers (e.g., "Layer 1 Multi-Entry with CLI/Web/API, Layer 2 Core Runtime with Session/Scheduler/Executor"), the title text, subtitle, color scheme per layer, and layout.

The cover image generation pipeline:

  1. read the article content
  2. extract key structural elements (title, layers, components, design pillars)
  3. build a detailed prompt that describes these elements visually
  4. call generate_image.py --generator openai
  5. verify the generated image visually before publishing

Image generation strategy

This skill should treat image generation as a configurable publishing capability, not as a hard requirement.

Current integration status:

  • the wechat-publisher execution project has image generation support and config keys
  • this skill has wired execution scripts for publishing / HTML conversion / AI-score checking
  • image generation is not yet embedded as a required default step in this skill's publishing loop

Default recommendation:

  • publishing should succeed even when image generation is disabled or unconfigured
  • if image generation is unavailable, fall back to text-first layout or manual cover selection
  • if image generation is enabled, separate the flows clearly:
    • cover image
    • in-article images
    • fallback behavior when image generation partially fails

When advising on YAML configuration, clarify these distinct blocks:

  • account credentials
  • publishing behavior
  • image generation provider keys / model settings
  • integration tokens

This prevents confusion between "what is needed to publish" and "what is needed to auto-generate images".

Topic selection rules

Prefer these topic angles for the owner's personal brand:

  • practical workflow / practice sharing
  • architecture or system design breakdown
  • toolchain setup, evaluation, or comparison
  • engineering pitfalls and debugging notes
  • open-source project analysis from a practitioner view
  • data infrastructure, data integration, data synchronization, or adjacent engineering topics

Avoid these angles unless explicitly requested:

  • shallow news reposting without analysis
  • motivational or generic industry commentary
  • purely promotional tool introduction without practitioner value

Topic-building quality checks

Before drafting, confirm the chosen structure answers these questions:

  1. what is the article actually giving the reader?
  2. why is this structure the right one for the topic?
  3. where are the concrete examples or practitioner judgments?
  4. what will the reader be able to do after reading the article?

Completion criteria:

  • the topic has been shaped into a clear article job
  • the output follows a deliberate structure rather than generic expansion

Workflow

Step 1: Clarify the source type

The skill should first identify the input type:

  • topic only
  • Feishu document
  • Markdown / notes
  • reference links
  • existing draft

Completion criteria:

  • source type is identified
  • publishing account is confirmed
  • intent is clear: publish now, produce draft, or produce review package

If the source is a Feishu doc, load it directly with Feishu doc tools when possible and treat it as the primary source of truth. If the source is only a topic, confirm the minimum missing context before research.

Step 2: Define the article job

Before writing, define:

  • target reader
  • article goal
  • article type
  • expected structure

Common article types:

  • practical tutorial
  • architecture / workflow explanation
  • toolchain evaluation
  • troubleshooting / case study
  • industry or technical trend analysis
  • document-to-article conversion

Completion criteria:

  • the article job is written in one short paragraph
  • the chosen structure is explicit

Step 3: Collect research material

Do research only after the job is defined.

Gather:

  • official docs / release notes / blog posts
  • real commands, configs, APIs, and behaviors
  • high-quality recent references
  • concrete examples or deployment notes
  • only relevant discussion when it adds practitioner perspective

Do not pad research with generic background.

Completion criteria:

  • key facts are collected
  • sources are available
  • reusable examples are identified

Step 4: Build the skeleton

Before full drafting, generate a skeleton:

  • title candidates
  • summary / digest
  • section outline
  • per-section angle
  • expected diagrams / examples
  • cover concept

Prefer skeletons with:

  • a sharp opening
  • 3-6 sections
  • uneven section length if needed
  • a clear ending that adds judgment or next-step advice

Completion criteria:

  • skeleton exists and can be reviewed before long-form writing

Step 5: Draft the article

Write the draft in Markdown.

The draft should:

  • start with the real problem or scenario
  • avoid generic openers like "随着...的发展"
  • avoid AI ceremonial phrasing
  • keep paragraphs tight
  • use concrete nouns and verbs
  • mix explanations with examples
  • show the actual steps when the topic is practical
  • preserve important English terms where natural

Good patterns:

  • problem statement
  • prerequisites
  • step-by-step implementation
  • commands or configs
  • validation steps
  • pitfalls
  • summary / recommendation

Completion criteria:

  • Markdown draft is complete
  • title, summary, and main body are ready
  • cover direction is identified

Step 6: Humanize and de-AI the draft

This is a mandatory step for professional publishing.

Check and fix:

  • generic filler
  • repetitive parallel sentences
  • over-polite or marketing-like tone
  • empty conclusions
  • sections that sound impressive but say nothing
  • overuse of the same rhetorical structure in every section

Useful checks:

  • does each section contain something only someone who did the work would know?
  • are there concrete examples, numbers, configs, commands, or paths?
  • does the article have personal judgment or author perspective?
  • would a technically literate reader trust this article?

Completion criteria:

  • the draft reads like a real technical blog post
  • obvious AI patterns are reduced
  • the voice matches the default profile unless overridden

Step 6.5: Normalize source into WeChat-ready Markdown

Before converting to HTML, normalize heterogeneous source Markdown into WeChat-ready Markdown.

This step should handle Feishu-specific constructs and other non-standard blocks, including:

  • <callout ...>...</callout> → bold text with emoji prefix preserved (e.g. <callout emoji="💡">定位:...</callout> becomes **💡 定位:...**), NOT a Markdown blockquote
  • <whiteboard ...>...</whiteboard> → local exported image reference when a token is available
  • <title ...>...</title> → top-level Markdown heading when appropriate
  • emoji hints preserved as bold prefixes when appropriate
  • residual wrapper tags stripped while preserving usable text

Completion criteria:

  • the article has been normalized into clean Markdown
  • the HTML renderer receives standardized Markdown instead of raw source-specific markup

Step 7: Render with gzh-design

Markdown → HTML must use the gzh-design skill. Read references/gzh-design-integration.md for the exact integration contract.

Required sequence:

  1. keep the Step 6.5 normalized Markdown as the canonical source;
  2. load gzh-design;
  3. choose a theme from its references/theme-index.md according to article type or the user's explicit choice;
  4. read the selected theme component library and references/common-components.md;
  5. assemble the final pure <section>…</section> body fragment—do not add html/head/body/style/script wrappers;
  6. preserve every source paragraph, figure, table, callout conversion, code block, and link;
  7. run scripts/wp-gzh-validate.sh <html> and fix until ERROR=0 and WARNING=0; do not trust the upstream validator's exit code alone because WARNING can still return success;
  8. generate the copy-ready preview with scripts/wp-html.sh.

Do not call html_converter.py in the normal path. It is legacy fallback only.

Completion criteria:

  • normalized Markdown and gzh-design HTML both exist;
  • selected gzh-design theme and selection reason are recorded;
  • validator reports 0 ERROR and 0 WARNING;
  • the HTML contains no raw source-specific blocks and no missing figures;
  • title / digest / author / cover are explicit.

Step 7.5: Generate cover image if missing

When the publishing flow needs a cover but none exists, attempt automatic cover generation from the configured image backend before publishing.

Priority:

  1. use user-supplied cover
  2. use an existing article image if appropriate
  3. if still missing, generate one cover image and use it for the draft

Completion criteria:

  • the publishing flow has a usable cover strategy
  • publishing is not blocked unnecessarily when image generation is available

Step 8: Execute publishing via wechat-publisher

When draft-box publishing is requested and prerequisites are satisfied, delegate execution to the wechat-publisher toolchain instead of inventing a new publishing path.

Use these execution assets from this skill:

  • references/wechat-publisher-execution.md
  • templates/wechat-publisher.yaml.example
  • scripts/wechat_publisher/
  • scripts/wp-list-accounts.sh
  • scripts/wp-token.sh
  • scripts/wp-html.sh
  • scripts/wp-ai-score.sh
  • scripts/wp-publish.sh
  • scripts/wp-bootstrap.sh
  • scripts/wp-run.sh
  1. prepare and preserve the normalized Markdown article;
  2. check AI score / humanization quality on Markdown;
  3. render with gzh-design, then run its validator to 0 ERROR / 0 WARNING;
  4. prepare cover / title / digest / author;
  5. call scripts/wp-publish.sh <gzh-html> --title ...—the HTML publishing path uploads local/external <img src> references to WeChat CDN before draft creation;
  6. capture the returned draft media_id;
  7. verify the created draft with scripts/wp-verify-draft.py --media-id <id> --account <name>; confirm title, author, digest, non-empty content, selected theme structure, and expected inline images;
  8. if publishing fails, keep the validated gzh-design HTML and preview as the ready-to-paste package.

Completion criteria:

  • the publishing attempt has been executed through the real backend
  • a successful draft has been read back from WeChat, not inferred only from the create response
  • success or failure is explicit
  • fallback output is ready when draft-box publishing is unavailable

Step 9: Package the final output

Mode A: draft-box publishing (preferred)

Use the configured WeChat publishing workflow to push the article into the draft box.

Typical required outputs:

  • title
  • digest
  • author
  • cover image
  • HTML content

This mode should be used when:

  • credentials are configured
  • IP whitelist is configured
  • API connection succeeds
  • upload / draft creation succeeds

Mode B: ready-to-paste package (fallback)

Use when draft-box publishing is not possible.

Deliver:

  • title
  • digest
  • author suggestion
  • cover image suggestion
  • final HTML or copy-ready formatted content
  • publishing notes

This mode is not a failure mode. It is the stable fallback for a personal subscription account.

Mode C: review package (optional)

Use only when the user explicitly asks for review before publishing.

Deliver:

  • Markdown draft
  • HTML draft
  • 3-5 rewrite suggestions
  • checklist of what still needs improvement
  • publishing recommendation

Completion criteria:

  • one of the three output modes is delivered
  • the user knows exactly what the next action is

Input Contract

Accept one or more of the following:

  • a topic
  • a Feishu doc token / URL
  • local Markdown file path
  • notes or outline
  • a set of reference links
  • publishing constraints

If the source is a Feishu document, prefer extracting and transforming that document instead of asking the user to restate the content manually. When doing so, use templates/feishu-doc-intake.md to capture publishing intent and transformation constraints.

If the user gives only a topic, ask only the minimum missing context:

  • target account (default to main)
  • audience
  • preferred structure or article type
  • any must-include material When doing so, use templates/topic-intake.md instead of asking open-ended questions.

Do not over-ask. If reasonable defaults exist, use them.

Output Contract

Every run should clearly deliver:

  • final title
  • final digest
  • author
  • cover direction or cover file
  • Markdown draft
  • WeChat HTML when available
  • publishing result or fallback package
  • a short note on what the user should do next

Use templates/final-package.md when a structured publishing package is needed.

Recommended output shape for Feishu doc publishing mode

When the source is a Feishu document, the final package should include:

  • title
  • digest
  • author
  • cover direction / cover file
  • what the publishing goal is
  • what main structural changes were made
  • what was preserved from the original doc
  • what was rewritten, removed, or reorganized for external publishing
  • publishing result or fallback package

Recommended output shape for topic content-building mode

When the source is a topic, the final package should include:

  • title
  • digest
  • author
  • chosen article type
  • chosen structure / scaffold
  • key references used
  • publishing result or fallback package

Draft-box publishing package

When draft-box publishing is attempted, the final package should include:

  • title
  • digest
  • author
  • cover image / cover direction
  • HTML content
  • publishing result or failure summary
  • fallback package if draft-box publishing fails

Ready-to-paste fallback package

When fallback publishing is used, deliver:

  • final title
  • final digest
  • author
  • cover image suggestion or cover file
  • Markdown or HTML ready to paste
  • short publishing notes
  • recommended next step

Publishing Strategy

Default strategy:

  1. try draft-box publishing first
  2. if credentials or API issues occur, produce the ready-to-paste package
  3. if the user wants review first, switch to review package
  4. never stop at "writing only" unless the user explicitly asks for writing-only output

Draft-box attempt order

When draft-box publishing is attempted, follow this order:

  1. load account config
  2. check AppID / AppSecret / whitelist assumptions
  3. prepare title / digest / author / cover
  4. prepare WeChat-compatible HTML
  5. call the wechat-publisher execution backend
  6. if successful, report the draft-box result clearly
  7. if failed, switch immediately to ready-to-paste package and explain the failure briefly

This makes the publishing flow stable and predictable instead of halting at the first failure.

Fallback Strategy

Use these fallbacks instead of stopping:

  • if AppID / AppSecret / whitelist is not ready → output publishing package
  • if token retrieval fails → output publishing package
  • if draft API fails → output publishing package
  • if image generation fails → publish without generated images when acceptable, or switch to text-first layout
  • if article quality looks weak → force another humanization pass before publishing
  • if the Feishu doc is too internal or too raw → restructure it into an explicit publishing skeleton before final drafting
  • if the topic is too broad → force job definition and scaffold selection before content generation

Ready-to-paste package checklist

When fallback is triggered, deliver a complete publishing package:

  • final title
  • final digest
  • author
  • cover image suggestion or cover file
  • copy-ready Markdown or HTML
  • notes on what to paste into the WeChat editor
  • short recommendation for the next step

WeChat Publishing Checklist

Before draft-box publishing, check:

  • account selected
  • title is sharp and not generic
  • digest is clean and share-card friendly
  • cover exists or fallback cover strategy is defined
  • author is set
  • HTML is WeChat-compatible
  • IP whitelist is configured
  • AppID / AppSecret are valid
  • publishing mode is explicit: draft / paste-package / review

Recommended Article Skeleton

Use this as the default skeleton unless a better structure is required:

  1. opening with the real problem or scenario
  2. background / context only if needed
  3. core implementation / workflow / architecture
  4. concrete examples / commands / configs / Feishu doc conversion notes
  5. pitfalls and lessons learned
  6. conclusion with actionable next steps

Topic Scaffolding Templates

When the source is only a topic, use one of the following scaffolds unless the case clearly demands a different shape.

Problem-oriented technical article

  1. why this problem matters
  2. what we are going to solve or build
  3. minimal prerequisites
  4. core workflow / architecture / implementation path
  5. concrete examples or validation
  6. pitfalls and practical notes
  7. conclusion and next steps

Tool / framework evaluation article

  1. what problem the tool is trying to solve
  2. what the tool is and where it fits
  3. core concepts or architecture
  4. hands-on experience / setup notes / example flow
  5. strengths, limitations, and suitable scenarios
  6. conclusion

Workflow / practice article

  1. the original problem or goal
  2. what was tried before and why it was not ideal
  3. the improved workflow
  4. how it works in practice
  5. lessons learned
  6. recommended next step

Content review and quality gate

Publishing should not stop at "article generated successfully".

When the generated article looks publishable but weak, run a review pass before draft-box publishing:

  1. check whether the article reads like the owner's own professional output, not like a sanitized document export
  2. check whether the source document was transformed into a publishing-grade structure instead of being lightly reformatted
  3. check whether the article contains concrete examples, configs, commands, paths, or practitioner judgment
  4. check whether the opening is anchored in a real problem or scenario rather than generic setup
  5. check whether the article has enough publishable value beyond the original doc

If the review finds the article is still in "document dump" form, rewrite or restructure before publishing.

Useful review questions:

  • does this article look like something the owner would publish on their own public account?
  • did the skill preserve technical value while increasing publishability?
  • would a reader get a clear payoff from the article?
  • is the structure chosen for the reader, not just for the source document?

Completion criteria:

  • the article has passed a qualitative review, not only an AI-score check
  • if the article is still too raw, it is reworked before final packaging

Common Pitfalls

  1. Rendering new articles with html_converter.py or html_converter_mature.py instead of loading gzh-design.
  2. Passing Markdown directly to wp-publish.sh; the canonical wrapper accepts validated gzh-design HTML.
  3. Publishing the _预览.html page instead of the clean <section> fragment.
  4. Skipping the gzh-design validator or accepting warnings; publishing requires 0 ERROR / 0 WARNING.
  5. Sending raw Feishu <grid>, <callout>, <whiteboard>, Mermaid, or mindmap syntax into gzh-design.
  6. Dropping or duplicating diagrams while migrating Feishu content.
  7. Compressing a mature source document when copy-transfer mode requires fidelity.
  8. Mixing components from multiple gzh-design themes or hand-writing an unrelated parallel theme.
  9. Using browser-only CSS, native nested-list assumptions, full-page wrappers, or missing <span leaf=""> wrappers.
  10. Assuming pre-rendered HTML cannot carry local images; the HTML publisher now uploads and replaces local/external img src values.
  11. Using --allow-missing-images by default; unresolved figures should block publishing unless the user explicitly accepts missing images.
  12. Omitting --cover when the article has no resolvable first image.
  13. Falling back to random Picsum/Pixabay covers instead of the configured generate_image.py pipeline or a relevant article image.
  14. Treating masked credentials shown by Hermes as truncated values; call the configured script and diagnose only real API failures.
  15. Declaring success from draft/add alone; read the draft back and compare title, digest, content, links, and figure count.

Verification Checklist

  • publishing goal is explicit

  • input source is identified

  • article structure is chosen for the right reason

  • draft reads like a professional technical blog

  • WeChat publishing package is complete

  • final deliverable includes title / digest / HTML or Markdown / cover / next action

  • fallback behavior is clear if draft-box publishing is unavailable

  • execution assets are available: references/gzh-design-integration.md, references/wechat-publisher-execution.md, templates/wechat-publisher.yaml.example, scripts/wechat_publisher/, scripts/wp-list-accounts.sh, scripts/wp-token.sh, scripts/wp-gzh-validate.sh, scripts/wp-html.sh, scripts/wp-ai-score.sh, scripts/wp-publish.sh, scripts/wp-verify-draft.py, scripts/wp-ready-md.sh

  • gzh-design was used for Markdown → HTML and its validator reports 0 ERROR / 0 WARNING

  • the clean <section> artifact—not the _预览.html page—is the file passed to publishing

  • intake templates are used when input is a Feishu doc or topic: templates/feishu-doc-intake.md, templates/topic-intake.md

  • final publishing package follows templates/final-package.md when a structured output is needed

  • YAML configuration advice distinguishes between publishing credentials and image-generation settings

  • WeChat HTML avoids duplicate numbering and visually weak nested lists when hierarchy matters

  • Feishu-native blocks (callouts, embedded whiteboard figures, appendix images) have been explicitly converted or migrated before HTML conversion

Skill Scope

This skill is the implementation/runtime skill for WeChat personal-subscription publishing.

Class-level workflow design, evaluation criteria, and broad publishing heuristics belong in the companion skill wechat-official-article-automation.

Use wechat-autopublish when the task is to actually operate the publishing pipeline: read source content, normalize Markdown, render HTML, prepare publishing assets, and attempt draft-box publishing or produce the fallback package.

Future Extensions

This skill can later be extended to support:

  • direct Feishu-doc-to-WeChat-article conversion mode
  • topic queue and batch publishing
  • personal style profile auto-refresh from the owner's blog
  • brand glossary and preferred terminology list
  • review pipeline with approval step
  • multi-account profiles if needed
  • expand the gzh-design theme library while keeping one canonical Markdown → HTML path

What ships with it: 72 files

348.3 KB alongside SKILL.md, 26 of them executable

scripts/

32 more files not listed here. See all 72 in the repository.

Keep looking

Skills are one crate of 326,852. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.