WordPress’s Abilities API is core’s interface for agents: a registry of named capabilities, each with a schema, exposed over REST. Pattern Builder registers twenty-six of them — nineteen for the site itself, and seven that reach patternbuilderwp.com through the account the WordPress user connected — so any agent that can sign in to your site can read its design system, list its blocks and patterns, store finished markup, add the tokens, block styles, images and fonts that markup depends on, and browse, install and upload collections, with no bespoke integration on either side.
The abilities
| Ability | Method | What it does |
|---|---|---|
pattern-builder/get-design-system | GET | Palette, gradients, spacing, font sizes and families, layout widths and style variations, resolved across core, the parent theme, the child theme and the active variation. An agent stops parsing theme.json and guessing. |
pattern-builder/list-block-types | GET | Every block registered on this site, with attribute schemas. Optional namespace filter. Anything not listed parses to core/missing. |
pattern-builder/list-patterns | GET | The site’s patterns without their markup. Optional source: theme, user or all. |
pattern-builder/get-pattern | GET | One pattern with its markup. id is a namespaced name or a user pattern’s post ID. |
pattern-builder/render-pattern | GET | The front-end HTML a stored pattern produces. |
pattern-builder/get-authoring-guide | GET | The pattern-authoring documentation as Markdown: an index with no input, one guide by name, or all. |
pattern-builder/get-validator | GET | The source of the markup validator, as files to write and run with Node. |
pattern-builder/get-editor-scripts | GET | This site’s own block editor script URLs in load order, for the validator. |
pattern-builder/create-pattern | POST | Store finished markup as a new pattern. title and content required; source is theme (default) or user; also name, description, categories, keywords, synced, viewportWidth. |
pattern-builder/update-pattern | POST | Replace an existing pattern’s markup. id and content required. |
pattern-builder/find-media | GET | The images already on this site that a pattern could point at, and — in the same answer — the route and a runnable curl line for adding a new one. |
pattern-builder/list-fonts | GET | The font families available to install. Naming a family describes that one: its weights, its styles, and whether it has a variable face. |
pattern-builder/add-design-tokens | POST | Add colours, gradients, font sizes, font families or spacing steps. destination is the theme’s theme.json or Global Styles. Existing tokens are never overwritten. |
pattern-builder/set-global-styles | POST | Set the styles a pattern inherits — the root, the elements, the blocks. This one replaces, because there is only one of each. |
pattern-builder/add-block-style-variation | POST | Register a named look as a theme style file, optionally with a small amount of checked literal CSS. |
pattern-builder/set-layout | POST | contentSize, wideSize and whether full-width blocks escape the root padding — what every constrained band measures itself against. |
pattern-builder/add-asset | POST | Store an image: SVG markup the agent wrote, or a URL for the site to fetch. Answers with the reference to put in the markup. |
pattern-builder/add-placeholder-image | POST | Draw a plain SVG placeholder locally, so a pattern never points at somebody else’s placeholder service. |
pattern-builder/add-font | POST | Install a self-hosted typeface from the font collection, and write the preset that actually makes it render. |
Two things are deliberately absent. Nothing takes a prompt. No ability turns a description into a pattern; the judgement lives in whichever agent is calling, and the writes take markup that agent has already composed. And nothing validates for you, because block validity is decided by re-running a block’s save function, which is JavaScript, and no server can do that. What the site can do is hand the agent the tool and its own block code, which is what the last two reads are for.
Writing the design system, not just the markup
An agent that can only write markup writes bad markup. Told to use a colour the theme does not define, it inlines a hex — which opts the pattern out of your palette, your dark mode and every future restyle. So four of the writes exist to let it establish the design first, in the order that actually works: the layout widths, then the tokens, then the styles, then the block style variations. A pattern that references a preset which does not exist yet renders as no styling at all, and nothing anywhere says so.
They behave differently on purpose. Adding a token is additive and inert, so a name you already use is skipped and yours wins. Setting a global style replaces, because there is only one link colour on a site and it paints every page. A variation is a third thing again: a named look applied with a class, scoped to the blocks that carry it, which is what lets an agent describe a second kind of button without freezing one into the markup.
Images and fonts
A pattern is markup plus the files it points at, and the files were the half an agent could not supply — so it invented URLs that 404, or pointed at a public placeholder service, meaning every visitor to your site fetched an image from somebody else’s server. find-media, add-asset, add-placeholder-image and add-font close that. Every one answers with the reference to put in the markup, because the right string is not guessable: a theme pattern composes its image URLs at render time, and a hard-coded one breaks the moment the theme moves.
Uploading actual image bytes is deliberately not an ability. Abilities are JSON in and JSON out, so a photograph would have to be base64 inside that JSON — which means the agent reading the file into its own context and paying for it. Instead there is one ordinary upload route that takes the raw bytes, and find-media hands the agent a ready-made curl line for it, so a file moves from disk to your site without passing through the agent at all.
The cloud abilities
Seven more abilities reach patternbuilderwp.com, and every one of them uses the connection the WordPress user made on the Pattern Builder screen: an agent never holds a cloud credential, and without a connection each refuses with pattern_builder_not_connected. Reads are GET, writes POST.
| Ability | Method | What it does |
|---|---|---|
list-collections | GET | The directory’s public and premium collections (scope=community, searchable), or the account’s own, Personal first (scope=mine). |
get-collection | GET | One collection with its pattern summaries, each marked whether it is already installed on this site. |
search-cloud-patterns | GET | Search public patterns; each names its collection, and collection=owner/slug narrows to one. |
install-collection | POST | Every pattern of a collection, as theme or user patterns, with the missing design tokens added; already-installed patterns skipped, failures reported, per-pattern results returned. |
install-cloud-pattern | POST | One pattern, the same way. |
upload-pattern | POST | A local pattern, or finished markup, into a collection (Personal by default). |
create-collection | POST | A private collection. On a free account the service refuses with an upgrade message, since collections of your own are a Pro feature; an agent never publishes. |
No ability makes a collection public, changes a visibility, or deletes a collection. Those stay with the account holder, in Pattern Builder. Collections explains the model.
Connecting an agent
1. Create an application password
Abilities are permission-gated, so calls need to authenticate. Application Passwords, built into WordPress, are the usual way: in wp-admin go to Users → Profile → Application Passwords, name one for the agent, and copy the password it generates. With WP-CLI:
wp user application-password create <login> pattern-author --porcelain
WordPress offers application passwords only over HTTPS, or on a site whose WP_ENVIRONMENT_TYPE is local. On a plain-HTTP development site, set that constant in wp-config.php (or in a wp-env project’s config block); development is not enough.
2. Call an ability
Every ability runs at /wp-json/wp-abilities/v1/abilities/{name}/run. Two conventions are easy to get wrong. Input goes under an input key, as nested query parameters on a GET and as a JSON wrapper on a POST. And the method is fixed per ability: reads are GET and writes are POST, and the other way round is refused.
# A read
curl -u "$WP_USER:$WP_APP_PASSWORD" -G
--data-urlencode 'input[id]=my-theme/hero'
"$WP_URL/wp-json/wp-abilities/v1/abilities/pattern-builder/get-pattern/run"
# A write
curl -u "$WP_USER:$WP_APP_PASSWORD" -X POST -H 'Content-Type: application/json'
--data '{"input":{"title":"Hero","content":"<!-- wp:group -->…<!-- /wp:group -->"}}'
"$WP_URL/wp-json/wp-abilities/v1/abilities/pattern-builder/create-pattern/run"
Sites without pretty permalinks use /?rest_route=/wp-abilities/v1/… instead. GET /wp-json/wp-abilities/v1/abilities lists what the authenticated user may run, each with its input and output schema, which is the place an agent should start.
3. Or reach them as tools
Because these are ordinary registrations in core’s registry, anything that bridges the Abilities API to another protocol gets them for free. An MCP server that exposes a site’s abilities as tools (the WordPress MCP Adapter, for instance) makes each of the ten a tool the agent can call by name, with the same permissions and the same schemas. There is no Pattern Builder-specific server to install, and none is planned; that is the point of registering abilities rather than inventing an API.
Teaching the agent to write patterns
Pattern Builder ships a pattern-authoring guide that tells an agent how to do the job well: orient on the theme’s design tokens before writing, pick the right kind of pattern, use preset slugs rather than values, mark up content slots correctly, and validate before storing anything. The same text ships in two forms:
- As a skill. The plugin’s
guides/pattern-authordirectory is a Claude Code skill (the repository’s.claude/skills/pattern-authorlinks to it). Copy or symlink it into your own project’s skills directory and an agent working in the theme’s files picks it up when a task involves a pattern. - Over the wire.
get-authoring-guidereturns the same Markdown, so an agent whose harness has no notion of a skill can be handed the documentation from the site it is working on. The index it returns also carries avalidateentry naming the two abilities below, so an agent that asks what to read is told the one step it cannot skip.
A theme can add its own house rules to what the site serves: which blocks this build has settled on, the copy voice, why a section is composed the way it is. That is a filter, and it deals in text rather than file paths, so a guide added this way needs no filesystem access:
add_filter( 'pattern_builder_authoring_guides', function ( $guides ) {
$guides['house-rules'] = array(
'title' => 'House rules for this theme',
'content' => "# House rulesnnSections are full width…",
);
// Or amend one that ships:
$guides['block-vocabulary']['content'] .= "nnCore blocks only on this site.";
return $guides;
} );
Validating before storing
Hand-written block markup is invalid far more often than it looks. It renders perfectly on the front end and breaks only when someone opens the editor, which says “This block contains unexpected or invalid content” and offers to discard it. WordPress decides validity by re-running each block’s save function, so the check has to run in JavaScript, and it should run against the block library the destination site actually has, since versions disagree about what current markup looks like.
An agent with the plugin’s files runs the bundled validator directly. It finds the WordPress install it lives in and loads that install’s own editor scripts, so nothing is downloaded and the answer comes from the right version:
npm i --no-save jsdom
node guides/pattern-author/scripts/validate-pattern.mjs path/to/pattern.php
An agent that only reaches the site over HTTP gets the same check from two abilities. get-validator hands over the script itself, and get-editor-scripts the site’s block editor script URLs in load order. The second exists because WordPress serves those files to anyone but not the order they load in, and the order is not forgiving:
# The tool. Write each file it returns into one directory.
curl -u "$WP_USER:$WP_APP_PASSWORD"
"$WP_URL/wp-json/wp-abilities/v1/abilities/pattern-builder/get-validator/run"
# This site's own block code, in load order.
curl -u "$WP_USER:$WP_APP_PASSWORD"
"$WP_URL/wp-json/wp-abilities/v1/abilities/pattern-builder/get-editor-scripts/run"
> scripts.json
npm i --no-save jsdom
node validate-pattern.mjs --scripts scripts.json pattern.html
The validator reports three things. Invalid means no version of the block ever wrote markup like this. Old form means the markup matches a deprecated save: the editor opens it and migrates it, but the file is missing what the block writes today, usually a block-supports class, so a style silently does not apply. Dropped attribute means that migration threw away something the agent wrote. The last two are the dangerous ones, because nothing else anywhere reports them. The scripts are cached by URL, versions included, so an upgraded site is fetched afresh. Node and jsdom are the one requirement no server can lift.
render-pattern is a useful second look once a pattern is stored: it shows the HTML the visitor gets, which is where a missing supports class becomes visible.
Requirements
The Abilities API is newer than Pattern Builder’s WordPress 6.8 floor. On a WordPress that has it, the abilities register automatically and appear in the registry; on one that does not, nothing registers and the plugin’s own REST routes under pattern-builder/v1 remain the interface. Agents authenticate as a WordPress user and can do exactly what that user can do, so give an agent a user with the capabilities it needs and no more.
