linchpin/skills/docspress-publish
- community
Checking that the SKILL.md file is still in the repository.
Publish a repo's Markdown docs to docs.linchpin.com with DocsPress — the shared page tree, the pinned linchpin/docspress fork that scopes deletion per repo, the WP_ACCESS_TOKEN secret, and the dry-run to draft to publish promotion ladder. Use when a project needs documentation published, when asked to "set up docspress" or "get these docs on the docs site", when a sync-docs workflow fails or deletes another repo's pages, or when docs exist in the repo but nowhere else. Not for writing the docs themselves — that's `generate-docs-from-source`, vendored from the same fork.
Install
npx vskill@latest install linchpin/skills/docspress-publishSKILL.md
Publish docs with DocsPress
DocsPress does not write documentation. It is a sync action: it reads Markdown out of docs/ and creates or updates WordPress Pages from it. Two halves, and only the second one is ours — content comes from the upstream generator, and this skill owns where it lands.
The part that is genuinely Linchpin-specific is small but unguessable: every project publishes into one shared page tree on docs.linchpin.com, which means a misconfigured sync will treat every other project's pages as removed documentation and trash them.
When to use
- A project has no published documentation, or docs that live only in the repo.
- Someone asks to "set up docspress", "publish the docs", "get these on the docs site".
- A
sync-docsrun fails, publishes to the wrong place, or trashes pages it does not own. - You are adding a second (third, tenth) repo to the shared docs site.
Not this skill:
- Writing the docs → upstream
generate-docs-from-source(see Preflight). - Committing and opening the PR → `commit-and-release`
and `task-tracking`.
- Operating the docs site itself (its theme, its database) →
`wp-pressable`. docs.linchpin.com is a subsite of the Linchpin multisite; this skill never touches it directly, only pushes to it.
Owns
Canonical for: the docs.linchpin.com target configuration, the pinned fork and why it is not upstream, managed-path ownership scoping, how WP_ACCESS_TOKEN is scoped, the per-repo .docspress/brief.md contract, and the promotion ladder.
Defers: documentation content and block selection → generate-docs-from-source, vendored from the same fork; commits and PRs → commit-and-release; branch and task → task-tracking.
Preflight
Read before acting. Never assume a repo's shape.
| Look for | Tells you | If missing | |
|---|---|---|---|
git remote get-url origin | The repo slug — this becomes the page-tree segment | Ask; do not guess from the directory name | |
docs/ contents | Whether content exists, and whether anything there should not be published | Nothing to sync yet — generate first | |
.github/workflows/sync-docs.yml | Already wired; you are debugging, not installing | Install it from references/sync-docs-workflow.md | |
gh secret list --repo <owner>/<repo> | Only whether a repo-level override exists | Nothing — WP_ACCESS_TOKEN is an org secret and will not appear here. See step 5 | |
.docspress/brief.md | What this repo's docs must contain and the checks they must pass | Write one before generating — step 3 | |
generate-docs-from-source in the skill list | The generator is installed (it ships vendored) | Fetch it (step 1) before writing any page |
Step 1 — Confirm the generator is present
Content generation is deliberately not duplicated here. generate-docs-from-source ships vendored with this library from `linchpin/docspress`, our fork of Automattic/docspress, pinned to a reviewed SHA — so it is normally already installed alongside this skill.
The fork is load-bearing, not a convenience copy: it is the version that reads the per-repo .docspress/brief.md in step 3. Upstream's generator ignores that file, so the two are not interchangeable.
If it is missing — an older install, or --skip-upstream — fetch it directly:
That also brings docspress-install, the generic non-Linchpin setup path. It is intentionally not vendored: it targets an arbitrary WordPress site and knows nothing about the shared page tree or managed-path. Reach for it only when publishing to a client's own site instead of docs.linchpin.com. See `references/vendoring.md`.
→ Checkable: generate-docs-from-source appears in the agent's skill list.
Step 2 — Shape the tree
Every Linchpin project publishes under one root page, so the repo's docs must sit in a subdirectory named for the repo, not at the root of docs/.
docs-dir stays docs, so anything else under `docs/` is published too. Internal planning notes, status logs and open-questions files are a common accident — move them out of docs/ (dev/planning/ is the established home) rather than hoping nobody reads them.
→ Checkable: find docs -maxdepth 1 -type f returns nothing.
Step 3 — Generate the content
Hand off to generate-docs-from-source. What it cannot know is what this repository's docs are supposed to contain — so write that down first, in .docspress/brief.md. The generator reads it before inventorying anything and treats it as the contract:
- Shape — library, application, catalog, or monorepo. Say it explicitly. A catalog repo
(one unit per skill, per block, per package) has no exports or CLI flags to enumerate, so without this it produces one thin overview page instead of a page per unit.
- Required pages and non-goals, so the tree neither misses a section nor grows one
nobody asked for.
- Acceptance checks — countable assertions, reported back as met or unmet. "Every unit
has a page and an index row" is a check; "cover everything" is a wish.
Two constraints belong in every Linchpin brief:
- No H1 in the body. The theme renders the page title, so pages carry a frontmatter
title: and start at ##. The workflow sets create-h1: false to match.
- Pages live under `docs/<repo-slug>/` (step 2), so relative links resolve inside the
subtree this repo owns.
Keep the brief outside docs/. The collector globs **/*.md below docs-dir with dot: false, so a brief at docs/BRIEF.md would publish itself as a page; a dot-directory is skipped.
Seeding beats describing. The generator preserves existing pages and updates them in place, so committing an index stub with the exact headings you want steers it harder than any sentence in the brief.
→ Checkable: .docspress/brief.md exists, every page has frontmatter title: and no # heading, and the generator reported each acceptance check as met.
Step 4 — Add the workflow
Copy the template from `references/sync-docs-workflow.md` to .github/workflows/sync-docs.yml and substitute the repo slug. The inputs that matter:
| Input | Value | Why | |
|---|---|---|---|
wordpress-url | https://docs.linchpin.com | Self-hosted target. Do not append `/wp-json` — the action does that | |
wordpress-site | docs.linchpin.com | The site identifier, not a WordPress.com ID | |
docs-dir | docs | The whole directory, hence step 2 | |
root-slug | wordpress-plugins | The shared root page these repos publish under | |
managed-path | wordpress-plugins/<repo-slug> | The one that prevents data loss — see below | |
create-h1 | false | The theme already renders the title | |
rewrite-links | true | Relative Markdown links become page URLs | |
delete-mode | trash | Removals are recoverable |
root-slug groups WordPress plugin projects. A different class of project needs a different root — agree one rather than filing it under plugins, and use it consistently in both root-slug and managed-path.
→ Checkable: every with: key exists in the pinned revision's action.yml.
Why managed-path is not optional
root-slug alone serves as both the URL prefix and the ownership boundary that scopes deletion. With several repos publishing below one shared parent page, each one treats the others' pages as removed documentation and trashes them on its first non-dry-run.
managed-path narrows ownership to one branch below the root, so a sync only cleans up its own removed docs. It is not in upstream `Automattic/docspress` — which is the entire reason the workflow pins the linchpin/docspress fork. Verify the pin before trusting it:
dist/index.js in that list means the input is compiled into the bundle the action actually runs, not just declared in action.yml.
→ Checkable: managed-path names this repo's segment and nothing broader.
Step 5 — The token
WP_ACCESS_TOKEN is an organisation secret, available to every repo in linchpin. There is normally nothing to provision, and nothing to check.
Do not report it as a blocker on a `gh secret list` miss. That command lists only repository secrets, so an org secret never appears in it. Reading absence there as "the token is missing" produces a confident false blocker on every repo:
Enumerating org secrets needs the admin:org scope, which an agent normally will not have, so treat "cannot verify" as the expected state rather than a problem.
The real signal is the first dry run: a token that is missing or unauthorised fails there with a 401 or 403 from WordPress, and that is a workflow-run result, not something to predict beforehand.
→ Checkable: nothing to do unless a run has actually failed on auth.
Step 6 — Verify locally, before any run
Cheapest checks first. Runnable snippets are in `references/verification.md`.
- Block JSON parses — every
wp:docspress/*comment is valid compact JSON with
allowed enum values. → all blocks parse
- Links and anchors resolve — every relative link and
#fragmentresolves from the
file containing it. → zero unresolved
- Converter round-trip — run the pinned action's own
markdownToBlocksover the tree.
→ zero conversion failures, and every block semantically identical
Byte-for-byte comparison on step 3 produces false alarms. DocsPress deliberately normalizes HTML-sensitive attribute characters to WordPress-safe Unicode escapes — < becomes \u003c and > becomes \u003e — so most blocks come back altered and none of it is a defect. Parse both sides and compare the attribute objects, not the raw strings.
Step 7 — Promote, one rung at a time
The workflow ships inert. Confirm the Actions summary at each rung before the next.
| Rung | Change | Confirms | |
|---|---|---|---|
| 1 | Run as-is (dry-run: true, status: draft) | The planned create/update/delete counts. A non-zero delete count on a first run means managed-path is wrong — stop | |
| 2 | dry-run: false | Pages exist as drafts; the page tree is right | |
| 3 | status: publish | Content and hierarchy are public | |
| 4 | Add the push trigger | Ongoing sync, only once someone has approved it |
Reverse sync (mode: reconcile, WordPress edits becoming pull requests) is a separate decision that authorises writes to both systems and needs a loop guard. Get explicit sign-off; the template documents it but leaves it commented out.
→ Checkable: each rung's Actions summary reviewed before the next is enabled.
Block catalog
At the pinned SHA the generator's table matches the docspress-blocks plugin: 17 blocks, hero, audience-paths, version-notice and version-switcher included. A project's root index.md reads as unfinished without the first two, so plan them in. (docspress/was-this-helpful is an eighteenth name you will meet; it is theme-owned and belongs in the Page template, not in Markdown.)
When a target site runs a different plugin revision, that revision's source is the authority — blocks/<name>/block.php, where each docspress_blocks_allowed_value() call names the valid values for one attribute — rather than the skill table or an existing page.
Guardrails
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/docspress-publish/SKILL.md
Popularity
- Repository stars
- 1
- 7-day trend score
- 8
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/linchpin/skills/docspress-publish)