validate-block-markup
Skill22 starsChanged 5 months agoMITView on GitHub
Validate, diagnose, or repair standalone serialized WordPress Gutenberg block markup built from core blocks, using a pinned Node.js runtime. Use when the user explicitly asks to validate, check, lint, or debug block markup or `<!-- wp:... -->` block comments, reports an invalid block, "unexpected or invalid content", or an "Attempt Block Recovery" prompt, or is about to paste markup into the WordPress Code Editor or assign it to post_content. Scope is standalone, cross-site-portable core block markup only; site-specific, theme-specific, dynamic, plugin, and third-party block content are out of scope. Do not trigger merely because another skill emits block markup - prototype-wp (offline WP plugin prototypes), wp-spec-to-goal and wp-requirements-to-goals (Codex goal bundles), and pressbridge (pushing code, CSS, or blocks to a live remote WP site) own their own workflows.
In this repository13 other files it gives its agents.
- ask-firstSkill
- cli-spec-to-goalSkill
- codex-imagegenSkill
- design-system-to-skillSkill
- extract-design-mdSkill
- extract-design-systemSkill
- handoff-docSkill
- orchestrateSkill
- prototype-wpSkill
- webg-spec-to-goalSkill
- wp-requirements-to-goalsSkill
- wp-rest-apiSkill
- wp-spec-to-goalSkill
The file
We split this skill into the rules it gives an agent
8 rules. About 0 are common, 5 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 8
Check serialized block markup against the WordPress core block library running in Node.js.
- Distinctive: line 19
No WordPress, PHP, wp-env, Docker, Playwright, or browser is required.
- Very specific: line 20
Run validation only through scripts/validate-block-markup.cjs.
- Distinctive: line 64
Use this whenever the request is to validate, check, review, or diagnose.
- Very specific: line 66
Put the markup in a temporary .html file, or pipe it on stdin.
- Distinctive: line 68
Read the JSON report from stdout.
- Distinctive: line 72
Stop there. Suggest fixes in prose.
- Distinctive: line 76
Use this only when the user asked for markup to be fixed, or when you generated the markup yourself.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Validate Block Markup
Check serialized block markup against the WordPress core block library running in Node.js. Treat structural validity and cross-site portability as separate verdicts, and treat review and repair as separate jobs.
Verdicts are produced against the core block definitions shipped with WordPress 7.0.2. Always tell the user which snapshot the verdict came from.
Requirements
- Node.js 20.10 or newer, with
npmonPATH. - First run installs a runtime into this skill's own directory:
npm ciof 350 packages, about 545 MB on disk, roughly 25 seconds, and it needs npm registry access. Later runs are offline and instant.--helpand--versionanswer immediately and install nothing. - The install never touches the user's project — no edits to their
package.json, no lockfile changes, nothing written to a project-levelnode_modules. Everything lands in<skill-directory>/node_modules/. - That distinction matters less than it sounds: the common
npx skills addlayout puts this skill inside the user's repository, so those 545 MB land in their repo tree. Say so before the first run. The skill ships a.gitignorecoveringnode_modules/and rewrites it before installing if it went missing, so git stays clean without the user doing anything. - Most of the installed bytes are
@wordpress/*packages, licensed GPL-2.0-or-later. The skill's own code is MIT. - No WordPress, PHP, wp-env, Docker, Playwright, or browser is required.
- Run validation only through
scripts/validate-block-markup.cjs. Do not import the module into your own process.
Dependency Bootstrap
The executable bootstraps itself. Before loading the validator it checks <skill-directory>/node_modules/ for four pinned packages and, if any is absent or at a different version, runs this in the skill directory:
npm ci --omit=dev --ignore-scripts --no-audit --no-fund| Package | Pinned version |
@wordpress/blocks | 15.13.1 |
@wordpress/block-library | 9.40.2 |
@wordpress/block-serialization-default-parser | 5.40.1 |
jsdom | 26.1.0 |
The pins the executable enforces live in a hardcoded map inside scripts/validate-block-markup.cjs, duplicated from package.json. When bumping a version, change both — they are not read from each other.
Bootstrap progress goes to stderr. If npm, registry access, or a writable skill directory is unavailable, the command exits 2; stop and report that validation could not run. Never run the install in the user's project.
Command Surface
node <skill-directory>/scripts/validate-block-markup.cjs [options] [<file|directory|->...]- Accepts any number of paths in one invocation.
-reads stdin. Stdin is also the default when no path is given.- A directory argument validates the
.htmlfiles directly inside it, in sorted order. Scanning is not recursive and ignores every other extension, so pointing at a tree silently validates a subset. Pass files explicitly when the tree matters. --treats every following argument as a path.-h/--helpprints usage.-v/--versionprints the skill version and the pinned WordPress snapshot.- On exit
0and1, stdout is nothing but a parseable JSON array — one report per input source. Bootstrap noise and all diagnostics go to stderr. Parse stdout, ignore stderr.
Exit codes:
| Code | Meaning |
0 | Every input source passed. |
1 | Findings contain at least one error. |
2 | Usage or input error — unreadable path, unknown option, no input sources found (including a directory with no .html files), or no input given while stdin is a terminal. |
Validation Workflow
Use this whenever the request is to validate, check, review, or diagnose. Do not modify the user's markup in this mode.
- Put the markup in a temporary
.htmlfile, or pipe it on stdin. - Run the command.
- Read the JSON report from stdout.
- Report
valid, every error, every warning, and every entry innotChecked. Never describe anotCheckeditem as verified. - Name the WordPress snapshot (
wordpressVersion) the verdict applies to. canonicalMarkupappears when parse-then-serialize changed the input. Offer it as a suggestion. Never silently substitute it for what the user supplied.- Stop there. Suggest fixes in prose; do not apply them unless asked.
Repair Workflow
Use this only when the user asked for markup to be fixed, or when you generated the markup yourself.
- Fix the errors at their source in the markup.
- Rerun the validator after each round of edits.
- Repeat until
validistrue. - Warnings may remain if the user accepts them. State which ones you left and why.
- Return the repaired markup, and say what changed.
- Substitute the validator's canonical serialization only when the user explicitly asked for normalization.
Interpret Findings
Errors — these make valid false:
no-blocks: the input produced zero blocks. Check the file is not empty and actually contains block comments.malformed-attribute-json: the JSON in an opening delimiter does not parse. Fix the JSON. Carriesline, notpath.freeform-html: content fell through as freeform/classic HTML. Wrap it in a core block.unregistered-block: the block is not in the pinned core library. Replace it with a core block.missing-block: the markup already contains acore/missingplaceholder, so the editor that produced it did not recognize the original block. Rebuild that section from core blocks; the original block cannot be recovered here.invalid-saved-content: the saved HTML does not match the registered core save implementation — this is what produces "Attempt Block Recovery" in the editor. Read theissuesarray for the exact mismatch, then fix the opening attributes and the saved HTML together.nonportable-core-block: a core block that depends on post, query, comment, taxonomy, template, authentication, or site-setting context. Replace it with static content.site-entity-id: an attachment, author, post, term, navigation, or reusable-block database ID. Remove the ID and any class derived from it.root-relative-url: anhreforsrcstarting with a single/. Use a genuinely portable URL, or disclose the destination-site dependency.missing-fragment-target: a#anchorlink with no matchingidin the same input. Add the anchor or drop the link.non-idempotent-serialization: a second parse-then-serialize pass changed the canonical markup, so the markup is unstable across editor round-trips and will keep drifting every time it is opened and saved. There is no patch for this — rebuild the affected blocks from scratch.
Warnings — these do not affect valid:
noncanonical-serialization: WordPress canonicalized the input. Always emitted at warning level; it never escalates. Compare againstcanonicalMarkupand let the user decide.theme-dependent-style: preset or style attributes whose appearance depends on the destination theme. Keep only if the user accepts that.custom-class: a custom CSS class that may not exist on the destination site. Same call.
What valid: true Does Not Mean
valid: true means the markup parses, matches the core save implementations, and carries no cross-site portability error. It is not a publication-safety verdict.
- Link checks only flag
href/srcvalues beginning with a single/, and#fragments with no matchingid.javascript:anddata:URLs, event-handler attributes such asonclick, and inline<script>all pass unflagged. - KSES filtering, user capabilities, and destination-site sanitization are never evaluated. Markup that passes here can still be stripped — or still be dangerous — on a real site.
- Report the whole
notCheckedarray with every verdict, not just when something fails.
See references/validation-contract.md for the full report schema, finding field shapes, portability policy, and limitations.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

