npx @shoppexio/cli, or install it globally. Authenticate with
a Shoppex API key that has the required theme scopes.
settings update validates the complete settings object. Fetch the current
settings first, make a focused change, and keep a local copy for review.
The CLI can also install the Shoppex MCP server configuration for supported AI
clients. Run shoppex --help for the exact commands available in your installed
version.
Editing an Easy theme locally
An Easy theme is a ThemeDocument, not a source tree. It is not one opaque file either.theme pull splits it into files you can read, diff, and commit.
theme push puts them back.
$schema pointer into .shoppex/schema/. VS Code
and other JSON language servers use it to complete block types, element types,
and settings. They also flag mistakes while you type. The schemas come from the
server on each pull, so they always match the contract that validates your push.
pull requires an empty target directory. Add --force to overwrite matching
files in a non-empty one. Pages deleted upstream are removed locally, and each
removal is printed.
theme.json carries a pageOrder array. Page aliases resolve in document page
order, so the checkout records that order instead of inferring it from the
directory listing. Reorder the entries to reorder the document. A page file you
add locally is appended, and the push output names it. Move it inside
pageOrder to place it somewhere else.
pull also writes AGENTS.md, so Cursor, Claude Code, and Codex pick up the
rules that the files do not show: which block types exist, that .shoppex/ is
off limits, and that a push conflict means pull-and-reapply. A pull refreshes
the guide it wrote itself. It never touches an AGENTS.md you wrote: it says so
and leaves your file alone.
push sends the reassembled document with the revision recorded at pull time.
If the Builder saved the theme in the meantime, the push is rejected with a
conflict. It does not overwrite that edit. Pull again, reconcile, then push. The
server is the only validator. A contract violation comes back as a validation
error that names the offending path, so the CLI keeps no second copy of the
schema.
push writes the draft. publish promotes exactly the revision the checkout
recorded, so a Builder save in between is a conflict instead of a silent
promotion of an edit this checkout never saw.
Which themes can be pushed
pull works for every Easy theme. push only works for themes whose document
is authoritative, which means themes imported from a ThemeDocument. A theme
installed from the catalog renders its document from Builder settings. The
server refuses direct document writes to it, and pull says so up front. That
checkout is still useful for reading, diffing, and backing up. Edit it in the
Builder instead.
Live preview while you edit
theme dev watches the checkout and saves the draft after each change. It also
serves a local page that frames the hosted preview and reloads it on every save.
http://localhost:<port> address. Open that address, not the
preview URL, because the local page performs the reload. The preview renders on
the server from the draft, so you see the real renderer, not a local
approximation.
A save that would store an identical document is skipped, so no-op writes do not
spend a revision. If the Builder saves the same theme while dev runs, the next
save conflicts and dev stops. Pull again, reconcile, then restart. A file that
is not valid JSON yet is normal mid-edit. It is reported once and does not stop
the loop.
The API key needs themes.read for pull. It needs themes.write for push,
dev, and publish. A key bound to one theme can use the equivalent
theme-specific scopes.
Advanced storefronts
Advanced storefronts use merchant-owned Vite and React source instead of a ThemeDocument. The CLI can pull the current source, push a complete local project, build it, and publish the completed artifact.pull requires an empty target directory. Add --force when you intentionally
want to overwrite matching files in a non-empty directory.
After a pull, the CLI writes .shoppex/storefront.json:
files map records the
last successful pull or push. On every pull, the CLI writes the full remote
manifest and removes locally tracked files that were deleted remotely. It
prints each removed path. --force still controls overwriting in a non-empty
directory.
pull downloads the whole revision as a single archive instead of one request
per file, so even large storefronts arrive in one round trip. Every extracted
file is verified against the manifest checksum, and the pull stops without
writing anything if the archive and the manifest disagree.
push sends every tracked file plus new local files. New files under
node_modules, dist, .git, .turbo, or .shoppex, and .DS_Store files
are ignored. A shoppex.theme.json at the storefront root is ignored too. The
name is reserved for theme package metadata, and the API rejects it as source.
Already tracked files are never ignored, so a tracked file such as
dist/vendor.js remains part of the source tree.
Exporting a storefront package
export downloads the complete source tree of the current revision as a single
ZIP. It adds one shoppex.theme.json package manifest, holding the theme
metadata and the storefront’s content. It is the portable form of a storefront:
back it up, hand it to another developer, or import it into another shop.
.shoppex/storefront.json, so --theme is optional there. Without --out the
CLI writes the server-provided filename into the current directory. It refuses
to overwrite an existing file unless you pass --force, and never writes
through a symlink. export needs only read access, so themes.read or the
theme-specific read scope is enough.
Pushes above about 10 MB automatically upload the complete source tree
as a single ZIP archive. This transport switch requires no flags and keeps the
same revision, deletion-confirmation, and build behavior as smaller pushes.
If a tracked file is missing locally, push prints the complete deletion list
and stops. Re-run with --delete to confirm those deletions. The full snapshot
then removes them remotely. If the remote revision changed, pull the latest
source before you push again. Pulling also applies remote deletions locally.
By default, push starts a build and prints its job ID. Use --no-build to
upload source without starting one. deploy checks the current revision’s
build every five seconds, waits up to 600 seconds, and publishes only after the
build reaches COMPLETED. Override the wait with --timeout <seconds>.
Immediately before publishing, deploy re-checks that the server is still on
the revision recorded in .shoppex/storefront.json. If another developer
pushed, deploy stops and asks you to pull or push first.
When a build fails, deploy and status print the failure kind and the
reason recorded by the build. They also print what to do about it, plus the
tail of the build log. The most common failure is lockfile_out_of_sync: your package.json
and lockfile disagree, because a dependency changed without a matching
bun install. Run bun install, then push again so the updated lockfile ships
with your source. workspace_unavailable is ours, not yours: retry the build.
The API key needs themes.read for list, pull, status, and the build
polling in deploy. It needs themes.write for push, build enqueueing, and
the publish step in deploy, so deploy needs both scopes. A key bound to one
theme can use the equivalent theme-specific read and write scopes.