[data-reveal]{opacity:1!important;transform:none!important}
Building

Frontend CLI

The frontend loader's command line — dev, build, start, prepare, clean, how dev auto-discovers the backend, and the per-backend workspaces.

The acms binary (also antelope-cms), shipped by @antelopejs-private/cms-nuxt, runs the shared dashboard frontend: the dev server, the production build and server, CI typings, and workspace cleanup. For the machine it drives — layers, config, the catch-all renderer — see Frontend layer.

Commands and flags

acms has five commands. They don't all take the same flags — the set varies per command:

  • -b, --backend-url <url> (env CMS_BACKEND_URL): dev, build, start, prepare, clean.
  • -p, --port <port> (default 3001, env PORT): dev, start only.
  • -f, --force (reinstall deps): dev, build, prepare.
  • --offline (reuse the cached manifest, env CMS_OFFLINE): dev, build, prepare.
  • --bootstrap-secret <secret> (env CMS_BOOTSTRAP_SECRET): dev, build, prepare.
  • -a, --all (clean every workspace): clean only.
CommandPurposeBackend URL
devDev server with HMR. Reserves the frontend port first and sends it to the backend so it can whitelist the origin for CORS. Copies each layer into the workspace and watches the source to mirror edits.Auto-discovers (see below)
prepareGenerate layer typings (nuxi prepare) and symlink .nuxt back into the layer. Meant to run as a layer's postinstall.Optional — CI-friendly
buildProduction build; downloads the layers as a ZIP from the backend, then nuxi build.Required
startRun the built production server (node .output/server/index.mjs).Required
cleanRemove workspace artifacts. -a/--all cleans every workspace.-b or --all
prepare exits 0 (with a warning) when no backend URL is set or the backend is unreachable. That's deliberate: a layer's postinstall calling acms prepare must not break a CI install when no backend is running.

How dev finds the backend

dev resolves the backend URL in order:

  1. An explicit -b / CMS_BACKEND_URL.
  2. Otherwise it walks up from the current directory for a .antelope/dev.json (written by a running ajs project dev), validates the recorded pid is alive, and reads the API endpoint from it (rewriting a wildcard host like 0.0.0.0 to localhost).

It stops at the first .antelope/dev.json it finds, so it won't accidentally attach to a parent project's backend. build, start, and clean do not auto-discover — give them -b.

Authenticating to the backend

The two routes acms fetches — the manifest and the layers ZIP — carry each layer's private options and full source, so the backend gates them behind nuxt.bootstrapSecret. acms resolves the credential to present in order:

  1. An explicit --bootstrap-secret / CMS_BOOTSTRAP_SECRET. Prefer the environment variable — a secret on the command line is visible to every process on the machine.
  2. dev and prepare then walk up for the project's .antelope/cms-dev.json, which a development backend publishes for exactly this purpose. So the local loop needs no configuration at all.

A discovered credential is presented only to the backend that published itacms compares the URL it is about to call against the api endpoint in that project's own .antelope/dev.json. Point -b at a staging or production host from inside a running project and the local credential is withheld rather than sent to it.

build uses only the explicit value: quietly authenticating a production build with a local dev instance's credential would fail far from its cause. start needs no credential — it makes no requests.

A refused credential is fatal for dev and build, and it never falls back to the cached manifest: that cache can still hold private options from a previously-authorized run, and replaying them would defeat the gate. prepare keeps its exit-0 contract and falls back to a workspace-less prepare.

Refusal only happens on a backend configured requireBootstrap: "enforce". The default, "warn", answers an unauthenticated caller with a 200 whose private options have been removed — so nothing fails and the build succeeds. acms warns whenever the layers arrive with no private options at all, which is the only client-side signal that this happened.
Against a backend that does not recognize the credential, dev fails with a message naming both remedies — it cannot work from a manifest with no layer source paths, which the backend serves only to authenticated callers on the same machine.
Workspaces are isolated per backend under ~/.acms/<hash>/ (each with its own node_modules, manifest cache, and client storage scope). After confusing state, reset with acms clean -b <url> or acms clean --all.