CLI reference
npx @impetik/xeer --help
npx @impetik/xeer --versionInside a project that has run npm install, npx xeer <command> resolves the local copy, and the
scaffolded npm run dev / check / build / test scripts work too. Prefer it on your PATH?
npm install --global @impetik/xeer, and drop the npx from every command on this page.
Every command accepts --json, which prints a single structured envelope instead of prose (or, for the
long-running commands, a stream of newline-delimited events). See Building with AI
agents.
Where a command takes [directory], it defaults to the current directory. Where it takes
[app|directory], you may name a deployed app by its name, its appId, or its URL — or omit it,
in which case the app the current directory is linked to is used.
#Global flags
| Flag | |
|---|---|
--json | Structured output. |
--version, -v | Print the installed version. |
--help, -h | Print the command list. |
--control-url <url> | Talk to a different Xeer control plane. Must be HTTPS except on loopback. XEER_CONTROL_PLANE_URL does the same. |
#Build and check
#xeer new
xeer new <directory> [--template notes|todo|blog|personal-site] [--json]Scaffolds a complete working app: manifest, project identity, typed server, Preact client, styles, a favicon, and a passing test suite. The target directory must be empty or nonexistent. The project name is derived from the directory name, lowercased and slugified.
--template defaults to notes:
| Template | |
|---|---|
notes | Per-user notes: one table, create and delete, ownership proven in tests. |
todo | A per-user task list: add, tick off, delete, and an open count read through an index. |
blog | Posts anyone can read and only their author can delete, with a list and a read view. |
personal-site | A few static pages from one shared content module, and no database at all. |
Every template checks, tests, and builds clean, and none of them scaffolds sign-in UI — every visitor
already has a verified identity, and the scaffolded README explains the opt-in path to a named account.
See Auth. With --json, result.template reports which one was written.
#xeer check
xeer check [directory] [--json]Validates xeer.app.json and analyses both source graphs — entrypoints resolve, the server export is
statically readable, no client module imports server code, routes do not collide. Runs nothing. This is
the fast inner-loop command; exit 0 means the project is well-formed.
#xeer build
xeer build [directory] [--json]Compiles a content-addressed build artifact — client bundle, server bundle, assets, and a manifest — into
.xeer/build/<hash>/, then verifies it. An artifact the verification refuses is never reported as a
successful build. Prints the artifactId (a sha256:… value); the same source and manifest always
produce the same id.
#xeer doctor
xeer doctor [directory] [--json]Diagnoses your local environment rather than your code: Node version, platform support, whether the build dependencies resolve, generated configuration, and local state. Reports each check as pass/warn/fail/skip. Run this first when something works on one machine and not another.
#Run locally
#xeer dev
xeer dev [directory] [--host <host>] [--port <port>] [--json]Starts a development server with your client and server running together. Client edits hot-reload; server
edits recompile and restart behind a health check with automatic rollback if the new version does not come
up. Defaults to 127.0.0.1 and a free port — pass --port to pin it.
Uses local personas instead of real sign-in, and a local database that persists between runs.
#xeer preview
xeer preview [directory] [--host <host>] [--port <port>] [--json]Verifies and runs the artifact xeer build produced, reading only the artifact's own contents and never
your source. The closest local approximation of production. Its state is separate from xeer dev's.
#xeer test
xeer test [directory] [--host <host>] [--json]Builds the project, type-checks tests/**/*.test.ts against the generated contract, boots the verified
artifact with fresh isolated state, runs every test in registration order, and tears down. Exit 1 on any
failure. See Testing.
#Sign in
These sign you in, so that you can deploy. They have nothing to do with your application's own users — see Auth.
#xeer auth login
xeer auth login [--control-url <url>] [--no-open] [--json]Browser-approved sign-in. Prints a verification URL and a confirmation code, then opens your browser
(--no-open leaves that to you) and polls until you approve or the request expires. Approve only if the
browser shows that exact code. The credential is written to ~/.xeer/credentials/cli.json with 0600
permissions; XEER_CONFIG_HOME overrides the directory.
#xeer auth status
xeer auth status [--json]Verifies the stored credential and prints who you are signed in as, when it expires, and which control plane it is for:
Signed in as you@example.com.
Credential expires 2026-08-24T09:41:12.883Z.
Control plane: https://control.xeer.runWhen the stored credential pins somewhere other than the default, the last line says so — which is how you find out why a deploy went somewhere unexpected:
Control plane: https://staging-control.xeer.run (non-default)xeer deploy prints the same warning to stderr before it builds. Fails with XE5002 when you are not
signed in.
#xeer auth logout
xeer auth logout [--json]Revokes the credential at the control plane and deletes the local file.
#xeer auth as / xeer auth clear
xeer auth as <alice|bob> [directory] [--workspace <id>]… [--json]
xeer auth clear [directory] [--json]Unrelated to signing in. These select the local development persona — a pretend app user —
xeer dev starts with, stored per project in .xeer/auth.local.json. They touch no account and no
credential.
--workspace is repeatable and each value may be comma-separated. It is a startup default only: a
browser tab that has already chosen a persona keeps it, and xeer test ignores the file entirely because
tests name their persona per call. See Local
personas.
#Ship
#xeer deploy
xeer deploy [directory] [--environment prod|preview] [--control-url <url>] [--json]Builds, verifies, and deploys. Targets production unless you pass --environment preview, which
deploys to a side-by-side URL with its own separate, disposable data. Waits for the deployed app and
confirms platform health, assets, and one authenticated request before reporting success — a deploy that
serves assets but fails authenticated requests fails with XE5104.
--environment accepts prod, production, or preview. Reports how many environment values it
injected.
#xeer promote
xeer promote [app|directory] [--from-artifact <artifactId>] [--control-url <url>] [--json]Makes what preview is serving live on production — the same bundle, not a rebuild — using production's
own environment values. --from-artifact promotes a specific retained version instead. Refused with
XE5175 when the app has nothing on preview yet.
#xeer rollback
xeer rollback [app|directory] <artifactId> [--environment prod|preview] [--control-url <url>] [--json]Redeploys an artifact the app already deployed successfully. Take the id from the ARTIFACT column of
xeer deployments. Records a new deployment rather than rewriting history, and injects environment
values as they are now, not as they were. Either argument order works — an artifact id is recognisable
on sight. Refused with XE5164 for an artifact this app never deployed.
#xeer deployments
xeer deployments [app|directory] [--limit <n>] [--control-url <url>] [--json]Deployment history for one app, newest first: environment, status (pending, ready, failed),
timestamp, failure reason, and the full artifactId. A * marks the deployment currently serving each
environment — the latest completed one. --limit takes a positive integer up to 200.
#xeer link
xeer link [directory] [--app <appId>] [--new] [--control-url <url>] [--json]With no arguments, lists the apps you own. --app points this directory at one of them by writing
xeer.project.json — commit it. --new deliberately forks the checkout to a brand-new app identity.
xeer deploy never invents an identity when xeer.project.json is present but unusable; it fails with a
hint pointing here.
#xeer disable / xeer enable
xeer disable [app|directory] [--control-url <url>] [--json]
xeer enable [app|directory] [--control-url <url>] [--json]Takes an app offline immediately and reversibly: requests get 410 Gone while the app, its data, and its
environment values stay exactly as they are. Both are idempotent, and both keep working when the app
itself is broken.
#xeer delete
xeer delete [app|directory] --confirm <application> [--control-url <url>] [--json]Permanent. Destroys the deployed app and its preview slot along with every byte of their stored data,
removes its URLs, and retires the appId for good. --confirm must be the application's exact name;
without it the CLI refuses locally (XE5150) before reading your credential.
#Inspect
#xeer inspect / xeer state / xeer logs
xeer inspect <preview-url|app> [--control-url <url>] [--json]
xeer state <preview-url|app> [--control-url <url>] [--json]
xeer logs <preview-url|app> [--after <cursor>] [--control-url <url>] [--json]inspect reads the running app's manifest, state its stored records, logs its recent log entries
(--after takes a cursor from a previous call to page forward).
A local xeer dev or xeer preview URL is read directly. A deployed app — named by name, appId, or
URL — is read through the control plane on your credential: a deployed inspector answers nobody else.
#xeer state reset
xeer state reset [directory] --state <dev|preview|test> --confirm <application> [--json]Clears local state for one mode. --confirm must be the exact application name. Prints a recovery path.
Take an export first if the data matters.
#Move data
#xeer export / xeer import
xeer export <preview-url|app> [--out <file>] [--control-url <url>] [--json]
xeer export --state <dev|preview> [directory] [--out <file>] [--json]
xeer import <preview-url> <file> [--json]
xeer import --state <dev|preview> [directory] <file> [--json]--state dev|preview reads or writes the state of the xeer dev / xeer preview server running in that
directory — no URL needed. Any other target is a deployed app, read on your credential. Without --out,
the document goes to stdout.
The file carries the schema that produced the rows plus every record, so it is readable and diffable on its
own. import replaces state wholesale in one transaction, and only when the document's schema is the
one currently in force or a compatible predecessor of it. There is no --force. import writes local
dev and preview state only.
xeer test state cannot be exported or imported — it is discarded after every run.
#Environment values
#xeer env
xeer env set <NAME> [value] [--environment prod|preview|dev] [--dir <directory>] [--json]
xeer env ls [--environment prod|preview|dev] [--dir <directory>] [--json]
xeer env rm <NAME> [--environment prod|preview|dev] [--dir <directory>] [--json]
xeer env pull [--environment prod|preview|dev] [--dir <directory>] [--json]set, rm, and ls default to prod; pull defaults to dev. --environment accepts prod,
production, preview, dev, or development. Omit the value on set to read it from stdin.
ls shows names, sizes, and timestamps — never values. pull writes the values for one environment to
.xeer/env.dev.local.json with 0600 permissions, adding .xeer/ to .gitignore first.
env uses --dir rather than a positional directory, because set NAME [value] already has an optional
trailing argument and a value is indistinguishable from a path.
Full details, including the naming rules and limits: Environment variables and secrets.
#Environment variables the CLI reads
| Variable | |
|---|---|
XEER_CONTROL_PLANE_URL | Default control plane origin, same as --control-url. |
XEER_CONFIG_HOME | Where the CLI stores your credential. Defaults to ~/.xeer. |
#Exit codes
| Code | |
|---|---|
0 | Success. |
1 | The operation failed — a diagnostic explains why. |
2 | You asked wrongly: a missing argument, an unknown flag, an unusable value. |
The split matters for scripting: exit 2 means "fix the command", exit 1 means "the command was fine and the platform refused or the project is broken".
#Requirements
- Node.js 22.12 or newer. The CLI checks at startup and prints a clear error otherwise.
- npm 11 and newer block native install scripts by default. If
xeer devorxeer buildcannot find its runtime, runnpm approve-scripts esbuild workerdin your project — or install globally withnpm install -g --allow-scripts=workerd,esbuild @impetik/xeer. xeer doctorreports on both.
#Next
- Diagnostics reference — every
XE####code. - Manifest reference — every
xeer.app.jsonfield. - Deploy, preview, promote, roll back — the shipping commands in context.