# SEO Publish

> Publishes a validated article to the client's website (CMS adapter per client.json). Use when a funnel card reaches the publication stage, or when asked to publish an approved article. Refuses to publish without documented client validation and QA verdict. Triggers on "publie l'article", "publish", publication-stage kanban cards.

- Skill: `lcrvl2/seo-publish` (Agent Skill)
- Install (CLI): `npx skillmds@latest add lcrvl2/seo-publish`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lcrvl2/seo-publish/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Marketing & Growth
- Author: lcrvl2 (https://skillmd.com/u/lcrvl2)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/lcrvl2/seo-publish

---


# SEO Publish

Publication worker: takes a validated article file and posts it to the client's site. This is the ONLY skill allowed to make content public; everything upstream is drafts in the workdir.

---

## Preconditions (hard gate : refuse if any is missing)

1. **Client validation documented**: the kanban card (or the request) shows an explicit client approval of THIS article.
2. **QA verdict**: a Content-quality-evaluator scorecard with PASS (or CONDITIONAL + editor override documented).
3. **CMS credentials available** for this client.

If any is missing: do NOT publish; report exactly what is missing (and on a kanban card: `kanban_block` with the reason).

---

## CMS resolution

From `seo/clients/<slug>/client.json` → `cms` block:

```json
"cms": { "type": "wordpress" | "wix" | "none", "base_url": "...", "auth_ref": "env:CLIENT_<SLUG>_CMS_TOKEN" }
```

`auth_ref` is a reference to an environment variable, never a secret in clear text.

### type: wordpress

REST API `POST {base_url}/wp-json/wp/v2/posts` with an Application Password (Basic auth from the referenced env var).
- Payload: `title`, `slug`, `content` (markdown converted to HTML), `status: "draft"` first.
- Verify the draft renders (GET the preview), then update `status: "publish"`.
- Set meta description via the SEO plugin's REST field if exposed (Yoast/RankMath); otherwise report that meta must be set manually.

### type: wix

Wix Blog REST API (`https://www.wixapis.com/blog/v3/draft-posts`), auth via API key + site ID from the referenced env vars. Create as draft, then publish. If the client's Wix plan/API access is not configured: block with "Wix API access to configure", do not attempt workarounds.

### type: none

No CMS connected: deliver instead of publishing. Deposit the final article + a short integration note in `seo/clients/<slug>/outputs/content/<date>/to-publish/` and notify the owner. The card is NOT marked published.

---

## Publication steps

1. Resolve CMS + credentials. Check preconditions.
2. Convert the article markdown: strip frontmatter, convert to the CMS format, keep internal links as site-relative URLs, keep visual placeholders as clearly marked TODO blocks ONLY if the card says visuals are pending; otherwise refuse (an article with raw placeholders must not go live).
3. Create as **draft** on the CMS. Fetch/preview it once: title, headings, links intact.
4. Publish. Fetch the live URL, verify HTTP 200 and that the H1 matches.
5. Report: live URL, publication timestamp, any manual follow-ups (meta description, visuals). On a kanban card: comment all of this, then hand back to the orchestrator.

## Failure behavior

Any API error: stop, report the exact error, never retry more than twice, never mark published on failure. Rollback: if publish succeeded but verification failed, revert the post to draft and report.

