From cbb47165bc2ec660076314bc358b66872a11be62 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 23 Apr 2026 14:19:41 +0100 Subject: [PATCH 1/4] apps/cli: two-phase AI build workflow with blockify skill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restructures the AI agent's site-build flow into explicit phases and adds a user-invokable skill for HTML → Gutenberg block conversion, measured against a sequence of full-build sessions to validate each change. Phase 1 — HTML prototype. The agent writes plain HTML/CSS/JS under `/tmp/prototype/` with a section-anchor skeleton, then fills one anchor per Edit. Design tokens are locked in a `tokens` anchor before any section fill. Theme writes are forbidden in this phase so the design is screenshot-approved before block markup enters the picture. Phase 2 — Port to block theme. The agent invokes the new `blockify` skill (apps/cli/ai/plugin/skills/blockify/SKILL.md) as a gate before writing block markup. The theme stylesheet is `cp`-ed from the prototype and adjusted via small Edits for block-DOM selectors (`.wp-block-button`, `.wp-block-image`), replacing a prior 60–90s silent regeneration. Page content is built in `/tmp/page-.html` and applied via `wp_cli eval '... file_get_contents(ABSPATH . "tmp/page-.html") ...'` — the prior `--post_content-file=` pattern silently failed because wp_cli runs in a WASM filesystem that cannot see host paths. Working cadence is split into content creation (one tool per turn to avoid silent generation cliffs) and fix-up loops (multiple Edits per turn when validate_blocks or take_screenshot report multiple issues). The validate_blocks tool description is updated in lockstep so it no longer instructs the agent to validate after every individual Edit. `maxTurns` default is raised to 100 to give headroom for the added section-by-section turns without truncating builds. --- apps/cli/ai/agent.ts | 2 +- apps/cli/ai/plugin/skills/blockify/SKILL.md | 175 ++++++++++++++++++++ apps/cli/ai/system-prompt.ts | 116 ++++++++----- 3 files changed, 249 insertions(+), 44 deletions(-) create mode 100644 apps/cli/ai/plugin/skills/blockify/SKILL.md diff --git a/apps/cli/ai/agent.ts b/apps/cli/ai/agent.ts index 329f697a58..5c803a932c 100644 --- a/apps/cli/ai/agent.ts +++ b/apps/cli/ai/agent.ts @@ -55,7 +55,7 @@ export function startAiAgent( config: AiAgentConfig ): Query { prompt, env, model = DEFAULT_MODEL, - maxTurns = 50, + maxTurns = 100, resume, autoApprove, activeSite, diff --git a/apps/cli/ai/plugin/skills/blockify/SKILL.md b/apps/cli/ai/plugin/skills/blockify/SKILL.md new file mode 100644 index 0000000000..01f00c5e68 --- /dev/null +++ b/apps/cli/ai/plugin/skills/blockify/SKILL.md @@ -0,0 +1,175 @@ +--- +name: blockify +description: Convert HTML content to native Gutenberg block markup. Invoke this any time you need to translate raw HTML (a section, a full page, a file on disk, a snippet in the conversation) into valid block markup. Works on any input — not scoped to a site, a post, or a theme. +user-invokable: true +--- + +# Blockify — HTML to Gutenberg blocks + +Convert HTML input into native Gutenberg block markup. The goal is **FAITHFUL CONVERSION**: reproduce the same DOM using native blocks, preserve every className, and only fall back to `core/html` for truly non-convertible elements. + +## Input and output + +- **Input**: any HTML — a single section, a full page, a file you `Read`, a snippet the user pasted, the `post_content` of an existing post fetched via `wp_cli post get`. This skill does not care where the HTML came from. +- **Output**: valid Gutenberg block markup that renders the same visual DOM. Return it inline in your response, write it to a file with `Write`/`Edit`, or apply it with `wp_cli post update` — whichever the caller asked for. +- **Out of scope**: this skill does NOT modify CSS, theme files, or site content by default. It is a pure HTML → block markup transformation. If the caller wants the result applied somewhere, they invoke the appropriate tool after receiving the output. + +## Decompose — do not give up on a section + +Never wrap an entire section in `core/html` just because some of its children are non-convertible. Break sections apart: convert every convertible child to a native block and isolate only the truly non-convertible child as its own `core/html` block. + +Example: a hero `
` with a heading, paragraph, buttons, image, AND a scroll-indicator animation becomes `core/group` > `core/heading` + `core/paragraph` + `core/buttons` + `core/image` + `core/html` (scroll indicator only). Do NOT keep the entire hero as `core/html`. + +## Translation table + +| HTML | Gutenberg block | +|------|----------------| +| `
`, `
`, `
`, `