Skip to main content
The pipeline is three commands, in order, every time:

Lint before every deploy

exjsx lint enforces the mechanical subset of the authoring conventions. Rule families, each with a rule id you can grep for:
  • Errors: invalid-envelope (a style value the server validator would reject: numbers, colors, units, flex enums).
  • Warnings: env-baked-url, img-alt, raw-atomic-overlap, placeholder-link, font-not-loaded, heading-structure, page-seo, duplicate-page-slug.
  • Info: oversized-raw, unnamed-shared-class, deep-nesting, empty-container.
Every finding prints its fix inline. Real output from a production project:
The final verified: line is a set of positive assertions: facts the linter proved about the bundle (every style envelope valid, every referenced font family covered, slugs unique). When a gate prints a verified: fact, it is proven; do not re-verify it with hand-rolled scripts.

Deploy

exjsx deploy <bundle.json> performs two kit writes (variables + the shared class registry) and N page upserts over REST. No wp-cli is needed: the deployer detects the Elementor version over REST and adapts prop formats per version. It is idempotent: re-run it any time, and unchanged pages are simply re-stamped.

Flags

--dry output:
--only warning, verbatim:

Drift protection

On deploy, each page’s live tree is compared against the hash stamped at the last deploy. A mismatch means a human edited the page in the Elementor editor, and the page is reported as skipped-drifted instead of being overwritten. Stop when you see it. Reconcile (use exjsx decompile to adopt the live tree back into JSX) or consciously --force; never reflex-force. Drift detection reads the live tree through wp-cli; without wp-cli the deploy still works, and the report says wp-cli unavailable : drift detection skipped (hand-edit protection off; set EXJSX_WPCLI).

The foreign-store merge guard

Deploying a small side bundle (a probe page, a one-off) to a site that already hosts another project used to let orphan cleanup delete the resident project’s classes. Now the deployer detects a foreign class store and merges instead of wiping: resident classes the bundle does not declare are preserved, and the report says so:
If the full resident store cannot be read for a safe merge, the deploy refuses with:

Multi-tenant targets: —inline

On shared or multi-site targets, build with exjsx build site --inline: self-contained pages, zero kit writes, no registry or variable clobber. Single-owned sites should use normal deploys, which own the class registry namespace (and give you the Class Manager names from cls=).

The loop

Build, lint, deploy, then verify with one call:
See Verify for what the gate asserts, and Recipes: agent briefs for how to budget fix rounds.