From cf3449b8ade0ba9aca4df3f49a200830cb83f00c Mon Sep 17 00:00:00 2001 From: Noel Tock Date: Fri, 11 Sep 2026 18:39:14 +0700 Subject: [PATCH] Clarify Block Runner skill artifact routing --- dev/test/fixtures/skill-activation.json | 50 ++++++++++++++++++++++++ dev/test/skill.test.ts | 39 ++++++++++++++++--- skills/block-runner/SKILL.md | 52 ++++++++++++------------- 3 files changed, 109 insertions(+), 32 deletions(-) diff --git a/dev/test/fixtures/skill-activation.json b/dev/test/fixtures/skill-activation.json index 3b70319..656719e 100644 --- a/dev/test/fixtures/skill-activation.json +++ b/dev/test/fixtures/skill-activation.json @@ -19,5 +19,55 @@ "Update WordPress core and all installed plugins.", "Back up the WordPress database.", "Configure redirects in the WordPress admin." + ], + "routes": [ + { + "prompt": "Invent a native Gutenberg feature section for this WordPress page.", + "route": "assemble", + "firstReference": "references/ASSEMBLE.md", + "artifact": "page post_content" + }, + { + "prompt": "Convert this authored landing-page HTML and its CSS into editable WordPress blocks.", + "route": "convert", + "firstReference": "references/GUIDE.md#4-convert--someone-elses-html-into-page-post_content", + "artifact": "page post_content" + }, + { + "prompt": "Create a static named Gutenberg block in source code for this existing project.", + "route": "author", + "firstReference": "references/AUTHORING.md", + "artifact": "registered block source" + }, + { + "prompt": "Implement a custom PHP renderer and editor control in my existing WordPress plugin.", + "route": "project-owned", + "firstReference": "references/GUIDE.md#11-continue-project-owned-development-when-static-generation-does-not-fit", + "artifact": "project-owned implementation" + }, + { + "prompt": "Repair this supplied Gutenberg markup before it is saved.", + "route": "validate-fix-validate", + "firstReference": "references/GUIDE.md#5-the-pre-flight-loop--before-page-markup-is-saved", + "artifact": "validated page post_content" + }, + { + "prompt": "Convert the rendered frontend HTML I scraped into authored WordPress content.", + "route": "exclude", + "firstReference": null, + "artifact": "none" + }, + { + "prompt": "Create a reusable WordPress section.", + "route": "clarify-artifact", + "firstReference": "references/GUIDE.md#0-understand-the-project-before-choosing-output", + "artifact": "choose page post_content or registered block source before writing" + }, + { + "prompt": "Configure redirects in the WordPress admin.", + "route": "exclude", + "firstReference": null, + "artifact": "none" + } ] } diff --git a/dev/test/skill.test.ts b/dev/test/skill.test.ts index 7c402d6..6154452 100644 --- a/dev/test/skill.test.ts +++ b/dev/test/skill.test.ts @@ -36,16 +36,45 @@ describe('canonical agent skill', () => { expect(guide).toMatch(/custom PHP renderer or custom editor\s+behaviour/); }); - it('keeps a balanced activation regression set', async () => { + it('keeps activation coverage and explicit artifact routes', async () => { const fixture = JSON.parse( await readFile(new URL('./fixtures/skill-activation.json', import.meta.url), 'utf8'), - ) as { shouldTrigger: string[]; shouldNotTrigger: string[] }; + ) as { + shouldTrigger: string[]; + shouldNotTrigger: string[]; + routes: Array<{ + prompt: string; + route: 'assemble' | 'convert' | 'author' | 'project-owned' | 'validate-fix-validate' | 'exclude' | 'clarify-artifact'; + firstReference: string | null; + artifact: string; + }>; + }; - expect(fixture.shouldTrigger).toHaveLength(9); - expect(fixture.shouldNotTrigger).toHaveLength(8); - expect(new Set([...fixture.shouldTrigger, ...fixture.shouldNotTrigger]).size).toBe(17); + expect(fixture.shouldTrigger.length).toBeGreaterThan(0); + expect(fixture.shouldNotTrigger.length).toBeGreaterThan(0); + expect(new Set([...fixture.shouldTrigger, ...fixture.shouldNotTrigger]).size).toBe( + fixture.shouldTrigger.length + fixture.shouldNotTrigger.length, + ); expect(fixture.shouldTrigger.every((prompt) => /WordPress|Gutenberg|block/i.test(prompt))).toBe(true); expect(fixture.shouldNotTrigger.some((prompt) => /non-WordPress|not use WordPress/i.test(prompt))).toBe(true); expect(fixture.shouldTrigger).toContain('Create a reusable named Gutenberg block in my existing WordPress plugin.'); + + const routeNames = new Set(fixture.routes.map((entry) => entry.route)); + expect(routeNames).toEqual( + new Set(['assemble', 'convert', 'author', 'project-owned', 'validate-fix-validate', 'exclude', 'clarify-artifact']), + ); + expect(fixture.routes.every((entry) => entry.prompt.length > 0 && entry.artifact.length > 0)).toBe(true); + expect( + fixture.routes + .filter((entry) => entry.route !== 'exclude') + .every((entry) => entry.firstReference?.startsWith('references/')), + ).toBe(true); + expect(fixture.routes.filter((entry) => entry.route === 'exclude').every((entry) => entry.firstReference === null)).toBe(true); + expect(fixture.routes.find((entry) => entry.route === 'clarify-artifact')?.artifact).toContain('before writing'); + + const skill = await readFile(new URL('../../skills/block-runner/SKILL.md', import.meta.url), 'utf8'); + for (const reference of fixture.routes.flatMap((entry) => (entry.firstReference ? [entry.firstReference] : []))) { + expect(skill).toContain(reference.split('#', 1)[0]!); + } }); }); diff --git a/skills/block-runner/SKILL.md b/skills/block-runner/SKILL.md index 7f89a58..5e2654a 100644 --- a/skills/block-runner/SKILL.md +++ b/skills/block-runner/SKILL.md @@ -4,8 +4,9 @@ description: >- Turn WordPress page content or authored design HTML into valid, native, editable Gutenberg blocks, or plan a reusable named registered block for deterministic source generation. Use when creating WordPress page content or sections, converting authored HTML or a design-tool export into block - markup, authoring a reusable named block in an existing WordPress project, understanding its - block integration before generation, validating or repairing Gutenberg + markup, authoring a reusable named block in an existing WordPress project, continuing an + in-scope Gutenberg component through custom PHP or editor code, understanding its block + integration before generation, validating or repairing Gutenberg markup, or before writing blocks to WordPress. Do not use for general WordPress administration, unrelated plugin or theme code, frontend-scraped HTML, or non-WordPress HTML. license: GPL-2.0-or-later @@ -14,36 +15,33 @@ compatibility: Requires Node.js ^20.19.0 || ^22.13.0 || >=24.0.0 and shell acces # Block Runner -## Start with the user's project +## Pick the artifact first -For a component that belongs in an existing project, read `references/GUIDE.md` §0 before -choosing an output, and `references/CONSTRUCTION-PATTERNS.md` to choose an implementation route -and inspect its contracts. Use relevant source and site context to recommend reuse, supported -generation or a developer handoff. Recognizing a route does not add generator support. Ask only -for choices that the request and repository do not answer; use structured questions if your -harness supports them, otherwise ask in plain language. Skip discovery for a self-contained -markup check or when the relevant project facts are already established. +Choose the visible result before discovering a project. Read the named first reference, use the +condition, and stop at its stated boundary. Do not load a construction taxonomy for a +self-contained page-content or markup-repair task. -## The short version +| Requested artifact | First reference | Use when | Completion boundary | +| --- | --- | --- | --- | +| Native page or post structure | [ASSEMBLE.md](references/ASSEMBLE.md), then [GUIDE.md §5–6](references/GUIDE.md) | You are inventing a page section and have no authored HTML whose styling must survive. Run `npx -y block-runner@latest assemble - --json` with an intent tree. | Valid native page `post_content`, delivered to the agreed destination. | +| Page or post content from authored design HTML | [GUIDE.md §4](references/GUIDE.md) | The supplied source is authored HTML; use `npx -y block-runner@latest convert - --json` when its CSS matters. | Valid native page `post_content` plus reported fallbacks and styling limits. Never treat frontend-scraped rendered HTML as authored input. | +| Reusable, named static registered block source | [AUTHORING.md](references/AUTHORING.md) | The requested result is a static `namespace/slug` block in code. | Confirmed source at its exact retained destination; build, integration, and WordPress proof remain separate. The complete plan in [AUTHORING-PLAN.md](references/AUTHORING-PLAN.md) is an advanced route, not a prerequisite. | +| Custom PHP renderer or editor behaviour in an existing project | [GUIDE.md §1.1](references/GUIDE.md) | Static generation cannot satisfy the requested component. | Continue in project-owned code; retain a useful native subtree only when it genuinely helps. Inspect [CONSTRUCTION-PATTERNS.md](references/CONSTRUCTION-PATTERNS.md) only when project facts needed for that implementation are missing. | +| Supplied block markup to repair or check | [GUIDE.md §5](references/GUIDE.md) | Markup already exists and must be safe to save. | `validate` → `fix` → `validate`; do not save a hard-invalid result. | -Pick by the requested artifact: +If “reusable section” does not say whether it is page `post_content` or a named registered source +block, ask that one artifact question before writing. Do not use this skill for unrelated WordPress +administration, non-WordPress HTML, or frontend-scraped HTML presented as source. -- **You need a reusable, named static registered block in code** → read `references/AUTHORING.md`. - For authored HTML, submit a declarative `AuthorOptions.proposal`, then run `author preview`, show - its literal tree and warnings, obtain confirmation for its exact hash, and run `author write`. - The deterministic generator writes executable source; follow the agreed source-only or plugin - delivery route and name the proof it has not established. The complete `AuthorOptions.plan` is an - advanced compatibility route. +## Discover only missing project facts -- **You are inventing the structure** → do not write HTML. Emit an intent tree (JSON - describing which blocks and how they nest) and pipe it to - `npx -y block-runner@latest assemble - --json`. Deterministic code builds the markup, so it - cannot come out invalid. This is the best path and the one to reach for by default. -- **You have authored source HTML** → `npx -y block-runner@latest convert - --json`. The only - path that carries CSS; use it when the styling matters (`--styling relaxed` is the default). - Its result is page `post_content`, not a reusable source package. -- **You have block markup to check** → `validate` → `fix` → `validate`. Never save markup that - is still invalid after `fix`. +For a component that belongs in an existing project, use [GUIDE.md §0](references/GUIDE.md) after +the artifact route is clear. Reuse established facts and inspect only the relevant source and site +context needed for this change. Existing-plugin integration needs inspection; a self-contained +paragraph repair does not. Use relevant facts to recommend reuse, supported generation or a +developer handoff. Recognizing a route does not add generator support. Ask only for choices that +the request and repository do not answer; use structured questions if your harness supports them, +otherwise ask in plain language. ## Generator boundary and continuation