Manage Blog Publishing
Use publishing/schedule.json as the durable external-syndication plan and state record. Keep self-hosted blog publication entirely outside this automation.
Enforce Hard Boundaries
- Enroll only an article whose front matter explicitly has
draft: false.
- Never publish to
site, run pnpm publish:article, or change article front matter from this workflow.
- Auto-enroll only an article whose front matter
date is strictly later than discovery.enabledAfter.
- Never discover or enqueue an article whose front matter sets
publish.autoSyndication: false.
- Treat
hacker-news as manual-only. Never include it in platformGroups, pipeline, --platforms, or queue release records; use ../publish-hacker-news/SKILL.md only after explicit user authorization.
- Require the article to be tracked and unchanged in Git, then require its canonical URL to be public and contain the exact article title before enrollment.
- Treat a queued platform as authorization for that article and external platform only.
The queue validator enforces draft state, canonical URL equality, a verified manual site record, and the absence of site from the automated pipeline.
Resolve Current Wechatsync Targets
Before inspecting due work or starting a release:
- Call Wechatsync
list_platforms with forceRefresh: true.
- For platforms other than
x, keep only entries where isAuthenticated is true and capabilities contains both article and draft.
- Keep
x when its refreshed entry is authenticated. X uses the summary-link workflow below, not Wechatsync full-article draft synchronization.
- Exclude local/non-publishing targets such as
zip-download and manual-only targets such as hacker-news, even if they report authenticated.
- Use the returned platform IDs exactly as reported. Never infer targets from Wechatsync documentation, an old run,
platformGroups, or a handwritten supported-platform list.
- If refresh succeeds but no target is eligible, pass an explicit empty set as
--platforms=; report attention and leave queued work for a later run.
- If the extension is disconnected or the refreshed list cannot be obtained, stop without changing queue state.
The eligible target set may change on every run. platformGroups is only an optional policy map for article-level class exclusions; it is not evidence that a platform is connected.
Discover and Enroll New Articles
- Run
pnpm publish:queue validate, then run pnpm publish:queue discover exactly once.
- Treat only the returned candidates as this run's discovery set. Never scan drafts manually or change
discovery.enabledAfter during a scheduled run.
- For each candidate, require
git ls-files --error-unmatch <path> to succeed and git status --short -- <path> to be empty.
- Fetch the exact canonical URL and verify that the public page contains the exact article title. A generic HTTP success is insufficient. If verification fails, leave it unqueued so a later run can retry.
- Run
pnpm publish:queue enqueue --article <path> --title <exact-title> --url <exact-canonical-url> for each verified candidate, in the order returned by discover.
- The command appends positions in increments of 100 and records the front matter
date as the manual site publication time:
{
"status": "published",
"attempts": 1,
"publicationMethod": "manual",
"publishedAt": "<actual-manual-publication-time>",
"verifiedAt": "<verification-time>",
"url": "<canonical-url>"
}
- If any article was enrolled, validate again, commit only
publishing/schedule.json with chore: enqueue newly published blog posts, and push main before inspecting due work.
- Use
exclude.groups for a configured policy group and exclude.platforms for an individual Wechatsync platform ID. Preserve release records when reordering or changing exclusions.
Never enqueue an article dated at or before the activation cutoff. Do not move the cutoff backward to import historical posts.
An English Hacker News translation with publish.autoSyndication: false is intentionally absent from discovery and must stay outside this schedule.
Inspect Due Work
Run:
pnpm publish:queue validate
pnpm publish:queue due --platforms <refreshed-platform-ids>
due is read-only. Report every attention item. Treat returned actions as one run's immutable work list and process those actions only. The queue starts external distribution for at most one previously unstarted article per run while also advancing due stages for articles already in progress.
Run the Scheduled Workflow
- Require the local
main checkout; external publication needs the user's main Chrome login state.
- Require
publishing/schedule.json to be unchanged. Allow unrelated working-tree changes under the repository's -i rule, but never stage them.
- Discover, verify, enqueue, commit, and push newly published articles using the workflow above.
- Resolve the current Wechatsync targets using the required refresh procedure above.
- Run
pnpm publish:queue due --platforms <comma-separated-refreshed-ids> exactly once after enrollment. This allows a newly enrolled article whose interval has elapsed to publish in the same run.
- Report
attention items. If no actions are due, stop.
- For each returned external action, run
start --platforms <same-refreshed-platform-ids>, stage only publishing/schedule.json, and commit chore: start <platform> publication for <slug>.
- Publish through Wechatsync and the user's main Chrome as described below.
- After verifying the exact public URL, run
complete, commit only the schedule with chore: record <platform> publication for <slug>, then push main.
- On failure, first check whether a public post already exists. If it does not, run
block, commit only the schedule with chore: block <platform> publication for <slug>, push main, and stop later actions for that article.
Never mark a draft, editor page, generic HTTP success, or unverified post as published.
Publish an External Target
- Read the main-Chrome syndication constraints in
../publish-blog-article/SKILL.md.
- If the target is
x, follow Publish X Summary Link below and do not run the full-article draft workflow.
- For every other target, use Wechatsync with the main Chrome extension to create the full-article draft. Upload local images first when required.
- Use the user's main Chrome session to complete metadata and final publication. Never use a separate browser profile or isolated browser.
- Verify the exact final public URL before calling
complete.
- If authentication, CAPTCHA, account confirmation, or an undefined platform workflow blocks final publication, record
blocked. A Wechatsync draft is not completion.
Publish X Summary Link
- Never send the full article body to X and never call Wechatsync
sync_article for X.
- Build one standard X post, not an X Article. Use front matter
publish.x.text when present; otherwise compose a concise summary from the article title and summary.
- Append the exact
releases.site.url canonical blog URL. Preserve the URL verbatim and keep the complete post within the limit shown by X's composer.
- Publish through the user's main Chrome X composer and verify the resulting public post URL before calling
complete.
Recover a Blocked Release
- Inspect
lastError and the external platform before retrying.
- If the public post already exists, verify it, run
start, then complete; do not republish.
- Otherwise resolve the blocker, run
start to increment attempts, and follow the normal external workflow.
State Commands
Use these commands only for external platforms; the CLI rejects site:
pnpm publish:queue discover
pnpm publish:queue enqueue --article <path> --title <exact-title> --url <canonical-url>
pnpm publish:queue start --article <path> --platform <external-platform> --platforms <refreshed-platform-ids>
pnpm publish:queue complete --article <path> --platform <external-platform> --url <public-url>
pnpm publish:queue block --article <path> --platform <external-platform> --error <message>
Do not edit external release states manually during normal operation.
1---2name: manage-blog-publishing3description: Discover newly published Hugo articles, enroll them in this repository's external-platform queue, and execute due syndication. Only discover articles published after the configured activation cutoff, resolve eligible targets from the currently authenticated Wechatsync platforms at run time, and handle X as a summary-and-canonical-link post rather than a full article. Use when Codex needs to run the recurring workflow, inspect or reorder the queue, configure exclusions, or recover blocked releases. Never use it to publish drafts or publish to the self-hosted site.4---56# Manage Blog Publishing78Use `publishing/schedule.json` as the durable external-syndication plan and state record. Keep self-hosted blog publication entirely outside this automation.910## Enforce Hard Boundaries1112- Enroll only an article whose front matter explicitly has `draft: false`.13- Never publish to `site`, run `pnpm publish:article`, or change article front matter from this workflow.14- Auto-enroll only an article whose front matter `date` is strictly later than `discovery.enabledAfter`.15- Never discover or enqueue an article whose front matter sets `publish.autoSyndication: false`.16- Treat `hacker-news` as manual-only. Never include it in `platformGroups`, `pipeline`, `--platforms`, or queue release records; use `../publish-hacker-news/SKILL.md` only after explicit user authorization.17- Require the article to be tracked and unchanged in Git, then require its canonical URL to be public and contain the exact article title before enrollment.18- Treat a queued platform as authorization for that article and external platform only.1920The queue validator enforces draft state, canonical URL equality, a verified manual site record, and the absence of `site` from the automated pipeline.2122## Resolve Current Wechatsync Targets2324Before inspecting due work or starting a release:25261. Call Wechatsync `list_platforms` with `forceRefresh: true`.272. For platforms other than `x`, keep only entries where `isAuthenticated` is `true` and `capabilities` contains both `article` and `draft`.283. Keep `x` when its refreshed entry is authenticated. X uses the summary-link workflow below, not Wechatsync full-article draft synchronization.294. Exclude local/non-publishing targets such as `zip-download` and manual-only targets such as `hacker-news`, even if they report authenticated.305. Use the returned platform IDs exactly as reported. Never infer targets from Wechatsync documentation, an old run, `platformGroups`, or a handwritten supported-platform list.316. If refresh succeeds but no target is eligible, pass an explicit empty set as `--platforms=`; report attention and leave queued work for a later run.327. If the extension is disconnected or the refreshed list cannot be obtained, stop without changing queue state.3334The eligible target set may change on every run. `platformGroups` is only an optional policy map for article-level class exclusions; it is not evidence that a platform is connected.3536## Discover and Enroll New Articles37381. Run `pnpm publish:queue validate`, then run `pnpm publish:queue discover` exactly once.392. Treat only the returned candidates as this run's discovery set. Never scan drafts manually or change `discovery.enabledAfter` during a scheduled run.403. For each candidate, require `git ls-files --error-unmatch <path>` to succeed and `git status --short -- <path>` to be empty.414. Fetch the exact canonical URL and verify that the public page contains the exact article title. A generic HTTP success is insufficient. If verification fails, leave it unqueued so a later run can retry.425. Run `pnpm publish:queue enqueue --article <path> --title <exact-title> --url <exact-canonical-url>` for each verified candidate, in the order returned by `discover`.436. The command appends positions in increments of 100 and records the front matter `date` as the manual site publication time:4445```json46{47 "status": "published",48 "attempts": 1,49 "publicationMethod": "manual",50 "publishedAt": "<actual-manual-publication-time>",51 "verifiedAt": "<verification-time>",52 "url": "<canonical-url>"53}54```55567. If any article was enrolled, validate again, commit only `publishing/schedule.json` with `chore: enqueue newly published blog posts`, and push `main` before inspecting due work.578. Use `exclude.groups` for a configured policy group and `exclude.platforms` for an individual Wechatsync platform ID. Preserve release records when reordering or changing exclusions.5859Never enqueue an article dated at or before the activation cutoff. Do not move the cutoff backward to import historical posts.60An English Hacker News translation with `publish.autoSyndication: false` is intentionally absent from discovery and must stay outside this schedule.6162## Inspect Due Work6364Run:6566```bash67pnpm publish:queue validate68pnpm publish:queue due --platforms <refreshed-platform-ids>69```7071`due` is read-only. Report every `attention` item. Treat returned actions as one run's immutable work list and process those actions only. The queue starts external distribution for at most one previously unstarted article per run while also advancing due stages for articles already in progress.7273## Run the Scheduled Workflow74751. Require the local `main` checkout; external publication needs the user's main Chrome login state.762. Require `publishing/schedule.json` to be unchanged. Allow unrelated working-tree changes under the repository's `-i` rule, but never stage them.773. Discover, verify, enqueue, commit, and push newly published articles using the workflow above.784. Resolve the current Wechatsync targets using the required refresh procedure above.795. Run `pnpm publish:queue due --platforms <comma-separated-refreshed-ids>` exactly once after enrollment. This allows a newly enrolled article whose interval has elapsed to publish in the same run.806. Report `attention` items. If no actions are due, stop.817. For each returned external action, run `start --platforms <same-refreshed-platform-ids>`, stage only `publishing/schedule.json`, and commit `chore: start <platform> publication for <slug>`.828. Publish through Wechatsync and the user's main Chrome as described below.839. After verifying the exact public URL, run `complete`, commit only the schedule with `chore: record <platform> publication for <slug>`, then push `main`.8410. On failure, first check whether a public post already exists. If it does not, run `block`, commit only the schedule with `chore: block <platform> publication for <slug>`, push `main`, and stop later actions for that article.8586Never mark a draft, editor page, generic HTTP success, or unverified post as published.8788## Publish an External Target89901. Read the main-Chrome syndication constraints in `../publish-blog-article/SKILL.md`.912. If the target is `x`, follow **Publish X Summary Link** below and do not run the full-article draft workflow.923. For every other target, use Wechatsync with the main Chrome extension to create the full-article draft. Upload local images first when required.934. Use the user's main Chrome session to complete metadata and final publication. Never use a separate browser profile or isolated browser.945. Verify the exact final public URL before calling `complete`.956. If authentication, CAPTCHA, account confirmation, or an undefined platform workflow blocks final publication, record `blocked`. A Wechatsync draft is not completion.9697## Publish X Summary Link98991. Never send the full article body to X and never call Wechatsync `sync_article` for X.1002. Build one standard X post, not an X Article. Use front matter `publish.x.text` when present; otherwise compose a concise summary from the article title and summary.1013. Append the exact `releases.site.url` canonical blog URL. Preserve the URL verbatim and keep the complete post within the limit shown by X's composer.1024. Publish through the user's main Chrome X composer and verify the resulting public post URL before calling `complete`.103104## Recover a Blocked Release1051061. Inspect `lastError` and the external platform before retrying.1072. If the public post already exists, verify it, run `start`, then `complete`; do not republish.1083. Otherwise resolve the blocker, run `start` to increment `attempts`, and follow the normal external workflow.109110## State Commands111112Use these commands only for external platforms; the CLI rejects `site`:113114```bash115pnpm publish:queue discover116pnpm publish:queue enqueue --article <path> --title <exact-title> --url <canonical-url>117pnpm publish:queue start --article <path> --platform <external-platform> --platforms <refreshed-platform-ids>118pnpm publish:queue complete --article <path> --platform <external-platform> --url <public-url>119pnpm publish:queue block --article <path> --platform <external-platform> --error <message>120```121122Do not edit external release states manually during normal operation.