CLI reference
npx @impetik/xeer --help
npx @impetik/xeer --versionRoot help lists each top-level command once. Use xeer <command> --help for one command or
xeer <command-group> --help to discover its subcommands; xeer help <command> is equivalent.
Inside 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.
Each command accepts only the options shown in its usage line. An unknown option, a missing option
value, or a value assigned to a boolean flag exits 2 with XE0002 before the command can write a file,
start a runtime, or make a network request. In particular, xeer deploy targets production by default:
preview deployment is xeer deploy --environment preview; --preview is deliberately rejected.
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 root, command-group, or command-specific help. |
--control-url <url> | Talk to a different Xeer control plane. Must be HTTPS except on loopback. XEER_CONTROL_PLANE_URL does the same, and the flag wins when both are set; either outranks the origin recorded in your stored credential. |
#Agent setup
xeer agent setup [directory] [--target auto|agents|claude|codex|cursor|vscode|mcp] [--check] [--json]Installs deterministic, project-local discovery files and a version-matched MCP configuration.
auto covers portable AGENTS.md discovery, the Claude-compatible projection, and MCP. --check
never writes: it exits non-zero with XE3101 for missing or stale generated files, or XE3102 when a
selected path is not owned by Xeer. A normal setup also refuses every write when any path conflicts.
The JSON result is xeer.agent-setup.v0 and lists only project-relative paths with create, update,
keep, or conflict actions.
#Agent context
xeer agent context [directory] [--json]Reads the bounded xeer.agent-context.v0 view: installed framework and docs versions, normalized
application metadata, source zones, capabilities, budgets, schema, discovered operations, diagnostics,
test inventory, safe next actions, MCP resources, and a stable contextHash. It uses the same analyzers
as check but supplies the generated contract in memory, so it never writes .xeer/generated. Paths are
project-relative; source text, secrets, state rows, logs, timestamps, machine names, and absolute paths
are excluded.
#Documentation search
xeer docs search <query> [--limit <n>] [--json]Searches the compact index bundled with this exact CLI version using deterministic lexical ranking.
Results identify on-demand Markdown pages by canonical URL and content hash. --limit accepts 1 through
20 and defaults to 5.
#Machine action catalogue
xeer actions [--json]Returns the complete xeer.actions.v0 registry inside the normal xeer.command.v0 envelope. Every
canonical CLI and MCP action declares its effects, idempotence, reversibility, destructive status,
human prerequisites, path policy, output protocol, and surface availability. The catalogue includes
service-token commands that are deliberately hidden from general human help, and each action absent
from MCP records why. Automation should use this catalogue instead of inferring safety from prose.
The MCP author profile is preview-only regardless of CLI compatibility defaults: it exposes
xeer_deploy_preview and no production-changing tool. Starting MCP with XEER_MCP_PROFILE=operator
adds exact-artifact promotion; the profile cannot be changed by a tool argument.
MCP tools (15 total; 14 author, 15 operator). Inputs ending in ? are optional.
| Tool | Action | Profiles | Summary | Inputs | Effects | Safety | Path policy | Output | Human prerequisite |
|---|---|---|---|---|---|---|---|---|---|
xeer_check | check | author / operator | Validate a project and report structured diagnostics. | directory?: string | read-sourcewrite-generated | writes; idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | none |
xeer_build | build | author / operator | Build and verify a content-addressed project artifact. | directory?: string | read-sourcewrite-generatedrun-local | writes; idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | none |
xeer_test | test | author / operator | Run the project test suite and record review evidence. | directory?: stringtimeoutMilliseconds?: integer [1000..1800000] | read-sourcewrite-generatedrun-localwrite-state | writes; idempotent; reversible; non-destructive | project-relative | xeer.dev.v0 | none |
xeer_new | new | author / operator | Create a new project from a supported scaffold. | directory: stringtemplate?: stringframework?: sveltekitui?: preact / react | write-sourcenetwork-read | writes; non-idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | none |
xeer_agent_context | agent.context | author / operator | Read normalized project facts, operations, diagnostics, tests, and safe next actions. | directory?: string | read-source | read-only; idempotent; reversible; non-destructive | project-relative | xeer.agent-context.v0 | none |
xeer_docs_search | docs.search | author / operator | Search the installed-version Xeer documentation index. | query: stringlimit?: integer [1..20]; default 5 | none | read-only; idempotent; reversible; non-destructive | none | xeer.docs-search.v0 | none |
xeer_doctor | doctor | author / operator | Diagnose the toolchain and generated project state. | directory?: string | read-sourcewrite-generated | writes; idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | none |
xeer_deploy_preview | deploy.preview | author / operator | Build and deploy an artifact to preview only. | directory?: stringcontrolUrl?: string | read-sourcewrite-generatedrun-localnetwork-readnetwork-write | writes; non-idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | A human must establish the builder credential with xeer auth login, or issue the service token supplied in XEER_SERVICE_TOKEN. |
xeer_promote | promote.operator | operator | Promote an exact review receipt in operator mode. | directory?: stringreceiptId: stringcontrolUrl?: string | network-readnetwork-writeproduction-change | writes; non-idempotent; reversible; non-destructive | project-or-url | xeer.command.v0 | A human must review the exact artifact and start xeer-mcp with XEER_MCP_PROFILE=operator. |
xeer_auth_status | auth.status | author / operator | Report builder credential metadata. | controlUrl?: string | network-readsecret-metadata | read-only; idempotent; reversible; non-destructive | none | xeer.command.v0 | none |
xeer_inspect | inspect | author / operator | Read a running application manifest. | previewUrl: stringview?: manifest / state / logs / export; default manifestafter?: string | network-readread-state | read-only; idempotent; reversible; non-destructive | app-or-url | xeer.command.v0 | none |
xeer_dev_start | dev.start | author / operator | Start a local development session. | directory?: stringhost?: stringport?: integer [0..65535]share?: booleantimeoutMilliseconds?: integer [1000..600000] | read-sourcewrite-generatedrun-localwrite-statenetwork-readnetwork-write | writes; non-idempotent; reversible; non-destructive | project-relative | xeer.dev.v0 | none |
xeer_dev_status | dev.status | author / operator | Read new events from a local development session. | sessionId?: stringcursor?: integer [0..9007199254740991]; default 0waitMilliseconds?: integer [0..600000]; default 0limit?: integer [1..1000]; default 200 | none | read-only; idempotent; reversible; non-destructive | none | xeer.dev.v0 | none |
xeer_dev_stop | dev.stop | author / operator | Stop a local development session and release its lease. | sessionId?: stringcursor?: integer [0..9007199254740991]; default 0 | run-local | writes; idempotent; reversible; non-destructive | none | xeer.dev.v0 | none |
xeer_diagnostics | diagnostics | author / operator | Explain one emitted diagnostic code. | code: string | none | read-only; idempotent; reversible; non-destructive | none | xeer.command.v0 | none |
CLI actions intentionally excluded from MCP (36).
| CLI action | Action | Summary | Effects | Safety | Path policy | Output | Why no MCP tool |
|---|---|---|---|---|---|---|---|
xeer init | init | Initialize Xeer in an existing SvelteKit project. | read-sourcewrite-sourcerun-localnetwork-read | writes; idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer agent setup | agent.setup | Install or verify project-confined agent adapters. | read-sourcewrite-source | writes; idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer deploy | deploy | Build and deploy a project artifact. | read-sourcewrite-generatedrun-localnetwork-readnetwork-writeproduction-change | writes; non-idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | MCP exposes a separate preview-only deploy action; direct production deploy stays CLI-only. |
xeer promote | promote | Promote a preview artifact to production. | network-readnetwork-writeproduction-change | writes; non-idempotent; reversible; non-destructive | project-or-url | xeer.command.v0 | MCP promotion is a separate action available only when the server starts in operator profile. |
xeer tunnel | tunnel.start | Expose a loopback HTTP server through an authenticated tunnel. | run-localnetwork-readnetwork-write | writes; non-idempotent; reversible; non-destructive | none | xeer.tunnel.cli.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer link | link | Link a checkout to an application the builder owns. | read-sourcewrite-sourcenetwork-readnetwork-write | writes; non-idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | Human identity and project ownership decisions are not delegated through MCP. |
xeer deployments | deployments | List deployment history for an application. | network-readread-statesecret-metadata | read-only; idempotent; reversible; non-destructive | project-or-url | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer rollback | rollback | Redeploy a previously deployed artifact. | network-readnetwork-writeproduction-change | writes; non-idempotent; reversible; non-destructive | project-or-url | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer disable | disable | Take an application offline without deleting its data. | network-readnetwork-writeproduction-change | writes; idempotent; reversible; non-destructive | project-or-url | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer enable | enable | Restore a disabled application to service. | network-readnetwork-writeproduction-change | writes; idempotent; reversible; non-destructive | project-or-url | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer delete | delete | Permanently delete an application and all of its data. | network-readnetwork-writewrite-stateproduction-change | writes; non-idempotent; irreversible; destructive | project-or-url | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer domains add | domains.add | Attach a customer-owned hostname to an application. | network-readnetwork-writeproduction-change | writes; idempotent; reversible; non-destructive | project-or-url | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer domains ls | domains.ls | List an application's platform and custom domains. | network-read | read-only; idempotent; reversible; non-destructive | project-or-url | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer domains status | domains.status | Refresh hostname and certificate validation. | network-readnetwork-writeproduction-change | writes; idempotent; reversible; non-destructive | project-or-url | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer domains remove | domains.remove | Detach a custom hostname and delete its provider certificate. | network-readnetwork-writeproduction-change | writes; idempotent; reversible; destructive | project-or-url | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer preview | preview | Run a verified artifact in a local preview server. | read-sourcewrite-generatedrun-localwrite-state | writes; non-idempotent; reversible; non-destructive | project-relative | xeer.dev.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer state | state.read | Read record counts from a running application. | network-readread-state | read-only; idempotent; reversible; non-destructive | app-or-url | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer state reset | state.reset | Permanently reset local environment state. | read-sourcewrite-state | writes; non-idempotent; irreversible; destructive | project-relative | xeer.command.v0 | Destructive state replacement requires an explicit CLI invocation. |
xeer logs | logs | Read the bounded log ring of a running application. | network-readread-state | read-only; idempotent; reversible; non-destructive | app-or-url | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer export | export | Export application state to a document. | network-readread-statewrite-file | writes; idempotent; reversible; non-destructive | project-or-url | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer import | import | Replace local or preview state from an export document. | read-sourcenetwork-writewrite-state | writes; non-idempotent; irreversible; destructive | project-or-url | xeer.command.v0 | Destructive state replacement requires an explicit CLI invocation. |
xeer auth login | auth.login | Establish a human builder credential. | network-readnetwork-writesecret-write | writes; non-idempotent; reversible; non-destructive | none | xeer.command.v0 | Human identity and project ownership decisions are not delegated through MCP. |
xeer auth logout | auth.logout | Remove the local builder credential. | network-writesecret-write | writes; idempotent; reversible; non-destructive | none | xeer.command.v0 | Human identity and project ownership decisions are not delegated through MCP. |
xeer auth as | auth.as | Select a deterministic local development persona. | write-state | writes; idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer auth clear | auth.clear | Reset the local development persona. | write-state | writes; idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer env set | env.set | Set an environment value or secret. | network-writewrite-statesecret-write | writes; idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | Secret values are intentionally unreachable through MCP; env pull returns plaintext. |
xeer env ls | env.ls | List environment variable names and metadata. | network-readsecret-metadata | read-only; idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | Secret values are intentionally unreachable through MCP; env pull returns plaintext. |
xeer env rm | env.rm | Remove an environment value or secret. | network-writewrite-statesecret-write | writes; idempotent; irreversible; destructive | project-relative | xeer.command.v0 | Secret values are intentionally unreachable through MCP; env pull returns plaintext. |
xeer env pull | env.pull | Write development secrets to a local file. | network-readwrite-filesecret-read | writes; idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | Secret values are intentionally unreachable through MCP; env pull returns plaintext. |
xeer token create | token.create | Issue a service builder token. | network-writesecret-write | writes; non-idempotent; reversible; non-destructive | none | xeer.command.v0 | Service credential issuance and revocation are intentionally CLI-only. |
xeer token ls | token.ls | List service token metadata. | network-readsecret-metadata | read-only; idempotent; reversible; non-destructive | none | xeer.command.v0 | Service credential issuance and revocation are intentionally CLI-only. |
xeer token revoke | token.revoke | Revoke a service builder token. | network-writesecret-write | writes; idempotent; irreversible; destructive | none | xeer.command.v0 | Service credential issuance and revocation are intentionally CLI-only. |
xeer actions | actions | Print the machine-readable action and safety catalogue. | none | read-only; idempotent; reversible; non-destructive | none | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer db tables | db.tables | List the tables of a running application database. | read-state | read-only; idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer db schema | db.schema | Print the declared schema of a running application database. | read-state | read-only; idempotent; reversible; non-destructive | project-relative | xeer.command.v0 | Not exposed through MCP v0; use the CLI deliberately. |
xeer db exec | db.exec | Run one SQL statement against a running application database. | read-statewrite-state | writes; non-idempotent; irreversible; non-destructive | project-relative | xeer.command.v0 | Destructive state replacement requires an explicit CLI invocation. |
#Build and check
#xeer new
xeer new [directory] [--template <id>] [--framework sveltekit] [--ui preact|react] [--json]Without a catalog id or framework, scaffolds a bundled Xeer application with a manifest, typed server, client, styles, favicon, and passing tests. The target directory defaults to the current directory and must be empty or nonexistent. The project name is derived from the directory name, lowercased and slugified.
The four bundled starters work offline and accept --ui. Any other exact --template id is looked
up in the public catalog after the target check. Catalog templates own their project kind and renderer,
so --ui with one is XE3013.
--framework is the other axis, not one of the template values: it writes a project Xeer runs
rather than compiles, so it is exclusive with both of the above. --template alongside it is
refused with XE3005, and a framework name Xeer cannot scaffold with XE3006.
--template defaults to the bundled notes starter:
| 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. |
All four are Xeer applications: they check, test, and build 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 persistent account. See Auth. With --json,
the result is { directory, name, files, template, ui }. A catalog install returns
{ directory, name, files, template, projectKind, platformVersion, artifactVersion }, plus
framework when projectKind is framework. Catalog results do not contain ui. XE3002 means
neither the bundled names nor the reachable catalog contained the exact id.
#SvelteKit projects
xeer new [directory] --framework sveltekit [--json]| Framework | |
|---|---|
sveltekit | A SvelteKit app on the Cloudflare adapter: Xeer owns config, deploy, and the tunnel. |
The other root contract Xeer understands. It writes
xeer.config.json instead of xeer.app.json, so every later command delegates to the project's own
package.json scripts rather than compiling a manifest — the same state
xeer init reaches by retrofitting an existing project.
xeer new my-kit-app --framework sveltekit
cd my-kit-app
npm install
npx xeer devWhat it writes: xeer.config.json, xeer.project.json, wrangler.jsonc naming
.svelte-kit/cloudflare, a package.json declaring dev, build, check, and test, a
vite.config.ts carrying the SvelteKit 3 RC, Vite 8, @sveltejs/adapter-cloudflare, remote-function
flags, and the Vitest configuration. The starter route calls and refreshes a server-only query from
src/lib/greeting.remote.ts; its shared module uses SvelteKit 3's #lib package import and has a
passing test. It also gets the same agent adapters as every Xeer scaffold.
- Install first. No
packageManagerfield is written, so Xeer detects the manager from the lockfile your install produces andpnpm,yarn, andbunwork exactly as well asnpm. Before the install there is no lockfile and nothing to run, and every framework command refuses withXE3204naming the install. --uidoes not apply and is refused withXE3004before anything is written. SvelteKit owns the renderer; there is noclient.runtime.providerto select.result.templateandresult.uiare both absent from the JSON, andresult.frameworknames what was written instead.versioninpackage.jsonis the SvelteKit release name. The scaffold pins it there because SvelteKit's default isDate.now(), which would give two builds of unchanged source two differentartifactIds — and the review evidencexeer testrecords is keyed to one of them.- No declared database, no storage bindings, and no
ctx.authin a+page.server.ts. The capabilities inxeer.config.jsonare provisioned by the control plane; a framework project brings its own datastore and its own request-level authentication. xeer preview,inspect,state, andlogsrefuse withXE3208, naming the alternative.xeer agent contextreturns a context withvalid: falseand a nestedXE3208diagnostic.
--ui defaults to preact and applies to the application templates only:
| UI provider | |
|---|---|
preact | The default. Writes no client block at all, so the project is identical to one scaffolded without the flag. |
react | Writes "client": { "runtime": { "provider": "react" } } into the manifest. The client sources are the same bytes under either provider; tsconfig.json differs only in paths, which is where the editor learns which renderer those sources mean, and the README names the provider. Nothing else on disk changes. |
The renderer is the platform's under both, so the scaffold declares no renderer in its own
dependencies. An unknown --ui value is refused before anything is written, the way an unknown
--template is. With --json, result.ui reports which provider was selected. See
client for what the manifest field means and
The client for what changes at runtime.
#xeer init
xeer init [directory] [--dry-run] [--json]Initializes the SvelteKit integration in an existing project. To start a new one instead, use
xeer new --framework sveltekit, which writes the same
xeer.config.json without running Wrangler setup. Detection reads
package.json, not node_modules, and reports the package manager and declared SvelteKit adapter.
--dry-run returns the xeer.init.v0 Xeer plan without writing. Applying it runs Wrangler setup when
needed, admits workerd's install script under pnpm, generates Cloudflare types, and creates
xeer.config.json. Xeer preserves the app's existing dev, check, test, and build scripts,
tsconfig.json, src/app.d.ts, routes, and hooks. An identical Xeer configuration is kept on later
runs and an existing different file is refused with XE3202.
For initialized framework projects, xeer check, build, test, and dev delegate to the native
package scripts. xeer dev --share adds Xeer's authenticated raw HTTP tunnel. xeer test runs the
package's test script and records the review evidence xeer promote requires.
xeer deploy runs the native build and packages the official Cloudflare adapter Worker and assets
for the Xeer control plane. xeer preview, inspect, state, and logs read a Xeer application
contract a framework project does not have and refuse with XE3208, naming the alternative.
xeer agent context returns valid: false with the diagnostic inside its context result. See
docs/SVELTEKIT_POC.md in the framework repository for what stays out of scope:
D1 and storage bindings, and request-level Xeer auth inside SvelteKit handlers.
#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, client npm imports are declared in
dependencies and installed, routes do not collide. Runs nothing. This is the fast inner-loop command;
exit 0 means the project is well-formed. One dependency problem is a property of bundling and can
only surface at xeer build: a dependency whose import chain reaches a Node builtin
(XE1502). A path import that would place a second renderer copy in the bundle (XE1503) is caught
here, at the import itself, and again by the build's own verification.
#xeer diagnostics
xeer diagnostics <XE####> [--json]Explains one diagnostic code that a command just emitted. Read the diagnostic's message, file, span, and hint first; use this command only when that exact code needs more context. It never prints the full diagnostic catalogue.
#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>] [--share] [--control-url <url>] [--tunnel-bootstrap <file>] [--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.
--share allocates a short-lived public development URL after authenticating
through the selected control plane. It keeps the runtime on loopback, disables
builder/admin surfaces on the shared path, exposes one tunnel-scoped guest
identity, and mirrors failed rebuild diagnostics into the browser while the
last accepted generation continues serving. Use --control-url to select the
same control plane your CLI credential belongs to.
An external trusted sandbox harness can allocate outside hostile code and pass
--share --tunnel-bootstrap <file>. This bypasses CLI account lookup and accepts only the agent
ticket, narrow resume secret, and public tunnel metadata. The file must not contain the allocator's
control secret and must not be group- or world-readable on POSIX systems. This option cannot be
combined with --control-url.
Uses local personas instead of real sign-in, and a local database that persists between runs.
#xeer tunnel
xeer tunnel <port|loopback-url> [--label <name>] [--host-header <preserve|rewrite|host>] [--request-header-add <name:value>] [--request-header-remove <name>] [--response-header-add <name:value>] [--response-header-remove <name>] [--upstream-tls-insecure] [--lifetime <seconds>] [--control-url <url>] [--json]Run xeer tunnel --help for target examples, option descriptions, runtime behavior, and the raw
tunnel security boundary.
Publishes an arbitrary loopback HTTP server through the authenticated tunnel
relay. Targets can be a port (3000), loopback address ([::1]:8787), or
exact HTTP/HTTPS loopback origin (https://localhost:8443). HTTP, streaming
responses such as SSE, and WebSockets use the same reconnecting, flow-controlled
transport as dev --share.
Raw mode preserves application authorization headers, cookies, Set-Cookie,
and all application routes. It adds standard X-Forwarded-* metadata and
preserves the public Host by default; use --host-header rewrite for servers
that require the loopback host. Header add/remove options are repeatable.
Self-signed loopback HTTPS requires the explicit --upstream-tls-insecure
opt-out. The process prints completed-request metadata and --json emits
xeer.tunnel.cli.v0 JSONL. Stop it with Ctrl+C to release the public URL.
Unlike dev --share, a raw tunnel does not strip application credentials,
block builder routes, inject a Xeer guest capability, or offer durable-preview
fallback/embed controls. The target application owns authentication, CSRF,
cookie policy, and host validation.
#xeer preview
xeer preview [directory] [--host <host>] [--port <port>] [--force] [--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. The
document is served byte-for-byte as built — no dev-server transform, no injected client script — so what
you preview is what deploys.
A preview owns its project's preview state for as long as it runs. If a previous run was killed
ungracefully, its lease is reclaimed automatically once that process is gone. --force takes the lease
even when the recorded pid still looks alive, which is what you want when that pid has been reused by
something else and not what you want while a real preview is running: two writers on one state directory
is the situation the lease exists to prevent.
#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. In human mode it 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.
Do not use --json for interactive login in this release. That mode suppresses the URL and code while
the approval page still requires the code, so the hosted flow cannot complete. This is a known CLI defect.
--control-url (or XEER_CONTROL_PLANE_URL) pins the whole sign-in: the authorization, the poll, and
the origin recorded in the credential. The verification URL comes from the control plane itself, so if it
arrives on a different address you get a warning on stderr rather than a refusal — a plane may legitimately
answer at more than one address, and the CLI cannot tell that apart from a plane misconfigured to point at
another deployment.
A sign-in that expires before you approve it fails with XE5005 and stores nothing — so the credential
you already had, and the control plane it points at, are still the ones in use. If the verification URL
was on another address, the expiry says so too: that is the likely reason the approval never arrived.
#xeer auth status
xeer auth status [--control-url <url>] [--json]Verifies the active credential and prints who you are signed in as, when it expires, and which control
plane it is for. XEER_SERVICE_TOKEN takes precedence over the stored file. A service token reports its
server-side id and label and has no expiry.
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.
Your stored credential is sent to whichever control plane the command was pointed at, because a token is valid at every address its issuing plane answers to and nothing here can tell a second address apart from a second plane. When the plane refuses it, the refusal names where the credential came from:
XE5004 CLI credential is invalid or expired.
Your stored credential was issued by https://control.xeer.run, not https://staging-control.xeer.run.
Run `xeer auth login --control-url https://staging-control.xeer.run` to sign in there.With --json, the result is
{ builder, expiresAt, controlOrigin, credential: { kind, tokenId, label, expiresAt, source } }.
#xeer auth logout
xeer auth logout [--control-url <url>] [--json]Revokes the stored human credential at the control plane and deletes the local file. When
XEER_SERVICE_TOKEN is set, logout refuses and leaves the stored human credential untouched. Unset the
environment variable to use the stored credential, or revoke the service token by id.
#xeer auth as / xeer auth clear
xeer auth as <alice|bob|carol> [directory] [--workspace <id>]… [--role <name>]… [--permission <name>]… [--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, --role, and --permission are each repeatable and each value may be comma-separated.
They are 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. A plain local
signIn() restores the complete default; an explicit persona selects that persona holding nothing
unless it also supplies workspace ids, roles, or permissions. See Local
personas.
#xeer token create / xeer token ls / xeer token revoke
xeer token create --name <label> [--control-url <url>] [--json]
xeer token ls [--control-url <url>] [--json]
xeer token revoke <tokenId> [--reason <why>] [--control-url <url>] [--json]token create requires an interactively signed-in builder. It prints the xst_ secret once and returns
its non-secret xstid_ id. Store the secret in the service's secret store as XEER_SERVICE_TOKEN.
Service tokens are full-builder credentials with no scopes and no expiry. They cannot issue another
service token, but they can list and revoke tokens owned by the same builder.
token ls returns metadata for active and revoked tokens and never returns a secret. token revoke
takes the xstid_ id from that list and stops the token on its next request. A missing network response
after token create is ambiguous, so run token ls before repeating the create command.
#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] [--receipt <receiptId> | --from-artifact <artifactId>] [--control-url <url>] [--json]Makes a reviewed preview artifact live on production — the same bundle, not a rebuild — using
production's own environment values. --receipt verifies the exact active preview, its reported tests,
and retained source identity. --from-artifact is the separate direct human override for a retained
version. 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.
#xeer domains
xeer domains add <hostname> [app|directory] [--control-url <url>] [--json]
xeer domains ls [app|directory] [--control-url <url>] [--json]
xeer domains status <hostname> [app|directory] [--control-url <url>] [--json]
xeer domains remove <hostname> [app|directory] [--control-url <url>] [--json]Attaches customer-owned hostnames to a production deployment through Cloudflare for SaaS. add returns
the CNAME target and the separate ownership and certificate TXT records; status refreshes their state
and reports active only when both hostname routing and TLS are active. remove makes routing dark first,
then deletes the provider hostname and certificates. If that cleanup is temporarily unavailable it exits
with XE5197; repeat the same remove command. Reattachment remains blocked until cleanup is confirmed.
Ownership validation and certificate DCV are separate stages, so certificate TXT records can appear after
the ownership record is accepted. Multiple certificate TXT values may share one _acme-challenge name;
create a separate DNS record for every returned value and keep them together until status and
providerSslStatus are both active and nextAction is ready.
Each builder has a configurable custom-domain allowance (10 by default). There is intentionally no
platform-wide cap: once the Cloudflare zone exceeds its included hostname allowance, additional-hostname
billing applies. ls includes both the generated platform origin and attached custom hostnames.
#Inspect
#xeer inspect / xeer state / xeer logs
xeer inspect <local-url|app|directory> [--environment prod|preview] [--control-url <url>] [--json]
xeer state <local-url|app|directory> [--environment prod|preview] [--control-url <url>] [--json]
xeer logs <local-url|app|directory> [--environment prod|preview] [--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 project directory — ., or any explicit path — reads whichever xeer dev or xeer preview server is
running for it, resolved from the lease that run holds, so the URL never has to be copied out of the
preview.ready event. If both a dev and a preview server are running for that directory it names neither,
and the command says so rather than guessing. A local xeer dev or xeer preview URL is read directly.
Neither form accepts --environment. A
deployed app is read through the control plane on your credential: a deployed inspector answers nobody
else. An app name or appId defaults to production; pass --environment preview for the preview slot. An
exact active deployed URL selects its own environment. Pairing a preview URL with --environment production
(or the reverse) is refused instead of silently reading the other slot. Human output labels the environment;
--json carries it beside the selected view so preview and production state or logs cannot be confused.
#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 <local-url|app> [--environment prod|preview] [--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. It follows the
same environment rule as the inspector commands: name/appId defaults to production, an exact deployed URL
selects its slot, and --environment preview selects preview explicitly. 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.
#Query the database
#xeer db
xeer db tables [directory] [--state <dev|preview>] [--json]
xeer db schema [directory] [--state <dev|preview>] [--json]
xeer db exec [directory] <sql> [--state <dev|preview>] [--write] [--json]Runs against the xeer dev / xeer preview server for that directory, through the same admin surface
the local editor uses. There is no deployed target: the secret it authenticates with is minted per run
and dies with the server that made it.
db exec takes one statement. Only the last statement of a batch may carry parameters and only its
rows come back, so a batch would silently discard results you asked for.
Reads run by default; anything that changes a row needs --write. Two things are refused whether or not
you pass it:
- DDL —
CREATE,ALTER,DROP. The runtime reconciles the physical schema against the DDL it recorded, so changing it from outside leaves the two disagreeing with nothing able to notice. Schema changes belong in the manifest. - Assignable pragmas. Only introspection pragmas run. One of the others switches
CHECKenforcement off, which would let a statement write exactly the values your generated types say cannot exist.
Ordinary UPDATE and DELETE are allowed with --write, and are safer than they look: the schema's
CHECK, NOT NULL, UNIQUE and foreign-key constraints bind every writer, not just your handlers.
Writes to the runtime's own tables are refused; reading them is not.
#Environment values
#xeer env
xeer env set <NAME> [value] [--environment prod|preview|dev] [--dir <directory>] [--control-url <url>] [--json]
xeer env ls [--environment prod|preview|dev] [--dir <directory>] [--control-url <url>] [--json]
xeer env rm <NAME> [--environment prod|preview|dev] [--dir <directory>] [--control-url <url>] [--json]
xeer env pull [--environment prod|preview|dev] [--dir <directory>] [--control-url <url>] [--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. |
XEER_SERVICE_TOKEN | Non-interactive service builder credential. It takes precedence over a stored CLI credential. |
#Network failures and re-running
Every command that reaches the control plane shares one bounded transport. Any HTTP response is
final — a 429 or a 500 becomes a diagnostic, never a silent retry. Only a request that got no response
at all is retried, and only where replaying it is safe: reads and idempotent operations such as link's
project listing, deployments, inspect, domains, disable/enable, and auth status make up to
three attempts with sub-second backoff. deploy, promote, rollback, delete, env rm, and
token create make exactly one, because a lost response is indistinguishable from a lost mutation.
So when the network drops: re-run a read freely, but read state before repeating a write. xeer deployments shows what each environment serves, and re-running deploy records a second deployment of
the same artifact — safe, but not free. Never work around a failing xeer link by deploying an unlinked
directory: deploy mints a fresh appId there, leaving you a second application with none of the
first one's data or domains.
The full contract, including a retry recipe for scripts, is in
.agents/skills/xeer/references/command-protocols.md.
#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.