DocumentationDownload

Local CLI

Nucleo 0.2+Free~26 min readUpdated October 31, 2026

The nucleo CLI runs on the developer's computer and talks to a remote Nucleo site, without holding any site logic.

On this page

01Overview

@nucleo/cli is a Node package with a single executable, nucleo. It is not WP-CLI: the wp nucleo … commands are described separately.

The CLI holds no site logic. Every command that touches the site calls Nucleo's abilities through the WordPress Abilities API (/wp-json/wp-abilities/v1/abilities/<name>/run), with a user and an Application Password.

The pull and push commands keep the site in a local folder of JSON files. Other commands do local work that the server cannot do: screenshots and CSS coverage with Playwright, token analysis of an HTML file, scaffolding and checking of component plugins.

nucleo mcp exposes the site's MCP server as a STDIO process, for MCP clients that do not speak HTTP.

The CLI code does not check the edition. The edition matters only on the site side: a command that calls a Pro ability fails with HTTP 404 if the site does not have an active Pro license.

02Requirements and installation

Requirements

What it does: lists what is needed to run the CLI.

How to use it: check the version with node --version.

Parameters: none.

Permissions: the site needs a WordPress user with an Application Password. The capabilities required depend on the command: see each command.

Edition: Free

Known limits:

  • Node 20 or later. The package is an ES module.
  • No mandatory dependencies.
  • Playwright is optional. It is needed only for screenshot and critical, with the Chromium browser.
  • The site needs the Nucleo plugin active. The plugin requires WordPress 6.9 or later, the version with the Abilities API that the CLI uses.
  • icons add downloads icons from https://api.iconify.design: it needs Internet access.
  • component check uses php, phpcs, phpstan and phpunit installed locally.

Installation

What it does: makes the nucleo command available.

How to use it: the package is not published on npm: as of 30 October 2026, npm view @nucleo/cli returns 404. There are three ways to install it.

Option 1, release package. The release build creates the file nucleo-cli-<version>.tgz. The file is attached to the GitHub release of the tag v<version>, together with the Free zip and the theme. Install it with npm:

sh
npm i -g ./nucleo-cli-0.2.0.tgz

The bin field of the package creates the nucleo command. The package contains only bin/, src/ and README.md.

Option 2, from the repository. In cli/ run npm link: npm links the nucleo command to the executable in the repository.

Option 3, without installing. Run node cli/bin/nucleo.js <command> from the repository root.

Parameters: none.

Permissions: with -g npm writes to the global package folder.

Edition: Free. The GitHub release contains the CLI together with the Free plugin.

Known limits: none found.

Installing Playwright

What it does: enables screenshot and critical.

How to use it: in the site's project folder:

sh
npm i -D playwright && npx playwright install chromium

The CLI first looks for Playwright next to itself. Then it looks for node_modules/playwright in the working folder and in the first parent folder that contains a package.json. It does not go further up.

Parameters: none.

Permissions: none.

Edition: Free

Known limits: there are three error messages. Each one gives the command to run:

  • Playwright missing: Playwright is not installed. … In the project folder run: npm i -D playwright && npx playwright install chromium.
  • Chromium missing: Playwright is installed but Chromium is missing. Run: npx playwright install chromium.
  • System libraries missing: Chromium cannot start: system libraries are missing. Run: sudo npx playwright install-deps chromium.

03Configuration and common mechanisms

Connecting to the site

What it does: sets site, user and password for the commands that call the site.

How to use it: three sources, in order of priority: command-line options, environment variables, and the file nucleo.config.json in the current folder.

{
  "site": "https://esempio.it",
  "user": "marco",
  "password": "abcd efgh ijkl mnop qrst uvwx",
  "componentsPath": "../wordpress/wp-content/plugins"
}

Parameters:

NameTypeAllowed valuesDefaultNotes
--site / NUCLEO_SITE / sitestringURL http: or https:noneRequired. The CLI removes trailing slashes.
--user / NUCLEO_USER / userstringWordPress loginnoneRequired.
--password / NUCLEO_APP_PASSWORD / passwordstringWordPress Application PasswordnoneRequired. Sent with Basic auth.
componentsPath (file only)stringpathnonewp-content/plugins folder of the local WordPress, for component deploy. Relative to the current folder.

Permissions: authentication is a WordPress Application Password, not OAuth. The CLI does not handle OAuth tokens. Without an OAuth token the site does not check scopes: only the user's capabilities count.

Edition: Free

Warning

The password in the file nucleo.config.json stays in plain text. The CLI does not protect it.

Known limits:

  • Errors: Missing site: use --site URL or NUCLEO_SITE, Invalid site URL: …, Invalid site URL (http or https required): …, Missing user: use --user or NUCLEO_USER, Missing Application Password: use --password or NUCLEO_APP_PASSWORD, nucleo.config.json is not valid JSON: ….
  • The CLI reads the configuration only when a command calls the site. tokens suggest, screenshot, component new and component check work without it.

Calls to abilities

What it does: sends the calls to the site's abilities.

How to use it: read abilities go with GET and the query input[key]=value, with nested objects in square brackets. Write abilities go with POST and the body {"input": {...}}. Every request carries Authorization: Basic … and Accept: application/json.

Parameters: none.

Permissions: those of each ability.

Edition: Free

Known limits:

  • HTTP 401 or 403: <ability>: accesso negato (HTTP <status>). Controlla utente e Application Password.
  • HTTP 404: <ability>: ability not found (HTTP 404). Is Nucleo active on this site?. The same message appears when the ability is Pro and the site has no license: Pro abilities are not registered.
  • Other statuses: <ability>: <message> with the site's message, or HTTP <status>.
  • Network: Connection to <site> failed: ….
  • Site rate limit: 60 writes every 60 seconds per user and scope group (filter nucleo/rate_limit). The response is ok: false with error.code rate_limited. Only the calls to content-list, terms-set and content-upsert made by pull and push retry: they wait retryAfter seconds (10 if missing), up to 5 times. The other calls report the error.

Command line, output and exit codes

What it does: parses arguments and options with the same rule for all commands.

How to use it: nucleo <command> [arguments] [--option value | --option=value | --flag].

Parameters: boolean options, without a value: --dry-run, --prune, --yes, --help, --version, --no-push, --use-tokens. All others require a value. Boolean options also accept =true or =1 and =false or =0; any other value gives an error.

Permissions: none.

Edition: Free

Known limits:

  • An option with a value followed by nothing, or by another --option, gives Missing value for --<name>. -- alone gives Invalid option: --.
  • An option that the command does not accept gives Unknown option: --<name>. Use "nucleo help"., before any call to the site.
  • Exit code: 0 if the command succeeds, 1 for usage errors, site errors or failed steps. component deploy exits with 2 if it copies the plugin but does not activate it. Errors go to stderr with the prefix nucleo: .
  • An unknown command gives Unknown command: <name>. Use "nucleo help".
  • Messages are partly in Italian and partly in English.

04General commands

nucleo help

What it does: prints the list of commands and configuration options, in English. It also lists --urls and --no-push of critical.

How to use it: nucleo help, nucleo --help or nucleo without arguments. --help works with any command and always prints the same general text.

Parameters: none.

Permissions: none.

Edition: Free

Known limits: none found.

nucleo --version

What it does: prints the package version (0.2.0 at this commit).

How to use it: nucleo --version.

Parameters: none.

Permissions: none.

Edition: Free

Known limits: none found.

nucleo guide

What it does: reads the phased guide from the site and prints it as text. Without a phase, the site chooses the first phase not completed.

How to use it: nucleo guide [phase] [--design PATH]. Calls nucleo/guide with GET. The phases are described in the phased guide.

Parameters:

NameTypeAllowed valuesDefaultNotes
phase (positional)integer0–4phase chosen by the siteOut of range: Usage: nucleo guide [0-4] [--design PATH]
--designstringup to 500 characters (ability schema)noneThe site replaces <design.html> in the guide texts with this value.

Permissions: edit_posts. OAuth scope of the ability: nucleo:read.

Edition: Free

Known limits: output on fixed lines: Phase N: <title>, State: tokens … · sections … · layouts … · menus … · post types … · documents …. Then, if present, Checks: (counts per type), Distinct: (list), Coverage: N of M documents read, then the sections Basics: (in every call, except phase 0), To do:, Rules: (with tools:), Exit: and Next:. Empty sections do not appear. A response with ok: false becomes an error with the site's message.

05Site sync

nucleo pull

What it does: downloads the site into a local folder. First it writes the files of nucleo/site-export. Then it downloads the items of the content types into content/<type>/<slug>.json and the terms into terms/<taxonomy>.json. Every item and every term gets the key base: the fingerprint of the site version, which push uses to recognize changes made on the site after the pull.

How to use it: nucleo pull [folder] [--prune]. Calls, in order:

  1. nucleo/site-export, which writes the export files.
  2. nucleo/content-list with perPage: 1 for the list of types. Then, for each type, with type, full: true, perPage: 50 and page, up to the last page.
  3. nucleo/terms-get without input for the list of taxonomies. Then with taxonomy for each one.

Parameters:

NameTypeAllowed valuesDefaultNotes
folder (positional)pathanynucleo-siteRelative to the current folder.
--pruneflag—absentDeletes the files content/<type>/<slug>.json that are absent on the site, and removes from terms/<taxonomy>.json the terms absent on the site. Moves to the backup copy the .json files in pages/, posts/, layouts/, sections/ and menus/ absent from the export.
--onlylistFILE[,FILE]absentSee nucleo pull --only below.

Permissions: manage_options for site-export (scope nucleo:admin). edit_posts on the type for content-list (scope nucleo:read). edit_posts, plus assign_terms of the taxonomy, for terms-get (scope nucleo:read).

Edition: Free

Known limits:

  • It downloads only the types with modeled: true in the content-list response, and those with a local content/<type>/ folder. The same applies to taxonomies with a local terms/<taxonomy>.json.
  • Items with managedBy are not written. Items skipped by the server become warnings and their local file is not deleted.
  • A content-list or terms-get that is absent (HTTP 404) is not an error: the related part is skipped.
  • Without --prune, a local term absent on the site stays in the file. A local file absent on the site is listed as local only: …. A document of pages/, posts/, layouts/, sections/ or menus/ absent from the export is listed as no longer on the site: …: a later push would create it again.
  • An absolute path, .., ., empty segments or \ in the site's response gives an error before writing.
  • Before overwriting or deleting, it copies each local file with different content to <folder>/.nucleo-backup/<date-time>/<path>. The date-time is the ISO one with - instead of : and ..
  • Output: Wrote N files in <folder>, then local backup: …, removed: … and local only: … on stdout. Warnings warning: … go to stderr, including menu items skipped by site-export.

nucleo pull --only

What it does: downloads only some files of nucleo/site-export and updates in site.json only their base. It is used to resolve a conflict by keeping the site's version.

How to use it: nucleo pull [folder] --only pages/home.json,menus/principale.json. Calls only nucleo/site-export.

Parameters:

NameTypeAllowed valuesDefaultNotes
--onlycomma-separated listpaths present in site-export—Empty entries are discarded. Empty list: Usage: --only FILE[,FILE]

Permissions: manage_options (scope nucleo:admin).

Edition: Free

Known limits:

  • It rejects paths in content/ and terms/: --only non accetta <file>: content/ e terms/ si scaricano con nucleo pull senza --only.
  • It rejects a path absent from the export: <file> non è tra i file di nucleo/site-export.
  • It does not download content/ and terms/, and it ignores --prune.
  • A local file that differs from the site's file is first copied to <folder>/.nucleo-backup/<date-time>/<path>. The output reports it with local backup: <path>.
  • With site.json in the list, the written file keeps the base of the local site.json.
  • Reads happen before any write: an error does not leave half-written files.

nucleo push

What it does: sends the local folder to the site. Order: images in media/, terms in terms/, items in content/, then all other .json files with nucleo/site-import. Before uploading images or sending data it runs the same push as a dry run: if the site finds errors, the command stops without changing anything. After each accepted batch of content/ or terms/ it writes the base of the items and terms of that batch, even if the push fails later; after a successful push it updates base, tokensBase and siteBase in site.json.

How to use it: nucleo push [folder] [--dry-run] [--prune [--yes]] [--use-tokens] [--acknowledge FILE] [--force FILE[,FILE]]. Calls, in order:

  1. nucleo/media-upload for each image .jpg, .jpeg, .png, .webp, .gif and .avif in media/ (not recursive). It updates media/manifest.json with file, url, alt and sha1.
  2. nucleo/terms-set per taxonomy, in batches of 500 terms, parents before children.
  3. nucleo/content-upsert per type, in batches of 25 items. Types cited by others (<type>:<slug> in fields) go first.
  4. With --prune: nucleo/content-list with perPage: 100 for each type with a local folder. With --yes: content-upsert with status: "trash".
  5. nucleo/site-import with files (all .json outside content/, terms/ and .nucleo-backup/), dryRun and, if present, pending, acknowledge and force.

Parameters:

NameTypeAllowed valuesDefaultNotes
folder (positional)pathanynucleo-siteRelative to the current folder.
--dry-runflag—absentDoes not upload images. Sends dryRun: true to terms-set, content-upsert and site-import: the site validates without saving. Images not uploaded enter the manifest with the URL https://media.invalid/<file>.
--pruneflag—absentLists the site items absent in content/<type>/ as prune: <type>/<slug>.
--yesflag—absentWith --prune, moves the listed items to the trash.
--use-tokensflag—absentSee nucleo push --use-tokens below.
--acknowledgepathJSON fileabsentSee nucleo push --acknowledge below.
--forcecomma-separated listpaths sent to site-import, files in content/ and terms/absentOverwrites the site's version in case of conflict. Files in content/ and terms/ are sent without base. Another path not sent gives the warning force ignored: ….

Permissions: upload_files for media-upload (scope nucleo:write). manage_terms of the taxonomy for terms-set (scope nucleo:write). edit_posts for content-upsert (scope nucleo:write). manage_options for site-import (scope nucleo:admin). edit_posts on the type for content-list.

Edition: Free

Known limits:

  • Output on stdout: media: <file> → <url> (id N), or (id N, already present) or (dry run). Then created: N, updated: N, unchanged: N (documents identical to the site ones, if greater than 0), content unchanged: N (items of content/ and terms of terms/ identical to the site ones, if greater than 0), trashed: N (if greater than 0) and errors: N. Each error goes to stderr as - <file>: <message> (<code>).
  • Exit code 1 if there is at least one error.
  • With quality_blocking errors it prints: Blocking issues: fix them, or ask the user to accept them and pass the file with --acknowledge FILE.
  • For each conflict it prints: Conflict: keep the site version with nucleo pull --only <file>, or overwrite it with nucleo push --force <file>. For a file in content/ or terms/ the suggestion is nucleo pull, without --only, which rejects them.
  • An item or a term changed on the site after the pull (different base) gives conflict and is not written. To keep the site version run nucleo pull; to overwrite it, --force with the file.
  • A failed upload stops the push before site-import. The items already uploaded stay in the manifest.
  • Local errors in content/ and terms/ stop the push before anything is sent, with Contenuti non validi: <file>: <message>. Codes: invalid_json, invalid_value, slug_mismatch (slug field different from the file name), type_mismatch (type field different from the folder) and duplicate (same slug in pages/ or posts/ for the types page and post).
  • --prune does not touch items with protected: true, those with managedBy and the terms. Without --yes it prints (add --yes to trash them).
  • Invalid JSON outside content/ and terms/, media/manifest.json included, stops the command before anything is sent: Invalid JSON in <file>: ….
  • If site-import responds ok: false, for example rate_limited after 5 retries, the command exits with 1 and the site's message.
  • If the preliminary dry-run finds errors, it prints no changes to the site: the site is not touched.
  • A missing folder gives Folder not found: <folder>.

nucleo push --use-tokens

What it does: before sending, it replaces in the local documents the style values equal to a token with the reference $group.key.

How to use it: nucleo push [folder] --use-tokens [--dry-run]. Calls nucleo/tokens-get. The tokens of site.json take precedence over those of the site.

Warning

Without --dry-run the files stay modified even if the push fails afterwards.

Parameters: nothing beyond the flag. With --dry-run it counts the replacements, does not change the files and validates the versions with the tokens replaced, like the real push.

Permissions: edit_posts (scope nucleo:read), plus the permissions of push.

Edition: Free

Known limits:

  • It applies to .json files with a root object, outside content/, terms/ and media/. It visits style of each node and its children, including the values per breakpoint.
  • Groups and properties: color (color, background, accentColor, dotColor and other keys of the inner parts), space (padding, margin, gap, controlsInset …), radius (borderRadius …), shadow (boxShadow), font (fontFamily, numberFont). The state keys …Hover and …Current use the group of the base key.
  • The comparison is exact after normalization: lowercase, spaces, #abc → #aabbcc, px → rem (16 px = 1 rem). A value only close to a token stays unchanged. 0 and $… references are not replaced. With several equal tokens the first one wins.
  • Output: tokens: <file> <n> per file and tokens: N replacements.

nucleo push --acknowledge

What it does: sends to site-import a person's consents on blocking quality reports (quality_blocking).

How to use it: nucleo push nucleo-site --acknowledge consensi.json. The file has this form:

{
  "pages/home.json": [
    { "rule": "a11y.contrast.low", "node": "cta", "reason": "Consenso di Marco, 27/10" }
  ]
}

The CLI shows each acknowledgement (Acknowledgement: <file> <rule> @<node>, reason: …) and asks Confirm? [y/N]. It accepts y, yes, s, si or sì. It sends only the confirmed acknowledgements.

Parameters: --acknowledge, path of the file, relative to the current folder.

Permissions: those of push.

Edition: Free

Known limits:

  • Without an interactive terminal (agent, CI, pipe) the command refuses: --acknowledge needs an interactive terminal: a person confirms each acknowledgement. ….
  • Each entry requires rule, node and reason as non-empty strings. Otherwise: <file>: <path> deve essere { "percorso.json": [{ "rule", "node", "reason" }] } con reason non vuoto.
  • Missing file: Acknowledgement file not found: …. Invalid JSON: Invalid JSON in ….
  • A consent on a file not sent to site-import, including in content/ or terms/, gives the warning acknowledgement ignored: ….
  • The consents file inside the site folder is not sent to site-import.

06Design and media

nucleo tokens suggest

What it does: reads the CSS of a design HTML file and proposes tokens for nucleo/tokens-set. It writes no files and does not call the site.

How to use it: nucleo tokens suggest design.html > tokens.json. On stdout it prints only {"tokens": …}. On stderr it prints the evidence: <group>.<key>: <value> (<occurrences>) from <variable> and no token: <type> <value> (<occurrences>).

Parameters:

NameTypeAllowed valuesDefaultNotes
<design.html> (positional)pathHTML file—Required. Otherwise: Usage: nucleo tokens suggest <design.html>

Permissions: none.

Edition: Free

Known limits:

  • It reads <style> blocks and style attributes. It removes <script> first. It ignores @font-face. Definitions outside @media, @supports and @container win.
  • A value becomes a token only if it appears at least 3 times.
  • With at least 3 CSS variables defined in the file, it replaces var(--name) with the value and ignores the rules without variables whose classes do not appear in the markup.
  • Product groups: color (primary, secondary, accent, background, text, surface, border, muted, chosen by lightness and saturation), font (body, heading), space (keys 1–16 by proximity), text (xs–6xl), radius (sm, md, lg, full), shadow (sm, md, lg). Durations always end in no token.
  • These do not become tokens: unset, inherit, initial, revert, revert-layer, none, normal, unresolved values with var(, and values with ;{}<>\.

nucleo media upload

What it does: uploads one or more files to the site's media library.

How to use it: nucleo media upload foto1.jpg foto2.png [--alt TEXT]. Calls nucleo/media-upload for each file, with file (base name), data (base64) and alt.

Parameters:

NameTypeAllowed valuesDefaultNotes
<file...> (positional)pathsone or more—Required. Otherwise: Usage: nucleo media upload <file...> [--alt TEXT]
--altstringany""Same alternative text for all files.

Permissions: upload_files (scope nucleo:write).

Edition: Free

Known limits:

  • The site accepts JPEG, PNG, WebP, GIF and AVIF.
  • Output: <file> → <url> (id N), or (already present) for a file already in the library. A failed file goes to stderr and does not stop the others. Code 1 if at least one fails.
  • No retry after rate_limited.

nucleo icons import

What it does: uploads the .svg files of a folder as site icons.

How to use it: nucleo icons import ./icone [--prefix P]. Calls nucleo/icons-set with { set: { name: svg } }, in batches of 50.

Parameters:

NameTypeAllowed valuesDefaultNotes
<folder> (positional)patha folder—Not recursive.
--prefixstringany""Prepended to the name.

Permissions: manage_options (scope nucleo:admin).

Edition: Free

Known limits:

  • Icon name: prefix plus the file name without extension, in lowercase, with the sequences outside a-z0-9 replaced by -. A name that does not start with a letter is skipped with a warning.
  • Without valid files: nessun file SVG con nome valido in <folder>, code 1.
  • A failed batch does not stop the others. Output: site icons: N.

nucleo icons add

What it does: downloads icons from Iconify and uploads them as site icons.

How to use it: nucleo icons add mdi:car lucide:truck or nucleo icons add mdi:car --as auto. It downloads https://api.iconify.design/<prefix>/<name>.svg, then calls nucleo/icons-set.

Parameters:

NameTypeAllowed valuesDefaultNotes
<prefix:name...>stringsformat prefix:name—Other format: formato atteso prefisso:nome
--asstringanyIconify icon nameOnly with one icon. With several icons: --as vale solo con una icona.

Permissions: manage_options (scope nucleo:admin).

Edition: Free

Known limits: an icon with an HTTP status other than 200, or with a response that does not start with <svg, gives an error and does not stop the others. Code 1 if at least one fails. The name sent does not go through the normalization of icons import.

nucleo icons remove

What it does: removes site icons.

How to use it: nucleo icons remove auto camion. Calls nucleo/icons-set with { remove: [...] }.

Parameters: <name...>, one or more names.

Permissions: manage_options (scope nucleo:admin).

Edition: Free

Known limits: output site icons: N. An ability error goes to stderr and gives code 1.

nucleo icons list

What it does: prints the site icons on one line and the built-in icons on a second line.

How to use it: nucleo icons list. Calls nucleo/icons-set with empty input, with POST.

Parameters: none.

Permissions: manage_options (scope nucleo:admin).

Edition: Free

Known limits: the call is a write for the site and counts toward the limit of 60 writes per minute. An invalid subcommand gives the usage Usage: nucleo icons import <folder> [--prefix P] | add <prefix:name...> [--as NAME] | remove <name...> | list.

07Local browser (Playwright)

nucleo screenshot

What it does: takes full-page screenshots of a URL at several widths. It does not call the site's abilities.

How to use it: nucleo screenshot https://esempio.it/chi-siamo/ [--out folder] [--widths 390,768,1440]. It requires Playwright with Chromium.

Parameters:

NameTypeAllowed valuesDefaultNotes
<url> (positional)URLhttp: or https:—Errors: Missing URL: …, Invalid URL: …, Invalid URL (http or https required): …
--outpathanyscreenshotsCreated if missing.
--widthscomma-separated listintegers from 240 to 3840390,820,1440,2560Duplicates discarded. Error: Invalid width: …

Permissions: none on the site. The CLI does not send credentials to the page.

Edition: Free

Known limits:

  • Viewport height 900 px. It waits for networkidle before the shot.
  • File name: <host-path>-<width>.png, with the characters outside a-z0-9 replaced by - (home if empty). It prints one path per line.
  • A page reserved for logged-in users shows the public version: Playwright does not receive the user's cookies.

nucleo critical

What it does: for each template it opens the URL with Chromium at four viewport widths (390, 820, 1440 and 2560 px), collects the CSS rules that match at least one visible element in the first screen, and writes the merged result to <folder>/<template>.css. Without --no-push it sends the CSS as the template's critical CSS.

How to use it:

  • nucleo critical --urls home=https://esempio.it/,page=https://esempio.it/chi-siamo/ [--out folder] [--no-push]
  • nucleo critical [--out folder] [--no-push]: without --urls it reads the urls map (template → URL) of nucleo/assets-report.

For each CSS it calls nucleo/critical-set with template and css.

Parameters:

NameTypeAllowed valuesDefaultNotes
--urlscomma-separated list of template=urltemplate=url pairsabsentEach pair is split at the first =: URLs with a query stay intact. A pair without =, without a template or without a URL gives a usage error.
--outpathanycriticalCreated if missing.
--no-pushflag—absentWrites the files and does not call critical-set.

Permissions: manage_options for assets-report (scope nucleo:read). edit_theme_options for critical-set (scope nucleo:design). The site configuration is required even with --urls --no-push.

Edition: with --urls Free. Without --urls Pro, because nucleo/assets-report requires a Pro license. Without a license the command writes nucleo: nucleo/assets-report not found. Without --urls, critical needs Nucleo Pro with an active licence. and exits with 1.

Known limits:

  • Without --urls it uses the urls map of the report. Entries without an absolute URL go to stderr as no URL in the report for template "<name>", skipped. If no URL is left: nucleo: no URL to analyse. Run the asset audit or pass --urls template=URL., with code 1.
  • Each template is measured at four viewports (390×844, 820×1180, 1440×900, 2560×1440). The rules are merged without duplicates, in order of first appearance.
  • The CSS contains only the rules that match at least one visible element in the first screen. Stylesheets from another origin cannot be read and are skipped.
  • The CLI caps the CSS at 50 KB: the merge stops at the first rule that would exceed the limit, without an error. The site still rejects a CSS larger than 50 KB (The critical CSS exceeds the 50 KB limit.): the local file stays written and the command stops at the first ok: false result of critical-set, with the site's message.
  • File name: the template with the characters outside A-Za-z0-9._- replaced by -.

08MCP

nucleo mcp

What it does: acts as a proxy between STDIO and the site's HTTP MCP server (POST <site>/wp-json/nucleo/v1/mcp). It serves MCP clients that start a local process.

How to use it: nucleo mcp with NUCLEO_SITE, NUCLEO_USER and NUCLEO_APP_PASSWORD in the environment of the MCP client. Each stdin line is a JSON-RPC message. Each response goes to stdout on one line.

Parameters: nothing beyond the site configuration.

Permissions: logged-in user via Application Password. Each ability called checks its own capability. OAuth scopes do not apply.

Edition: Free. Pro abilities appear only if the site has a license.

Known limits:

  • Requests are processed in sequence, one at a time.
  • Notifications, that is messages without id, produce no output. An error on a notification goes to stderr.
  • Invalid JSON: response -32700 Parse error. HTTP error or empty response: response -32000 with the message.
  • The CLI forwards the Mcp-Session-Id header if the server sends it. The Nucleo server at this commit does not send it.
  • The process ends with code 0 when stdin closes.

09Components

nucleo component new

What it does: creates a component (data source, action or block) in a local components plugin. If the plugin is missing, it also creates the skeleton.

How to use it: nucleo component new <data-source|action|block> <name> [--dir FOLDER] [--vendor PREFIX]. It does not call the site.

Parameters:

NameTypeAllowed valuesDefaultNotes
<kind>stringdata-source, action, block—Other value: Invalid kind: …
<name>string^[a-z][a-z0-9-]{1,40}$—Error: Invalid name: …
--dirpathanynucleo-componentsThe folder name is the plugin slug.
--vendorstring^[a-z][a-z0-9-]{0,39}$from the folder name: nucleo-acme-components becomes acme, nucleo-components becomes siteError: Invalid vendor: …

Permissions: none on the site.

Edition: Free

Known limits:

  • Plugin skeleton: <slug>.php with the header Nucleo Components: <vendor>, composer.json, phpunit.xml, phpstan.neon, phpcs.xml.dist and tests/bootstrap.php.
  • Component files: src/DataSources/<Class>.php, src/Actions/<Class>.php, or blocks/<name>/block.nucleo.json with src/Blocks/<Class>Renderer.php. Always a test in tests/<Class>Test.php. The registered name is <vendor>/<name>.
  • If an expected file already exists, it writes nothing: File già esistente: … Nessun file scritto.
  • It prints the written paths, one per line.

nucleo component check

What it does: runs php -l on the plugin's PHP files, then phpcs, phpstan and phpunit. A failed step does not stop the others.

How to use it: nucleo component check [--dir FOLDER]. It does not call the site.

Parameters:

NameTypeAllowed valuesDefaultNotes
--dirpathanynucleo-componentsMust contain <slug>.php.
NUCLEO_TOOLS (variable)pathfolderabsentAlternative folder for phpcs, phpstan and phpunit.

Permissions: none on the site.

Edition: Free

Known limits:

  • Tool lookup: <plugin>/vendor/bin/<tool>, then NUCLEO_TOOLS/<tool>, then the name in the PATH.
  • Fixed arguments: phpcs --standard=phpcs.xml.dist, phpstan analyse --no-progress --memory-limit=1G -c phpstan.neon, phpunit -c phpunit.xml.
  • Output: <step>: ok|fail|missing and the output of the step if it is not ok. Code 1 if a step is not ok.
  • Missing plugin: Plugin not found in <dir>: <slug>.php is missing. Create it with "nucleo component new".

nucleo component deploy

What it does: checks the plugin, copies it into the plugins folder of a local WordPress and activates it. The copy is local: no HTTP request carries PHP code.

How to use it: nucleo component deploy [--dir FOLDER] [--plugins PATH]. Steps:

  1. Calls nucleo/site-describe and reads environment. It proceeds only with local or development.
  2. Runs component check. If a step is not ok, it copies nothing.
  3. Copies the folder to a temporary folder next to the destination, without hidden files, vendor, node_modules, tests, phpunit.xml, phpstan.neon, phpcs.xml.dist and composer.lock. At the end it replaces the destination. If the copy fails, the previous version stays.
  4. Calls nucleo/component-activate with plugin: <slug>.

Parameters:

NameTypeAllowed valuesDefaultNotes
--dirpathslug ^[a-z0-9][a-z0-9-]{0,60}$ as folder namenucleo-components
--pluginspathwp-content/plugins foldercomponentsPath of nucleo.config.jsonWith neither: componentsPath mancante: …

Permissions: edit_posts for site-describe (scope nucleo:read). activate_plugins for component-activate (scope nucleo:admin). Writing to the file system of the plugins folder.

Edition: Free

Known limits:

  • With staging, production or a missing environment it prints the human step and exits with 1: the component arrives with the site migration or with the deploy via git.
  • It does not overwrite an existing destination without the line Nucleo Components: in the first 8 KB of the main file. It refuses a source and a destination that coincide or contain each other, also through symbolic links: it copies nothing and exits with 1.
  • If the site answers not_found after the copy, componentsPath is not the plugins folder of the linked site: message and exit with 1.
  • Other activation errors: the copy stays, the command prints activate <slug> from Plugins (<error>) and exits with 2.
  • Success output: copied N files to <destination> and plugin active.
Esc
↑↓ to select↵ to openEsc to closeLocal search, no data sent