Ask a general-purpose coding agent for a landing page and you get back the internet’s average. A hero with a gradient somewhere between purple and blue, because that is the most common gradient there is. A pricing table with three cards and a “Most Popular” badge on the middle one, because that is the most common pricing table there is. Headings in Inter, because Inter is what an agent reaches for when nothing tells it otherwise. None of it is wrong exactly. It is just generic, and it rarely matches the brand it was supposed to represent, because the agent had no brand to read from, only a blank editor and its own defaults.

Brndle, the free WordPress block theme this blog runs on, ships a different answer to the same prompt: a Claude Code skill, invoked as /brndle-pages, that generates a landing page by choosing from a closed set of native Gutenberg blocks and a closed set of design tokens, instead of writing HTML and CSS from scratch. This post is a technical walkthrough of that architecture, what we could confirm from the theme’s own repository, what the REST API and the block registration pattern actually do, and where the line sits between documented fact and reasonable inference from how the rest of the theme is built.

In this guide

  • Why an agent writing raw HTML defaults to generic
  • What is actually confirmed about the /brndle-pages integration
  • The block catalog an agent chooses from, and how it is registered
  • Design tokens as guardrails: 12 color schemes, 8 font pairs, two filters
  • A walkthrough, labeled honestly as illustrative, from brief to published page
  • Where this still needs a human
  • Questions people ask

We covered the general version of this idea, for any theme or framework, in A Design System an AI Agent Can Follow: tokens an agent can read, rules it can check, theme.json as a contract, and a page gate. This post is the specific case. Brndle does not ask an agent to follow written rules about colour and spacing and hope it complies. It gives the agent a smaller surface to choose from in the first place, so there is less to drift away from.

Why does an AI-generated landing page default to generic?

Because writing a page from scratch is an open-ended task, and an agent fills every gap in an open-ended task with whatever is statistically common across the pages it learned from. Asked for “a SaaS landing page,” there is no brand file to consult unless one is handed over, so the model reaches for the median SaaS landing page: dark hero, light-on-dark gradient, three-tier pricing, a testimonial carousel. It is not a failure of the model. It is what happens when the task is “write arbitrary markup” and nothing constrains the vocabulary.

The fix our design-system post describes for that general case is to write tokens and rules down and hope the agent reads and follows them. That works, but it depends on the agent reading the rules file, interpreting it correctly, and not drifting the next time a rule is ambiguous. A narrower fix is to not let the agent write markup at all. If the only way to add a pricing section is to emit a brndle/pricing block with a plans array, there is no markup for the agent to invent a layout in. The constraint is structural, not advisory.

What is actually confirmed about the Claude Code integration?

We read the public GitHub repository at github.com/brndle-themes/brndle rather than take the feature on faith, and we are going to be specific about what that reading turned up, because the honest version of this story is more useful than a smoothed-over one.

The repository root carries a CLAUDE.md file and a .claude/ directory, the same pattern this blog’s own posts describe for giving a coding agent project-specific instructions before it writes anything. Inside that directory sits a skill file, .claude/skills/brndle-pages.md, invoked from the theme directory in Claude Code with the slash command /brndle-pages. The repository’s own documentation states plainly what the skill is for: generating “complete landing pages from a text description,” using the theme’s native blocks rather than hand-written markup.

A second file backs the skill up: docs/AI-USAGE-GUIDE.md, described in the repo as covering “all 18 blocks (full attribute reference + decision trees), the REST settings API, page templates, and complete worked examples for landing pages and blog posts.” We read it. It is a real reference document, not marketing copy: a block-by-block attribute schema, a table mapping content needs to block choices, a worked JSON example for a full landing page, a REST curl example against the settings endpoint, and a pre-publish checklist with items like “empty title, code, quote, or items cause silent render failure.”

What we want to be precise about: this is a documented interface contract, not a captured transcript. We did not find, and are not claiming to have seen, a literal log of a Claude Code session running /brndle-pages against a live site. What is confirmed is the skill file exists, the reference guide it points to exists and is substantive, and the block and REST surfaces it documents are the same ones registered in the theme’s own PHP. The walkthrough later in this post is built from that documented contract and labeled as illustrative for exactly this reason.

The block catalog an agent chooses from

Brndle ships 18 custom blocks in total, split into two registers that the documentation says not to mix inside the same content area. Fourteen are the marketing register, built for full-width landing-page sections:

BlockWhat it renders
brndle/heroAbove-fold section: eyebrow, title, subtitle, primary/secondary CTA, optional logos
brndle/statsA row of key metrics, each a value/label pair
brndle/featuresAlternating text-and-image feature rows
brndle/content-image-splitA single feature, side by side with an image
brndle/how-it-worksA numbered step process
brndle/comparison-tableA feature comparison grid
brndle/pricingA multi-plan pricing table with one plan markable as featured
brndle/testimonialsCustomer cards: avatar, quote, role
brndle/teamTeam member cards
brndle/logosA trust/client logo strip
brndle/video-embedA YouTube or Vimeo embed with a poster image
brndle/faqAn accordion FAQ that emits FAQPage JSON-LD schema
brndle/ctaA closing call-to-action banner
brndle/lead-formName/email/message capture with REST submission

The remaining four are an editorial register, meant for long-form articles mixed with core paragraph and heading blocks rather than full-width marketing sections: brndle/code (syntax-highlighted, with a copy button and line numbers), brndle/pull-quote (three variants), brndle/timeline (dated milestones) and brndle/tabs-accordion (one block, two display modes). The usage guide is explicit that tabs-accordion in accordion mode is not a substitute for faq when you need the schema markup: “Emits FAQPage schema” is a property of one specific block, not of accordion-shaped content in general.

All 18 blocks are described as server-side rendered and built for WordPress 6.9 and up at apiVersion: 3. That matters for what an agent is actually doing: it is not generating a client-side component tree. It is producing an attributes object that a PHP render callback turns into HTML on the server, the same way any other block in a block theme works.

How does an attribute object become rendered HTML?

This is the part of the architecture we could verify directly against source, and it is the mechanism that makes the guardrail real rather than cosmetic. Block registration in Brndle runs through a single class, BlockServiceProvider, in the Brndle\Providers namespace. It holds a list of block slugs and loops over it, calling WordPress’s own register_block_type() against each block’s block.json file. Nothing about that is unusual for a block theme; it is the standard registration pattern.

The part worth paying attention to is the shared render_callback. For every block in the list, rendering goes through the same path: apply any attribute migrations for older content, resolve a Blade view by naming convention (blocks.hero for the hero block, for instance, loaded from resources/views/blocks/), and hand the view the parsed attributes. The view decides the actual markup, the actual classes, the actual structure. An agent supplying a JSON attributes object for brndle/hero is choosing a title, a subtitle, a variant, a CTA label and URL, values that fill named slots in a template someone already designed and styled. It cannot, through that interface, add a new element, change a margin, or introduce a colour the view was not built to render. The constraint is enforced by the same code path that renders every other hero section on every other page, which is a different guarantee than “the agent was told not to.”

We want to flag the boundary of what we verified here plainly: we confirmed the class name, the loop over a block list, the call to register_block_type(), and the shared Blade-based render callback with its fallback to raw content when the view function is unavailable. We did not audit every individual Blade view in resources/views/blocks/ for correctness, so “the template was built correctly” is doing some of the work in that paragraph, and it is a claim about the theme’s authors, not one we independently re-verified line by line.

Design tokens as guardrails

The block catalog controls structure. A separate, smaller surface controls appearance: Brndle’s settings, read and written through a REST endpoint at brndle/v1/settings (GET/POST/DELETE), persisted in wp_options under the key brndle_settings. The documented settings an agent or a script can set include a colour scheme, a font pair, a header style, a footer style, and dark-mode behaviour:

curl -X POST 'https://example.com/wp-json/brndle/v1/settings' \
  -u 'user:app-password' \
  -H 'Content-Type: application/json' \
  -d '{"color_scheme":"midnight","header_style":"glass"}'

The colour scheme field is confirmed to accept one of twelve named values: sapphire, indigo, cobalt, trust, commerce, signal, coral, aubergine, midnight, stone, carbon, neutral. The font pair field accepts one of eight: system, inter, geist, plex, dm-sans, editorial, magazine, humanist. Header style has eight documented options and footer style has six. None of these is a free-text field. An agent setting the site’s identity is picking a name from an enumerated list, the same way it picks a block type from the 18 available.

Two filters extend the closed set for a developer who wants a thirteenth colour scheme or a ninth font pair: brndle/color_presets and brndle/font_pairs. That they exist as named, documented filter hooks is itself informative about the architecture, the set is closed by default and intentionally extensible by a developer writing PHP, not something an agent calling the settings endpoint can widen on its own. An agent generating a page is working inside whatever set the site owner’s PHP has defined, which is exactly the “theme.json as the contract” idea from our design-system post, applied here to a REST-exposed settings object instead of a theme.json file an agent reads directly.

This is the mechanical reason the “design system as guardrails” framing holds up better here than the general advisory version. In the general case, a rule like “never a raw hex value outside the palette file” is a sentence a script can check after the fact, and our own audit of our sites when we wrote that post found violations of our own rule. Here, there is no code path for an agent to write a raw hex value into a page at all, the only colour-setting surface is a REST field that validates against twelve names. An agent cannot drift the accent colour one shade darker by accident, because “one shade darker” is not a value the field accepts. It is a narrower piece of the overall problem, colour and type, not spacing, not copy, not layout judgement, but for the piece it covers, it is a closed system rather than a policed one.

It is worth being equally direct about what this does not guarantee. A closed set of twelve colour schemes keeps an agent from inventing an off-brand hex value; it does not by itself prove every scheme passes contrast requirements in every combination, and it does not touch markup-level accessibility concerns like heading order, alt text, or focus rings, which live in the Blade views, not in the settings schema. We wrote a full WCAG 2.2 checklist for block theme authors, including the specific failure modes we found in our own themes, in Is Your Block Theme Really Accessible?, and the same caution applies here: a closed design-token system is a strong guardrail against palette and spacing drift, and it is a floor, not a certificate.

A walkthrough: from a one-line brief to a page

We do not have a transcript of an actual Claude Code session running /brndle-pages against a live install, so we are not going to present one as if we did. What follows is built directly from the documented decision tree and the worked example in docs/AI-USAGE-GUIDE.md, walked through as an illustration of how the pieces fit together rather than a recording of a real run.

Say the brief given to the agent is: “Landing page for a project-management tool aimed at agencies. Two plans, $19/mo solo and $49/mo agency. Needs social proof and an FAQ.” The usage guide documents a standard section order for building a landing page this way:

hero → logos → stats → features → how-it-works → pricing → testimonials → comparison-table → team → video → faq → lead-form → cta

Not every section is mandatory for every brief; the agent is choosing a subset and an order from that documented flow, not filling all thirteen slots every time. For this brief, a reasonable subset is hero, stats, features, pricing, testimonials, faq, cta. Each block gets an attributes object, in the shape the guide documents. The hero and pricing blocks, for example, adapted from the pattern in the guide’s own worked example:

<!-- wp:brndle/hero {
  "eyebrow": "FOR AGENCIES",
  "title": "Ship client projects without the status-call",
  "subtitle": "One board per client. Billing and updates included.",
  "cta_primary": "Start free",
  "cta_primary_url": "/signup",
  "variant": "dark"
} /-->

<!-- wp:brndle/pricing {
  "plans": [
    {
      "name": "Solo",
      "price": "$19",
      "period": "/mo",
      "features": ["1 workspace", "Email support"],
      "featured": false
    },
    {
      "name": "Agency",
      "price": "$49",
      "period": "/mo",
      "features": ["Unlimited workspaces", "Priority support"],
      "featured": true,
      "badge": "MOST POPULAR"
    }
  ]
} /-->

Block markup is standard WordPress comment-delimited HTML, so it can be written to a file and created as a page through WP-CLI, exactly as the guide documents:

wp post create landing.html \
  --post_type=page \
  --post_title="Agency Landing Page" \
  --post_status=publish \
  --meta_input='{"_wp_page_template":"template-landing.php"}'

Before that page goes live, the documented pre-publish checklist asks the agent to confirm, among other things: every required attribute is filled (an empty title, items, code or quote causes a silent render failure, not an error), the block JSON parses, the page template is set, and the page has been checked on both desktop and mobile. If the brief also called for a specific look, the agent sets it once through the settings endpoint, {"color_scheme": "trust", "font_pair": "inter"}, say, and every block on every page picks the tokens up, because the blocks read from the same settings object rather than carrying colour values of their own.

Where this still needs a human

A closed catalog of blocks and a closed set of tokens removes a specific category of mistake, off-brand colours, invented layouts, fonts nobody loaded. It does not remove the rest of the job.

  • Whether the page order makes sense for this audience. The documented flow is a reasonable default, not a guarantee that a comparison table belongs on every page, or that logos should come before or after stats for a given brief.
  • Whether the copy is true. Nothing in the block schema checks whether “$19/mo” is the actual current price, or whether a testimonial quote is real. An agent filling a testimonials block’s attributes with plausible-sounding text is a fabrication risk the architecture does nothing to prevent.
  • Silent failures from thin content. The guide’s own warning is specific: an empty required attribute does not throw an error, it renders nothing. A rushed brief that leaves items empty on a faq block ships a blank section nobody flagged.
  • Register mixing. The “don’t mix marketing and editorial blocks in the same content well” rule and the “FAQPage schema belongs only to brndle/faq, never to tabs-accordion” rule are both things the documentation tells an agent to follow. Nothing in the block registration mechanism stops a differently-prompted agent from ignoring either one; they are conventions in the skill file, not hard constraints in the renderer.
  • Real browser verification. A page that validates against the JSON schema and passes the pre-publish checklist on paper still needs to be opened at 390px and checked for the things only a browser shows: overflow, contrast in the chosen colour scheme, focus order. The token system narrows what could go wrong here; it does not test it for you.
  • Judgement a closed catalog cannot encode. Whether this brief actually needed a comparison table, whether the hero’s eyebrow text is doing anything, whether seven sections is too many for this product, those are calls a person who has looked at enough landing pages makes, not calls a schema validates.

Questions people ask

Does this feature require Claude Code specifically, or does it work with other AI agents?

The documented skill and slash command, /brndle-pages, are built for Claude Code. But the mechanism underneath, standard WordPress block markup, a REST settings endpoint, and WP-CLI page creation, is not Claude-specific. Any agent or script that can write block-comment HTML and call a REST endpoint or WP-CLI can use the same surfaces; it just would not have the pre-written skill file guiding it through the decision tree and attribute reference unless that content were fed to it separately.

Can the agent invent a colour outside the twelve schemes?

Not through the documented settings endpoint, which validates the color_scheme field against the named list. A developer can extend the list itself with the brndle/color_presets filter, but that is a PHP-level change to what the set contains, not something the agent does by passing an arbitrary value at request time.

What happens if the agent submits invalid block JSON or a missing required attribute?

Per the usage guide, a missing required attribute like title, code, quote or items causes a silent render failure, the section renders nothing rather than throwing a visible error. That is why the documented pre-publish checklist exists as a separate step: it is explicitly a check a human or a follow-up automated pass needs to run, because the render path does not surface the problem on its own.

Is the generated page portable, or locked into Brndle?

It is standard Gutenberg block markup stored in wp_posts.post_content, the same storage format any WordPress block theme uses. Deactivate Brndle and the blocks that are Brndle-specific (brndle/hero, brndle/pricing, and so on) will not render without the theme or a compatible block library registered, in the same way any theme-registered block stops rendering without its theme. The content and the attribute data survive; the visual output depends on the theme that registers the blocks, which is the normal tradeoff of using theme-level custom blocks rather than only core blocks.

Does the FAQ block actually help SEO, or is that marketing language?

The documented behaviour is specific and checkable: brndle/faq emits FAQPage JSON-LD schema, which is the structured data format Google’s documentation associates with FAQ rich results eligibility. Whether a given page actually earns a rich result depends on Google’s own ranking and eligibility systems, which are outside anything the theme controls; the theme’s part is emitting valid schema, not guaranteeing the result.

Do I need Composer or npm installed on the live site to use this?

No. Brndle is built on Sage, Acorn, Blade and Tailwind v4, which is a Composer- and npm-driven development stack, but the documented release process produces a distributable ZIP with the build already compiled, so a client site runs the theme without needing either toolchain installed. The /brndle-pages skill and the REST/WP-CLI paths operate against the already-built theme, not against its source build pipeline.

Does this replace hiring a designer?

For the narrow job of “assemble a page from on-brand, pre-styled sections without drifting off the palette,” largely yes, in the same way a page builder with a locked design system replaces some of that work. It does not replace the judgement calls listed above: whether the page structure fits the product, whether the copy is accurate, whether the overall narrative is convincing. Those remain a person’s job whether the first draft came from an agent or from a blank editor.

How is this different from asking a general chatbot to “write me landing page HTML”?

A general chatbot writing raw HTML and CSS is solving an open-ended problem with no enforced vocabulary, which is exactly the failure mode described at the top of this post: generic gradients, invented spacing, whatever font the model reaches for. The /brndle-pages skill narrows the task to selecting from 18 registered blocks and a closed settings schema. The difference is not that one approach is “smarter” than the other. It is that one has a closed set of valid outputs enforced by the rendering code, and the other does not.

Does the page update if I change the colour scheme later?

Based on the confirmed architecture, blocks render server-side through views that read from the shared settings object rather than storing colour values in each block’s own attributes, changing color_scheme through the REST endpoint should restyle every page built from these blocks without touching their stored content, the same way changing a theme.json palette restyles a block theme without editing individual pages. We note this is inference from the architecture’s documented structure rather than something we tested against a live before/after page ourselves.

The takeaway

The interesting part of Brndle’s Claude Code integration is not that an agent can generate a landing page, plenty of tools do that. It is what the agent is and is not allowed to generate. Eighteen registered blocks, rendered through one shared callback that resolves a Blade view per block, and a settings schema with twelve named colours and eight named font pairs: that is a small enough surface that an agent cannot drift outside the brand even if it wanted to, because the renderer has nowhere to put an off-palette value. It is the same idea as a design system an AI agent can follow, with the enforcement moved from a rules file an agent has to read and obey into the registration and rendering code itself. What is left for a person to do is exactly the part no schema can check: whether the page is telling the truth, and whether it is the right page to build at all.