BEM Blocks for AI Agents
Vision
Split the layout authoring workflow into two distinct phases:
- Design phase — AI agent creates or selects BEM blocks (components with HTML + CSS + JS)
- Assembly phase — AI agent composes a page from existing blocks without reading their source
The block registry is the bridge. An agent composing a page only needs the block catalog:
name, parameters, description. It never needs to read the block implementation.
Block Registry
layoutloader already builds a block registry at load time via blockFinder:
Layouts.Blocks.ByName map[string]model.LayoutBlock
Layouts.Blocks.ByFullName map[string]model.LayoutBlock // sourceID#blockName
Each model.LayoutBlock carries:
Name— BEM block name (hero,button,card)Params— typed parameters with defaults and descriptions (viaarg_typedirective)SourceID— which layout file defines this blockHasContent— whether the block accepts{{yield content}}
This is enough for an agent to compose a page. Example agent prompt:
Available blocks: hero(title, subtitle), button(label, variant="primary"), card(title, body)
Build a landing page with a hero, three cards, and a CTA button.
The agent outputs a JSON layout or a Jet template using only block names and params.
JSON Layouts
docs/dev/json_layouts.md describes the existing JSON layout format that lets you compose
pages from blocks without writing HTML:
{
"blocks": [
{ "name": "hero", "params": { "title": "Welcome", "subtitle": "..." } },
{ "name": "card", "params": { "title": "Feature 1", "body": "..." } }
]
}
This is already the agent-friendly interface. The agent does not need to know HTML.
Inline CSS/JS (defer_block)
Each BEM block optionally declares its CSS and JS. The layoutloader extracts this at parse
time. flush_blocks "style" and flush_blocks "js" emit the collected assets once per page.
This means the agent can compose pages from blocks and get correct CSS/JS automatically —
it never has to think about asset management.
Name Collision Warnings
Since blocks are global across all imported layout files, the registry warns at load time
when two files define a block with the same name:
NoteWarning: block "hero" defined in both layout/hero.html and layout/alt-hero.html
The last definition wins (consistent with ByName last-wins semantics). The warning lets
the agent or template author know to rename one of them.
Workflow
Design phase (agent creates blocks)
Agent input: "Create a hero block with title, subtitle, CTA button, and background image"
Agent output: layout/hero.html (HTML structure + inline CSS + inline JS)
The agent writes a self-contained BEM block file. The block is immediately available in the
registry after the layout is reloaded.
Assembly phase (agent composes pages)
Agent input: block catalog + "Build a SaaS landing page"
Agent output: JSON layout or Jet template referencing existing blocks
The agent picks blocks from the catalog, supplies parameters, and produces a composition.
No HTML knowledge required. No CSS/JS knowledge required.
API Exposure
To make the block catalog available to agents, the GraphQL API should expose:
type LayoutBlock {
name: String!
sourceID: String!
params: [LayoutBlockParam!]!
hasContent: Boolean!
staticCSS: String # extracted at load time if CSS is static
staticJS: String
}
type Query {
layoutBlocks(siteID: ID!): [LayoutBlock!]!
}
An agent queries layoutBlocks once per site, caches the result, and uses it for all
subsequent assembly tasks.
Relation to JSON Layouts
JSON layouts (docs/dev/json_layouts.md) are already designed for programmatic composition.
HTML-based Jet templates with {{yield blockName(params...)}} calls are more flexible but
require knowledge of Jet syntax.
For agents, JSON layouts are the preferred interface — declarative, schema-validated,
no template syntax. HTML templates are better for human authors who want fine-grained
layout control.
Both formats use the same block registry. An agent can start with JSON layouts and graduate
to HTML templates as its capabilities grow.
Summary
| Phase | Who | Interface | Output |
|---|---|---|---|
| Design | Agent / human | File editor | layout/block-name.html |
| Assembly | Agent | Block catalog API | JSON layout or Jet template |
| Render | trip2g | Jet template engine | HTML page with deduped CSS/JS |