Write abilities
The 33 write abilities change documents, design, media, content and settings on the site, subject to permissions and OAuth scopes.
On this page
01Overview
Write abilities are the operations that an AI agent, the local CLI or an administrator use to change the site. Each ability has a name, an input and output schema, annotations, an execution and a WordPress capability check.
Nucleo registers them with the WordPress Abilities API, in the nucleo category, with show_in_rest: true. Each ability checks the OAuth scope and, for writes, applies the rate limit. Pro abilities are registered only with a Pro license.
Document abilities follow the same procedure: validation, quality check, compilation and revision.
To connect a client or to set up OAuth, see the guide Connect an AI agent. Read-only abilities are in the chapter Read abilities.
02Common mechanisms
Registration and edition
What it does: registers the abilities on the initialization hook. It skips the ones that are not available and, without a Pro license, the Pro ones. It registers only lowercase names that are not registered yet.
How to use: registration is automatic on the wp_abilities_api_init hook. The MCP tool name is the ability name with / replaced by -: nucleo/doc-create becomes nucleo-doc-create. From WP-CLI the nucleo/ prefix is optional.
# runs an ability from the command line
wp nucleo ability run <name> --input='<JSON>'Parameters: none.
Permissions: see Permissions and scope.
Edition: the Pro abilities are doc-translate, assets-audit, css-purge, kit-apply, css-optimize, css-optimize-apply and css-optimize-off. All the others are Free.
Without a Pro license, the Pro abilities are not registered.
Known limits: if the input has no required fields, the schema receives default: [].
Permissions and scope
What it does: the permission check first verifies the WordPress capability of the ability. Then, if the request has an OAuth token, it verifies the scope required by the ability.
The check verifies the WordPress capability of the ability.
With an OAuth token, it verifies the scope required by the ability.
Without a token, as from a wp-admin session or from WP-CLI, only the capability applies.
How to use: a missing scope returns a WP_Error insufficient_scope with status 403 and the required scope in the data. The MCP server checks the scope before running the ability and responds with insufficient_scope: requires scope ... and isError: true.
Parameters: none.
Permissions: the scopes for writes are nucleo:write, nucleo:publish, nucleo:design and nucleo:admin. Each scope maps to a reference capability: edit_posts, publish_pages, edit_theme_options and manage_options. The effective capability is the one shown in each section.
Edition: Free
Known limits: the base scope depends on the ability name. The nucleo:publish requirement depends on the input and on the post status, as the warning explains.
With an OAuth token and publish: true at the first level of the input, nucleo/doc-create, nucleo/doc-patch, nucleo/doc-texts-set and nucleo/doc-translate also require the nucleo:publish scope, in addition to their own. The check applies to every ability whose input publishes, that is with publish: true or with a status publish, future or private at the first level. nucleo/doc-create with postId, nucleo/doc-patch, nucleo/doc-texts-set, nucleo/doc-rollback, nucleo/layout-conditions-set and nucleo/fields-set also require nucleo:publish when postId points to a published, scheduled or private post: the edit goes online at once. Without the scope the call responds insufficient_scope.
Rate limit
What it does: each ability with readonly other than true counts one call in a fixed 60-second window. The key is the current user and the scope group of the ability. All 33 abilities in this chapter have readonly: false.
How to use: beyond the limit, the ability does not run and returns this error.
{"ok": false, "error": {"code": "rate_limited", "message": "...", "retryAfter": 60}}Parameters: filter nucleo/rate_limit, default 60 calls per window.
Permissions: not applicable.
Edition: Free
Known limits: the counter is atomic. The limit applies to REST, MCP and WP-CLI, because it is checked when the ability runs. nucleo/doc-translate calls nucleo/doc-texts-set internally, but it counts as one call.
Result format
What it does: abilities return an object with ok and, on error, error with code and message. Some shape checks return a WP_Error instead, usually with code invalid_input. The MCP server turns the WP_Error into isError: true with the text <code>: <message>.
How to use: document abilities return {ok, postId, revision, errors, quality, error?}. The quality field contains score (seo, a11y, perf), blocking and issues. The document error codes are invalid_document, quality_blocking, conflict, not_found, exists, patch_failed and write_failed.
Parameters: none.
Permissions: not applicable.
Edition: Free
Known limits: nucleo/kit-apply and nucleo/site-import return a report without the ok key. The MCP server treats only ok: false as an error.
Acknowledgements (acknowledge)
What it does: a list of accepted blocking quality issues. Each entry is {rule, node, reason}, with three required strings. The document merges new acknowledgements with the ones already saved.
How to use: in nucleo/doc-create, nucleo/doc-patch and nucleo/doc-publish. In nucleo/site-import it is an object that maps the file path to a list, with a non-empty reason.
Parameters: see the individual abilities.
Permissions: those of the ability.
Edition: Free
Known limits: the blocking check applies with publish: true and on every save of a post that is already published. An invalid shape returns invalid_input.
03Summary
| Ability | Scope | Capability | Edition | dryRun | readonly / destructive / idempotent |
|---|---|---|---|---|---|
nucleo/doc-create | nucleo:write | edit_pages/edit_posts, edit_theme_options for layouts and sections | Free | yes | false / false / false |
nucleo/doc-patch | nucleo:write | edit_post (+ publish_post) | Free | yes | false / false / false |
nucleo/doc-publish | nucleo:publish | publish_post | Free | no | false / false / false |
nucleo/doc-rollback | nucleo:write | edit_post | Free | no | false / true / false |
nucleo/doc-texts-set | nucleo:write | edit_post (+ publish_post) | Free | no | false / false / false |
nucleo/doc-translate | nucleo:write | edit_post (+ publish_post) | Pro | no | false / false / false |
nucleo/tokens-set | nucleo:design | edit_theme_options | Free | no | false / false / true |
nucleo/fonts-import | nucleo:design | edit_theme_options | Free | no | false / false / true |
nucleo/icons-set | nucleo:admin | manage_options | Free | no | false / false / true |
nucleo/media-import | nucleo:write | upload_files | Free | no | false / false / false |
nucleo/media-upload | nucleo:write | upload_files | Free | no | false / false / false |
nucleo/media-formats | nucleo:write | upload_files | Free | no | false / false / true |
nucleo/menu-set | nucleo:design | edit_theme_options | Free | no | false / true / false |
nucleo/site-options-set | nucleo:admin | manage_options | Free | no | false / false / true |
nucleo/settings-set | nucleo:admin | manage_options | Free | no | false / false / true |
nucleo/content-upsert | nucleo:write | edit_posts | Free | yes | false / true / false |
nucleo/terms-set | nucleo:write | manage_terms of the taxonomy | Free | yes | false / false / true |
nucleo/model-set | nucleo:design | manage_options | Free (Pro parts) | yes | false / false / true |
nucleo/fields-set | nucleo:write | edit_post / edit_term | Free | no | false / false / true |
nucleo/layout-conditions-set | nucleo:design | edit_post | Free | no | false / false / true |
nucleo/assets-audit | nucleo:design | manage_options | Pro | no | false / false / true |
nucleo/assets-rules-set | nucleo:design | manage_options | Free | no | false / false / true |
nucleo/css-purge | nucleo:design | manage_options | Pro | no | false / false / true |
nucleo/critical-set | nucleo:design | edit_theme_options | Free | no | false / false / true |
nucleo/critical-request | nucleo:design | edit_theme_options | Free | no | false / false / false |
nucleo/css-optimize | nucleo:design | manage_options | Pro | no | false / false / true |
nucleo/css-optimize-apply | nucleo:design | manage_options | Pro | no | false / false / false |
nucleo/css-optimize-off | nucleo:design | manage_options | Pro | no | false / true / true |
nucleo/kit-apply | nucleo:design | edit_theme_options | Pro | yes | false / false / true |
nucleo/site-import | nucleo:admin | manage_options | Free | yes | false / false / true |
nucleo/cache-rebuild | nucleo:admin | manage_options | Free | no | false / false / true |
nucleo/gap-report | nucleo:write | edit_pages | Free | no | false / false / false |
nucleo/component-activate | nucleo:admin | activate_plugins | Free | no | false / false / true |
No write ability produces a visual preview. The signed preview URL comes from nucleo/doc-preview, described in the chapter Read abilities.
04Documents
nucleo/doc-create
What it does: creates a page, a post, a layout or a section from a Nucleo document. With postId it attaches the first Nucleo document to an existing content item. Quality is checked on the page composed with the site layouts (header, footer, single or product), also for a new content item.
How to use: MCP tool nucleo-doc-create. Example: {"title": "Contacts", "document": {...}, "publish": false}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
document | object | compact or full document | — | Required. |
title | string | 1–200 characters | — | Required without postId. |
slug | string | ^[a-z0-9]+(?:-[a-z0-9]+)*$ | wp.slug or meta.slug of the document, then the title | Slug of the new content, also for drafts. If it is already used, WordPress adds a suffix and the output has a warning in warnings. |
postId | integer | ≥ 1 | — | Existing content without a Nucleo document. Type, title and status stay those of the post. |
postType | string | page, post, nucleo_layout, nucleo_section | from the document kind | Ignored with postId. Without postType: layout and popup create a nucleo_layout, section a nucleo_section, any other kind a page. page and post refuse the kinds layout, popup and section. |
publish | boolean | — | false | Ignored with postId. |
dryRun | boolean | — | false | Validates and computes the quality without saving. |
acknowledge | array | entries {rule, node, reason} | — | See Acknowledgements. |
No other property is allowed (additionalProperties: false).
Output: {ok, postId, revision, slug, warnings?, errors, quality, error?}. slug is the one the content received, absent with dryRun. With dryRun and no postId, it returns postId: 0 and revision: 0. Codes: invalid_input (WP_Error), invalid_document (with errors), quality_blocking (with quality) and write_failed. With postId, not_found and exists are also possible, when the content already has a document.
Permissions: with an existing postId, edit_post on that post; with a missing postId, edit_posts. For nucleo_layout and nucleo_section, edit_theme_options. For post, edit_posts, plus publish_posts with publish: true. For page, edit_pages, plus publish_pages with publish: true. Scope nucleo:write; with postId on a published content item, the scope nucleo:publish is also needed.
Annotations: readonly false, destructive false, idempotent false.
Dry-run: yes (dryRun).
Edition: Free
Known limits: for nucleo_layout the document kind must be layout or popup. For nucleo_section it must be section. With postId the kind must be page or absent. If root.children is empty and the post has text, the text becomes at most 200 nc/text blocks (paragraphs, headings, list items). Images and other elements are lost; the original stays in the _nucleo_wp_content meta. A document with "bind" is compiled a second time after creation. Each call writes an entry to the audit log.
nucleo/doc-patch
What it does: applies a list of operations to an existing document, in order and atomically. It checks that baseRevision is the current revision.
How to use: MCP tool nucleo-doc-patch. Example: {"postId": 12, "baseRevision": 3, "ops": [{"op": "set", "id": "h1", "path": "content.text", "value": "About us"}]}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
postId | integer | ≥ 1 | — | Required. |
baseRevision | integer | ≥ 0 | — | Required. Revision read before the change. |
ops | array of object | operations below | — | Required. |
publish | boolean | — | false | |
dryRun | boolean | — | false | |
acknowledge | array | entries {rule, node, reason} | — |
Semantic operations, by node id:
op | Fields | Effect |
|---|---|---|
set | id, path (keys separated by dots), value | Writes the value into the node. value: null removes the key. It cannot touch id or children. |
insert | parent, node, index? | Inserts a subtree among the children of parent. Each node has an id (^[a-z0-9]{1,12}$) and a type. The ids must be new. Without index it goes at the end. |
move | id, parent, index? (without from) | Moves a node under another parent. It cannot move into itself or into a descendant. |
remove | id (without path) | Removes a node. |
duplicate | id | Copies the node right after the original. The new ids are <id>c<n> (max 12 characters) or a base36 hash. |
wrap | ids (non-empty list, without duplicates), with (type required, id optional) | Wraps sibling nodes in a new container, at the position of the first one. |
JSON Patch operations (RFC 6902, pointers RFC 6901): add, replace, test, copy (from, path), move with from and remove with path. test fails if the value differs or the path is missing.
Output: {ok, postId, revision, errors, quality, error?}. Codes: invalid_input (WP_Error), not_found, conflict (revision changed), patch_failed, invalid_document, quality_blocking and write_failed. patch_failed reports the index of the operation in the message (Operation N: ...).
Permissions: edit_post on postId. With publish: true, publish_post is also required. Scope nucleo:write.
Annotations: readonly false, destructive false, idempotent false.
Dry-run: yes (dryRun).
Edition: Free
Known limits: no operation on the document root. The internal patch error code (invalid_op, forbidden, not_found, conflict) does not appear as error.code: it always appears as patch_failed. A post without a Nucleo document gives patch_failed. On a published post the blocking check applies even without publish.
nucleo/doc-publish
What it does: publishes the current document. It saves it again with publish: true on the current revision.
How to use: MCP tool nucleo-doc-publish. Example: {"postId": 12}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
postId | integer | ≥ 1 | — | Required. |
acknowledge | array | entries {rule, node, reason} | — |
Output: {ok, postId, revision, errors, quality, error?}. Codes: invalid_input (WP_Error), not_found, quality_blocking, invalid_document, write_failed and conflict.
Permissions: publish_post on postId. Scope nucleo:publish.
Annotations: readonly false, destructive false, idempotent false.
Dry-run: no.
Edition: Free
Known limits: each successful call creates a new revision.
nucleo/doc-rollback
What it does: restores an earlier revision. The restore creates a new revision, so the history is kept.
How to use: MCP tool nucleo-doc-rollback. The revision number comes from nucleo/doc-revisions, described in the chapter Read abilities.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
postId | integer | ≥ 1 | — | Required. |
revision | integer | ≥ 1 | — | Required. |
Output: {ok, postId, revision, errors, quality, error?}. Codes: invalid_input (WP_Error) and not_found (document or revision), plus those of the save.
Permissions: edit_post on postId. Scope nucleo:write.
Annotations: readonly false, destructive true, idempotent false.
Dry-run: no.
Edition: Free
Known limits: it does not accept acknowledge. On a published post, a blocking issue not covered by the saved acknowledgements gives quality_blocking.
nucleo/doc-texts-set
What it does: rewrites the texts of a document in bulk. The structure and the other fields do not change.
How to use: MCP tool nucleo-doc-texts-set. The id and path values come from nucleo/doc-texts, described in the chapter Read abilities.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
postId | integer | ≥ 1 | — | Required. |
baseRevision | integer | ≥ 0 | — | Required. |
texts | array | entries {id, path, text}, with non-empty id and path | — | Required. No other key in the entry. |
publish | boolean | — | false |
Output: {ok, postId, revision, errors, quality, error?}. Codes: invalid_input (WP_Error), not_found, invalid_path (field not translatable or node missing), plus those of nucleo/doc-patch.
Permissions: edit_post on postId. With publish: true, publish_post is also required. Scope nucleo:write.
Annotations: readonly false, destructive false, idempotent false.
Dry-run: no.
Edition: Free
Known limits: it accepts only the paths that nucleo/doc-texts exposes. Each text becomes a set operation of nucleo/doc-patch. If a path is not allowed, it writes nothing.
nucleo/doc-translate
What it does: copies a document into a new post of the same type, applies the translated texts and links the translation to the source through the multilingual plugin. Language and link are set on the draft copy, before the texts and the publication. If a translation in that language already exists, it returns it with existing: true and creates or changes nothing: update its texts with nucleo/doc-texts-set. If the texts are not applied, the copy is deleted.
How to use: MCP tool nucleo-doc-translate. Example: {"postId": 12, "lang": "en", "title": "About us", "texts": [...]}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
postId | integer | ≥ 1 | — | Required. Source document. |
lang | string | 2–5 characters, ^[a-z-]{2,5}$ case-insensitive | — | Required. Saved in lowercase. |
title | string | at least 1 non-empty character | title of the source | The slug comes from the title. |
texts | array | entries {id, path, text} | — | Required. As in nucleo/doc-texts-set. |
publish | boolean | — | false |
Output: {ok, postId, existing?, error?}. Codes: invalid_input (WP_Error), not_found, create_failed, unknown_language (language not configured in the multilingual plugin) and same_language (the source is already in that language), plus the codes of nucleo/doc-create and nucleo/doc-texts-set.
Permissions: edit_post on the source. With publish: true, publish_post on the source is also required. Scope nucleo:write.
Annotations: readonly false, destructive false, idempotent false.
Dry-run: no.
Edition: Pro
Known limits: if the texts do not apply, the copy is deleted and the response is an error, so a retry does not find a half-done translation. With existing: true the translation was already there: nothing is created or changed. The link to the translation group happens only if the source has a language in the multilingual plugin. After linking it fires the action nucleo/translation_created ($newId, $sourceId, $lang).
05Design tokens, fonts and icons
nucleo/tokens-set
What it does: changes the design tokens and republishes the token CSS.
How to use: MCP tool nucleo-tokens-set. Example: {"tokens": {"color": {"primary": "#1d4ed8"}, "space": {"20": 6}}}. The full rules are in the chapter Design tokens.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
tokens | object | groups color, space, text, font, radius, shadow, container | — | Required. Only the values to change. |
Output: {ok, tokens, contrast} with the full set of tokens after the change and contrast, the list of contrast problems that the new tokens cause in published documents (rule, postId, node). Codes: invalid_input (WP_Error, if tokens is not an object) and invalid_tokens (invalid value or group).
Permissions: edit_theme_options. Scope nucleo:design.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no.
Edition: Free
Known limits: the values merge with the saved ones, group by group and key by key. null removes the key. A group sent as a non-object value replaces the whole group. New keys are lowercase, with digits and -, at most 48 per group. space and text are in rem, text as [minRem, maxRem], container in whole px.
nucleo/fonts-import
What it does: downloads a Google Fonts family locally, as woff2 files in the uploads library, and makes it available to the tokens. It replaces the same family if already imported.
How to use: MCP tool nucleo-fonts-import. Example: {"family": "Inter", "weights": [400, 700]}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
family | string | letters and digits, single spaces | — | Required. |
weights | array of integer | multiples of 100 from 100 to 900, from 1 to 9 entries | — | Required. |
italic | boolean | — | false | Downloads the italic variants instead of the normal ones. |
Output: {ok, faces: [{family, weight, style, url}]}. Codes: invalid_input (WP_Error), invalid_family, invalid_weights, uploads_unavailable, font_format, font_host_rejected, font_network, font_too_large and font_write.
Permissions: edit_theme_options. Scope nucleo:design.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no.
Edition: Free
Known limits: each font file is at most 2 MB. It accepts only the allowed font hosts and subsets. The file path on the server does not appear in the response.
nucleo/icons-set
What it does: adds, replaces or removes the site icons for nc/icon. The other icons stay.
How to use: MCP tool nucleo-icons-set. Example: {"set": {"phone": "<svg viewBox=\"0 0 24 24\">...</svg>"}, "remove": ["old"]}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
set | object | name → SVG markup | — | Name ^[a-z][a-z0-9-]{0,40}$. |
remove | array of string | names of site icons | — |
Output: {ok, icons, builtin}, that is the names of the site icons after the change and the names of the built-in icons. Code: invalid_input.
Permissions: manage_options. Scope nucleo:admin.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no.
Edition: Free
Known limits: at most 300 icons, 20000 bytes each. The SVG must have a viewBox and at least one element. Only the elements svg, g, path, circle, ellipse, rect, line, polyline and polygon remain. Colors become currentColor. The name of a built-in icon (for example phone) replaces it everywhere, including in nc/menu and nc/list.
06Media
nucleo/media-import
What it does: downloads a public image from an https URL and adds it to the media library, with alternative text.
How to use: MCP tool nucleo-media-import. Example: {"url": "https://example.com/photo.jpg", "alt": "Shop front"}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
url | string | https URL to a public host | — | Required. |
alt | string | — | — | Required. Empty string for decorative images. |
title | string | — | — | Media title. |
Output: {ok, id, url, width, height}. Codes: invalid_input (WP_Error), invalid_url, download_failed (network, HTTP other than 200, empty file or over 10 MB, failed save) and unsupported_type.
Permissions: upload_files. Scope nucleo:write.
Annotations: readonly false, destructive false, idempotent false.
Dry-run: no.
Edition: Free
Known limits: timeout of 15 seconds. Allowed types: jpeg, png, webp, gif and avif, checked on the actual content. It does not detect duplicates: each call creates an attachment.
nucleo/media-upload
What it does: uploads to the media library an image sent as base64, with alternative text. If it finds an identical file already uploaded, it returns it without uploading it again.
How to use: MCP tool nucleo-media-upload. Example: {"file": "logo.png", "data": "<base64>", "alt": "Logo"}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
file | string | file name with extension, at least 1 character | — | Required. The saved extension comes from the actual type. |
data | string | base64, at least 1 character | — | Required. |
alt | string | — | "" | |
title | string | — | — |
Output: {ok, id, url, width, height, file, sha1, existing}. Codes: invalid_input (WP_Error), invalid_data (invalid or empty base64), unsupported_type and download_failed (over 10 MB or failed save).
Permissions: upload_files. Scope nucleo:write.
Annotations: readonly false, destructive false, idempotent false.
Dry-run: no.
Edition: Free
Known limits: a duplicate is recognized by the SHA-1 and by the original file name, including with suffix -1, -2. Allowed types: jpeg, png, webp, gif and avif.
nucleo/media-formats
What it does: generates the modern formats (avif, webp) enabled in the site options, for images already uploaded, originals and intermediate sizes.
How to use: MCP tool nucleo-media-formats. Example: {"missing": true, "limit": 50}. The formats are enabled with imageFormats of nucleo/site-options-set.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
ids | array of integer | ≥ 1, max 50 entries | — | Image attachments only. Others are skipped. |
missing | boolean | — | false | Only images without generated formats. |
limit | integer | 1–50 | 20 | Applies only without ids. |
Output: {ok, done: [{id, formats}], enabled, supported, remaining}. remaining counts the image attachments still without formats. Code: formats_disabled (no format enabled).
Permissions: upload_files. Scope nucleo:write.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no.
Edition: Free
Known limits: without ids it works in ID order. supported lists the formats that the server image editor can write.
08Content and terms
nucleo/content-upsert
What it does: creates or updates content items by type and slug. It moves items with status: "trash" to the trash. An item with errors writes nothing, while the others continue.
How to use: MCP tool nucleo-content-upsert. The item format is in the chapter Dynamic data.
Parameters:
| Name | Type | Allowed values | Default | Notes | ||
|---|---|---|---|---|---|---|
items | array of object | 1–100 entries | — | Required. Partial write: a missing key stays as it is. | ||
items[].type | string | allowed content type | — | Required. | ||
items[].slug | string | — | — | Required. | ||
items[].title | string | — | — | Required on creation. | ||
items[].status | string | draft, publish, private, future, pending, trash | draft on creation | |||
items[].date | string | local time Y-m-d\TH:i:s or Y-m-d | — | |||
items[].excerpt | string | — | — | |||
items[].body | string | HTML | — | Filtered with wp_kses_post without unfiltered_html. | ||
items[].featuredImage | string \ | integer \ | null | media:<file>, attachment ID, null | — | |
items[].terms | object | taxonomy → list of slugs | — | |||
items[].fields | object | field values, with symbolic references | — | |||
items[].parent | string \ | null | slug of an item of the same type | — | Hierarchical types only. | |
items[].menuOrder | integer | — | — | |||
dryRun | boolean | — | false | Reports the planned actions without writing. | ||
items[].base | string | hash read from nucleo/content-list with full | — | If the item changed on the site after it was read, error conflict and nothing is written. | ||
media | object | file name → URL | — | From the CLI manifest. | ||
pending | array of string | symbols that the push will create | — | Only with dryRun. |
With status: "trash" the item goes to the trash. With a token without the nucleo:publish scope, the trash, the publication and the change of an item already published, private or scheduled return forbidden.
Output: {ok, created, updated, unchanged, trashed, results, errors}. ok is true if errors is empty. results contains {index, slug, action, id, hash}, with action created, updated, unchanged or trashed. An item identical to the saved one is not written: unchanged, and post_modified stays as it is; hash is the new base, absent with dryRun. errors contains {index, slug, type, path, code, message}. Codes per item: conflict, invalid_input, unknown_field, required, unknown_type, invalid_value, duplicate, ambiguous_slug, slug_conflict, forbidden, managed_by_document, not_found, protected, unknown_taxonomy and error, plus those of the fields. General error invalid_input with 0 or more than 100 items.
Permissions: edit_posts. Per item: edit_posts for the type, edit_post on the existing item, publish_posts for the type with publish, future and private, delete_post for trash, assign_terms for each taxonomy. Scope nucleo:write.
Annotations: readonly false, destructive true, idempotent false.
Dry-run: yes (dryRun).
Edition: Free
Known limits: body of an item with a Nucleo document gives managed_by_document. The system's protected pages are not moved to the trash (protected).
nucleo/terms-set
What it does: creates or updates the terms of a taxonomy by slug, in a partial way. It does not delete terms.
How to use: MCP tool nucleo-terms-set. Example: {"taxonomy": "area", "terms": [{"slug": "nutrition", "name": "Nutrition"}]}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
taxonomy | string | taxonomy slug | — | Required. |
terms | array of object | max 500 entries: slug, name (required on creation), description, parent (slug), fields | — | Required. |
dryRun | boolean | — | false | Planned action and id null. |
terms[].base | string | hash read from nucleo/terms-get | — | If the term changed on the site after it was read, error conflict and the term is not written. |
media | object | file name → URL | — | |
pending | array of string | symbols (term:<taxonomy>/<slug>, media:<file>) | — | Used with dryRun. |
Output: {ok, created, updated, unchanged, results, errors}. results contains {index, slug, action, id, hash}, with action created, updated or unchanged (term identical to the saved one, not written). Codes per term: conflict, invalid_input, duplicate, unknown_taxonomy, invalid_value, required, not_found, forbidden and error, plus those of the fields. General error invalid_input.
Permissions: manage_terms of the taxonomy. Per term: edit_terms on creation, edit_term on the existing term. Scope nucleo:write.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: yes (dryRun).
Edition: Free
Known limits: a term with errors writes nothing, while the others continue. A taxonomy that does not exist does not pass the permission check.
09Content model and fields
nucleo/model-set
What it does: saves the content model, that is types, taxonomies and field groups. It validates and computes the diff before writing.
How to use: MCP tool nucleo-model-set. The format is in the chapter Dynamic data.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
model | object | {schema: 1, postTypes, taxonomies, fieldGroups} | — | Required. A key sent replaces the whole list. A missing key stays as saved. |
dryRun | boolean | — | false | Returns the diff without saving. |
confirm | array of string | ids of destructive changes, for example field:dettagli/prezzo | [] |
Output: {ok, diff, kept}. kept lists the parts that were not sent. Errors: {ok: false, errors} with the validation errors, {ok: false, error: {code: "destructive"}, diff} for unconfirmed destructive changes, and invalid_input.
Permissions: manage_options. Scope nucleo:design.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: yes (dryRun).
Edition: Free, with Pro parts.
Known limits: type slugs of at most 20 characters, taxonomy slugs of at most 32. WordPress slugs and types registered by other plugins or by the theme return reserved_slug. A repeater cannot contain another repeater. If types or taxonomies change, the site registers them again and flushes the rewrite rules. The destructive annotation is false even when, with confirm, the call removes types or fields.
nucleo/fields-set
What it does: saves the field values of a content item or a term, in a partial way. An empty value clears the field.
How to use: MCP tool nucleo-fields-set. Example: {"postId": 34, "values": {"price": 120}}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
postId | integer | — | — | Only one of postId and termId. |
termId | integer | — | — | |
values | object | field key → value. Repeaters are lists of rows. | — | Required. |
base | string | hash read from nucleo/fields-get | — | If the values changed after they were read, error conflict and nothing is written. |
Output: {ok, hash?, errors?}, with hash the new base after saving, and errors {code, path, message}, for example unknown_field, required, invalid_value, too_many and too_few. General codes: invalid_input, conflict and not_found, when no type or taxonomy with fields exists for that ID.
Permissions: edit_post on postId or edit_term on termId. Without one of them, or with both, the permission is denied. Scope nucleo:write.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no.
Edition: Free
Known limits: it checks each value before writing. It writes only the fields of the Nucleo model, not those of other plugins.
10Layout
nucleo/layout-conditions-set
What it does: replaces the include, exclude and priority conditions of a layout. The rest of the document does not change. The save rebuilds the layout map.
How to use: MCP tool nucleo-layout-conditions-set. Example: {"postId": 7, "conditions": {"include": [{"type": "post_type", "value": "product"}]}}. The condition types are in the chapter Compiler and runtime.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
postId | integer | ≥ 1 | — | Required. nucleo_layout post. |
conditions.include | array of object | conditions {type, ...} | — | Required. |
conditions.exclude | array of object | conditions | [] | |
conditions.priority | integer | — | 0 | |
baseRevision | integer | ≥ 0 | — | Optional. If present, it must match the current revision. |
Output: {ok, postId, revision, errors, quality, error?}. Codes: invalid_input (WP_Error), not_found, not_layout, conflict and invalid_document. Invalid conditions are in errors with code layout_condition.
Permissions: edit_post on postId. Scope nucleo:design; on a published layout the scope nucleo:publish is also needed.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no.
Edition: Free
Known limits: the post must be a nucleo_layout with kind layout or popup. The post status does not change.
11Assets, CSS and critical CSS
The operation of rules, audit, reduction and critical CSS is described in the chapter Optimizer and assets.
nucleo/assets-audit
What it does: plans the audit of the assets loaded by the sample templates of the site. Each template is a background job. It replaces the previous plan.
How to use: MCP tool nucleo-assets-audit. The report is read with nucleo/assets-report, described in the chapter Read abilities.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
templates | array of string | ^[a-z0-9_-]{1,40}$, max 20 entries | all |
Output: {ok, jobs}. Codes: invalid_input (WP_Error) and no_templates.
Permissions: manage_options. Scope nucleo:design.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no.
Edition: Pro
Known limits: the jobs start with a single cron event.
nucleo/assets-rules-set
What it does: replaces the user asset rules (dequeue, defer, replace) and republishes the rule table.
How to use: MCP tool nucleo-assets-rules-set. Example: {"rules": [{"action": "dequeue", "handle": "contact-form-7", "templates": ["page"]}]}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
rules | array | rules {action, handle, templates, ...} | — | Required. List. |
Output: {ok, count, warnings}, where warnings is a list of warning texts. Code: invalid_input (WP_Error).
Permissions: manage_options. Scope nucleo:design.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no.
Edition: Free
Known limits: invalid rules are ignored at compile time, but they stay saved. count is the number of rules sent, not the number of valid rules.
nucleo/css-purge
What it does: reduces the third-party CSS for a template type, using a sample page of the site. It returns the sizes before and after and the URL of the variant.
How to use: MCP tool nucleo-css-purge. Example: {"template": "page", "handles": [{"handle": "elementor-frontend", "src": "https://..."}]}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
template | string | ^[a-z0-9][a-z0-9-]*$ | — | Required. |
handles | array of object | {handle, src}. handle ^[A-Za-z0-9_][A-Za-z0-9_.-]*$, src non-empty | — | Required. |
Output: {ok, results: [{handle, before, after, url}]}. Codes: invalid_input (WP_Error), dir_unwritable, write_failed and sample_unreachable.
Permissions: manage_options. Scope nucleo:design.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no.
Edition: Pro
Known limits: the reduction runs in the same request, not in the background.
nucleo/critical-set
What it does: saves the critical CSS of a template.
How to use: MCP tool nucleo-critical-set. It is called by the CLI or by the external service after nucleo/critical-request.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
template | string | non-empty, for example home, page, single, product | — | Required. |
css | string | — | — | Required. |
Output: {ok, bytes}. Codes: invalid_input and invalid_critical_css (both WP_Error).
Permissions: edit_theme_options. Scope nucleo:design.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no.
Edition: Free
Known limits: it removes </style from the CSS. The maximum is 51200 bytes (50 KB) after cleaning.
nucleo/critical-request
What it does: asks an external service to compute the critical CSS of the templates. The result comes back through nucleo/critical-set.
How to use: MCP tool nucleo-critical-request. The service URL and key are set with nucleo/settings-set, group service.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
templates | array of string | 1 to 64 characters each, at least one entry | home, page, single, product, archive, search, 404 |
Output: {ok, job}. Codes (WP_Error): invalid_input, service_not_configured, service_unreachable and service_error.
Permissions: edit_theme_options. Scope nucleo:design.
Annotations: readonly false, destructive false, idempotent false.
Dry-run: no.
Edition: Free
Known limits: it requires an https service URL and a key, set in the Nucleo settings.
nucleo/css-optimize
What it does: computes a CSS optimization candidate for a template type, from the DOM measured in the browser: third-party sheets reduced and critical CSS of the first screen. It does not publish the candidate.
How to use: MCP tool nucleo-css-optimize. The candidate is published with nucleo/css-optimize-apply.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
template | string | ^[a-z0-9][a-z0-9-]*$ | — | Required. |
samples | array of object | 1–10 entries | — | Required. |
samples[].url | string | URL on the same host as the site | — | Required. |
samples[].viewport | string | desktop, mobile | — | Required. |
samples[].html | string | page HTML, non-empty, max 3 MB | — | Required. |
samples[].fold | string | HTML of the first screen, max 3 MB, may be empty | — | Required. |
classes | array of string | max 2000 entries, max 200 characters each | [] | Classes seen after loading, kept by the reduction. |
Output: {ok, candidate: {sheets, before, after, critical: {bytes, error}, samples, classes}}. Codes: invalid_input (WP_Error), no_stylesheets, dir_unwritable and write_failed.
Permissions: manage_options. Scope nucleo:design.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no. The candidate itself is an unpublished preview.
Edition: Pro
Known limits: a sample on another host invalidates the whole request.
nucleo/css-optimize-apply
What it does: publishes the parts of the candidate that passed the check in the browser: reduced sheets and critical CSS. It removes the candidate and returns the saved status entry.
How to use: MCP tool nucleo-css-optimize-apply. Example: {"template": "page", "candidateId": "<id from nucleo/css-optimize>", "purge": true, "critical": false, "check": {"elements": 812, "diffs": []}}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
template | string | ^[a-z0-9][a-z0-9-]*$ | — | Required. |
purge | boolean | — | — | Required. Publishes the reduced sheets. |
critical | boolean | — | — | Required. Publishes the critical CSS. |
check.elements | integer | ≥ 0 | 0 | |
check.diffs | array of object | — | [] | At most 20 are kept. |
candidateId | string | 40 hexadecimal characters | — | Required. The id returned by nucleo/css-optimize. |
Output: {ok, status}. Codes: invalid_input (WP_Error), no_candidate (run nucleo/css-optimize first), candidate_changed (the saved candidate is another one), candidate_stale (the site changed after the measurement: a saved document, the rebuild queue or the tokens; run nucleo/css-optimize again), critical_too_big (critical CSS over the limit) and the other codes of CssOptimizeState::apply().
Permissions: manage_options. Scope nucleo:design.
Annotations: readonly false, destructive false, idempotent false.
Dry-run: no.
Edition: Pro
Known limits: without a saved candidate it returns no_candidate. Critical CSS over 50 KB returns critical_too_big.
nucleo/css-optimize-off
What it does: turns off the CSS optimization of a template type. It removes reduced sheets and critical CSS. The status entry stays, with status off.
How to use: MCP tool nucleo-css-optimize-off. Example: {"template": "page"}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
template | string | ^[a-z0-9][a-z0-9-]*$ | — | Required. |
Output: {ok}. Code: invalid_input (WP_Error).
Permissions: manage_options. Scope nucleo:design.
Annotations: readonly false, destructive true, idempotent true.
Dry-run: no.
Edition: Pro
Known limits: none.
12Kit
nucleo/kit-apply
What it does: applies a starter kit with the same import used for sites: it creates or updates tokens, sections, pages and layouts.
How to use: MCP tool nucleo-kit-apply. The kits are listed with nucleo/kit-list, described in the chapter Read abilities. Details are in the chapter Kit.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
kit | string | ^[a-z0-9-]+$ | — | Required. Kit ID. |
dryRun | boolean | — | false | Counts without writing. |
Output: import report: {created, updated, unchanged, errors, warnings, ids, base, tokensBase}, without ok. Codes (WP_Error): invalid_input, kit_unknown and requires_missing (with missing in the data).
Permissions: edit_theme_options. Scope nucleo:design.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: yes (dryRun).
Edition: Pro
Known limits: the only recognized requirement is woocommerce. An unknown requirement is never met. If the site shows the posts on the home page and the kit has page:home, that page becomes the home page.
13Import and export
nucleo/site-import
What it does: imports the files produced by nucleo/site-export. It creates or updates, by slug, tokens, sections, pages, posts, layouts, rules, media, menus and site settings (title, tagline, homepage, language). Quality is checked on the page composed with the site layouts, also for new pages. Pages and posts are imported before layouts, because layout conditions refer to them (page:<slug>).
How to use: MCP tool nucleo-site-import. The local CLI uses it for nucleo push. Details are in the chapter Import, export and sync.
Parameters:
| Name | Type | Allowed values | Default | Notes | |
|---|---|---|---|---|---|
files | object | relative path → JSON content (string) | — | Required. | |
dryRun | boolean | — | false | Validates each document as a real import, with schema and blocking issues, without writing. | |
force | boolean \ | array of string | true or file paths | false | Imports even what changed on the site after the export. site.json applies to tokens and settings. |
pending | array of string | symbols, for example evento:congresso, page:servizi/consulenza, term:area/nutrizione | [] | Only with dryRun: items that the same push creates first. | |
acknowledge | object | file path → list {rule, node, reason}, non-empty strings | — | Blocking issues accepted by a person. |
Output: {created, updated, unchanged, errors, warnings, ids, base, tokensBase}, without ok. Each entry of errors contains {file, message, code, guide}, with code among error, conflict, duplicate, not_json, invalid_document and quality_blocking. General code: invalid_input (WP_Error).
Permissions: manage_options. Scope nucleo:admin.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: yes (dryRun).
Edition: Free
Known limits: an internal error code not in the list becomes error, with the original code in the message. base and tokensBase are the new fingerprints to write into site.json.
14Cache
nucleo/cache-rebuild
What it does: recompiles the given documents or all of them, without new revisions. It republishes from the token database, asset rules, layouts and the content model.
How to use: MCP tool nucleo-cache-rebuild. It is needed when nucleo/site-describe reports the Nucleo cache as empty.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
postIds | array of integer | ≥ 1, max 200 entries | all documents |
Output: {ok, rebuilt, queued, republished}. republished is false if another rebuild holds the lock. Code: invalid_input (WP_Error).
Permissions: manage_options. Scope nucleo:admin.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no.
Edition: Free
Known limits: it rebuilds at most 20 documents right away. The rest goes to the queue. A document that cannot be rebuilt (invalid, or with blocking quality issues on a published post) keeps its previous output: see nucleo/status, fields stale and failed. Without postIds it considers only page, post, nucleo_layout and nucleo_section with the _nucleo_doc meta.
15Gap report
nucleo/gap-report
What it does: records something the design asks for and Nucleo cannot do, with the workaround used. The same pair of block and need increments a counter.
How to use: MCP tool nucleo-gap-report. The reports are read with nucleo/gap-list, described in the chapter Read abilities.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
need | string | 1–500 characters | — | Required. |
block | string | Nucleo block name, for example nc/section-ref | — | |
workaround | string | max 1000 characters | — | |
page | string | max 200 characters | — |
Output: {ok, count}. Code: invalid_input.
Permissions: edit_pages. Scope nucleo:write.
Annotations: readonly false, destructive false, idempotent false.
Dry-run: no.
Edition: Free
Known limits: it keeps at most 200 reports. The oldest ones are discarded.
16Components
nucleo/component-activate
What it does: activates a Nucleo components plugin already present on disk. It installs nothing and receives no code.
How to use: MCP tool nucleo-component-activate. Example: {"plugin": "workshop-components"}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
plugin | string | ^[a-z0-9][a-z0-9-]{0,60}$ | — | Required. Plugin slug. |
Output: {ok, plugin, active, already}. Codes: invalid_input (WP_Error), not_found, not_component and activation_failed.
Permissions: activate_plugins. Scope nucleo:admin.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no.
Edition: Free
Known limits: the file must be at WP_PLUGIN_DIR/<slug>/<slug>.php, with the header Nucleo Components. A plugin that is already active returns already: true.
17WooCommerce
nucleo/woo-checkout-fields-set
What it does: adds, replaces or removes additional fields of the WooCommerce block checkout. Nucleo saves them in the nucleo_woo_checkout_fields option and registers them on every request with the WooCommerce Additional Checkout Fields API (woocommerce_register_additional_checkout_field), with id nucleo/<key>. WooCommerce saves the values on the order and shows them in the admin and in emails.
How to use it: MCP tool nucleo-woo-checkout-fields-set. Example: {"set": [{"key": "vat", "label": "VAT number", "location": "address", "type": "text", "required": false}], "remove": ["old"]}.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
set | array of object | fields | — | A field with a key already saved replaces it. |
set[].key | string | ^[a-z][a-z0-9-]{0,39}$ | — | WooCommerce id nucleo/<key>. |
set[].label | string | 1–100 characters | — | |
set[].location | string | contact, address, order | — | Checkout section. With address the field appears in the shipping and billing addresses. |
set[].type | string | text, select, checkbox | — | |
set[].required | boolean | true, false | false | |
set[].options | array of {value, label} | 1–50 entries, unique value | — | Only with type select. |
remove | array of string | saved keys | — |
Output: {ok, fields}, the fields after the change. With empty input (no set nor remove) nothing changes and it returns the saved fields. Codes: woo_missing, invalid_field, too_many_fields.
Permissions: manage_options. Scope nucleo:admin.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no.
Edition: Pro
Known limits: at most 20 fields. The fields appear only in the block checkout (woo/checkout with mode blocks), not in the classic shortcode. Removing a field does not delete the values already saved on orders.
nucleo/woo-checkout-parts-set
What it does: shows or hides parts of the WooCommerce checkout. Order notes, terms and conditions and the coupon field are inner blocks of the Checkout page, which must use the woocommerce/checkout block: the ability removes them or puts them back in their place in the page content, which WordPress saves with a revision (if the page has a Nucleo document, its original copy is edited). Company, phone and the second address line are WooCommerce options (hidden, optional, required) and also work with the classic checkout. Without parameters it returns the current state and is not counted as a write; on a classic checkout or without a Checkout page the block parts are null.
How to use it: MCP tool nucleo-woo-checkout-parts-set. Example: {"orderNote": false, "company": "optional"}. Without parameters it returns the current state.
Parameters:
| Name | Type | Allowed values | Default | Notes |
|---|---|---|---|---|
orderNote | boolean | true, false | — | Block checkout-order-note-block. |
terms | boolean | true, false | — | Block checkout-terms-block. |
coupon | boolean | true, false | — | Block checkout-order-summary-coupon-form-block. |
company | string | hidden, optional, required | — | Option woocommerce_checkout_company_field. |
phone | string | hidden, optional, required | — | Option woocommerce_checkout_phone_field. |
address2 | string | hidden, optional, required | — | Option woocommerce_checkout_address_2_field. |
Output: {ok, parts, pageId}, the state of the six parts after the change and the id of the Checkout page. Codes: woo_missing, invalid_part, no_checkout_page, not_block_checkout and anchor_missing (the page lacks the block to place the part next to).
Permissions: manage_options. Scope nucleo:admin.
Annotations: readonly false, destructive false, idempotent true.
Dry-run: no.
Edition: Pro
Known limits: it needs a Checkout page with the woocommerce/checkout block. An invalid value changes nothing. If the order summary has the old structure of the page created by the WooCommerce installer, with the totals as direct children, the ability moves them into a checkout-order-summary-totals-block, as the editor does. This way the editor does not put the removed coupon back.
Was this page helpful?