# CLI specification — command by command **Derived from:** `packages/cli/src/` (actual implementation) · **As of:** 2026-07-10 · Built: `deploy`, `list`, `delete`, `signup`, `activate`, `whoami`, `init`, `inspect`, `plan`, `preview`, `prod`, `approve`, `verify`, `logs`, `rollback`, `feedback` (+ `--version`/`-v`/`version`, `help [command]`). The MCP server (BUILT, see MCP.md) wraps these same command functions. Account/API-key/quota subsystem (B3, SSOT D16): full spec in [ACCOUNTS.md](ACCOUNTS.md). ## Invocation & global behavior ``` openpouch [--json] [--help] ``` - **`--json`**: exactly one JSON object on stdout — no prose, no colors. Errors too: `{"ok": false, "error": {"category", "message", "fix"}}` — categories: `usage`, `env`, `auth`, `quota`, `provider`, **`network`** (the openpouch API could not be REACHED at all — DNS/refused/timeout/TLS; the message names the host + cause and the fix gives a concrete connectivity check like `curl -sS https://openpouch.sh/healthz`, so a sandbox without egress is not mistaken for a broken app — Codex 2026-07-04), `policy-denied`, `approval-required`, `human-required`, `internal` —, plus an optional **`suggestedCommand`** (string) when there is exactly one unambiguous next command to run (e.g. `openpouch init`, `openpouch deploy dist`, `openpouch deploy .`) — so an agent can act on it directly instead of parsing the prose `fix`. It is omitted when the fix is an example, contains placeholders, or offers several options; the `fix` text is always present. Designed for agents; everything below documents these shapes. - Without `--json`: short human-readable lines. - **Universal `summary` field (PRD R3):** every result — success and error, in `--json` and in the MCP tool result — carries a top-level **`summary`** string right after `ok`: plain-language, jargon-free text written for a *non-technical* operator. The agent relays it to its human (verbatim if it likes); it says what happened, whether the app is live and healthy, and what (if anything) the human must do. In human (non-`--json`) output the same text is echoed after a blank line. Generated centrally in `src/summary.ts`. The MCP server additionally surfaces it as a leading `Relay this to your human:` text block (see MCP.md). *(One field is CLI-only: the optional top-level `feedbackHint`, added in the CLI's `render()` on error/dead-end results, is NOT present on MCP tool results — the MCP path never runs `render()`. Every other field, incl. `summary`/`error`/`suggestedCommand`, is identical across CLI `--json` and MCP.)* - **The live link is the primary result (PRD R5):** on a successful deploy the live URL is promoted to a top-level **`url`** field (the instant lane also adds top-level **`claimUrl`**), so an agent never has to dig it out of a nested object before handing it to the human. - **Exit codes:** `0` ok · `1` unexpected failure · `2` usage error · `3` manifest/policy missing or invalid · `4` auth (no/invalid key) · `5` provider error · `6` policy gate (`approval-required`, `policy-denied`, or `human-required`) · `7` deploy reached a terminal failed state · `8` deploy live but smoke/verify failed. - **Providers:** the manifest's per-environment `provider` selects the adapter — `render`, `vercel`, or `openpouch-run` (the instant lane; key **optional** — anonymous by default, or under your account if an openpouch API key is set, B3). See `openpouch deploy` and [INSTANT-LANE.md](INSTANT-LANE.md). - **Tuning env vars:** `OPENPOUCH_POLL_MS` (deploy status poll interval, default 5000 ms) · `OPENPOUCH_DEPLOY_TIMEOUT_MS` (poll timeout, default 600000 ms) · `OPENPOUCH_HOME` (overrides `~` for `.openpouch/` secrets — used by tests) · `OPENPOUCH_KEY_FILE` (full path of the openpouch-run account-key file, overriding the `~/.openpouch/openpouch-run.key` default — honoured by both the reader and `activate`'s writer). - **Key resolution per provider** (never logged; provider comes from the environment's `provider` field in the manifest — the manifest decides the adapter): render → `RENDER_API_KEY` env var, else `~/.openpouch/render.key`; vercel → `VERCEL_TOKEN`, else `~/.openpouch/vercel.token` (+ optional `VERCEL_TEAM_ID` for team scope); **openpouch-run → `OPENPOUCH_API_KEY` env var, else the key file (default `~/.openpouch/openpouch-run.key`, override the path with `OPENPOUCH_KEY_FILE`); absent = anonymous (no Bearer sent), which is fine — the instant lane needs no account (PRD R5)**. `OPENPOUCH_HOME` overrides `~` (tests). Values are passed to the adapter and never appear in output, logs, or files. Missing-key errors are provider-specific. Exception: `init`'s service auto-match is Render-only today. - Launcher: `bin/openpouch.js` is a plain Node script running the compiled build (`dist/main.js`); in the monorepo run `npm run build` first (without a build it exits 1 with that hint). - Usage/help: `openpouch help` or `openpouch --help` prints usage and exits **0**; a bare `openpouch` with no command also prints usage but exits **2** (usage error). An unknown command exits 2. - Version: **`openpouch --version`** (or `-v`, or `openpouch version`) prints `openpouch ` and exits **0**; with `--json` it returns `{"ok": true, "version": ""}`. The version is the published `openpouch` package version, injected into the bundle at build time (so it always matches what was installed). **npm/npx friction (Codex 2026-07-04).** `npx openpouch …` depends on npm's cache; on machines where `~/.npm` is root-owned or unwritable (a common sandbox artifact), `npm install`/`npx` fail before openpouch even runs. Agent-safe workaround — point the cache at a local writable dir: `npm_config_cache=.openpouch-npm-cache npx -y openpouch deploy --json` (or `npm install --cache `). **Two more npx realities (Codex 2026-07-05):** (a) **parallel `npx openpouch` invocations can race the shared npm cache** (`ENOTEMPTY` rename errors) — run npx calls sequentially, or preinstall once so later calls skip npm entirely (`npm i -g openpouch`, or project-local `npm i -D openpouch` + `npx --no-install openpouch …`); (b) **every cold `npx` needs registry access** (including `npx openpouch --help`) — in offline/network-gated sandboxes preinstalling is the only robust path. This is environment friction, not an openpouch error, so openpouch can't fix it from inside; the same notes live in the website `llms.txt` so agents find them during discovery. **(c) npm's own update notices** print to stderr around openpouch's clean single-JSON stdout — harnesses that MERGE streams can see them interleaved with the JSON (Codex suite smoke 2026-07-05); when strict parsing matters, set `npm_config_update_notifier=false` (or preinstall, which skips npm at run time entirely). **Command-specific help (OpenClaw 2026-07-04).** `openpouch --help` and `openpouch help ` print that command's OWN page — usage line, applicable flags, one example, and the most common failure with the next command to run (every `--help` used to print the same global page, so an agent probing for exact syntax had to infer). Bare `--help` / `help` keep the global page; `help ` exits 2 and falls back to the global usage. With `--json` the help arrives as `{ok, command, help: [lines]}`. ## `openpouch deploy [dir] [--json]` Zero-config **instant lane** (SSOT D11): packages a folder and deploys it to an anonymous ephemeral preview on openpouch's own infra — no account, no provider key, no manifest. The optional **`dir`** positional picks the folder (default: the current directory) — e.g. `openpouch deploy dist` ships a framework build output in one flow (`npm run build && openpouch deploy dist`, no `cd`). Returns a live `https://.openpouch.sh` URL, a `claimUrl`, and an `expiresAt` (unclaimed previews vanish after 72 h). Writes the deployment truth back into the **project root** (`deploy.manifest.json` with `preview` → provider `openpouch-run`, `deploy.policy.json`, `deploy.evidence.json`, `DEPLOYMENT.md`). > **Claim-token privacy:** the `claimUrl` carries a single-use claim token — anyone who has that link can claim the preview, so it is a secret. It is kept out of everything that gets committed or relayed: **`deploy.evidence.json` and `DEPLOYMENT.md` do NOT contain it** (the evidence `notes` only points at where it lives), and the plain-language `summary` (written to be relayed to a human verbatim) never contains it either — so an agent can't leak it by pasting the summary into a public report/chat (Balerion/Claude 2026-07-01, hardening the OpenClaw 2026-06-29 flag). The full link is persisted to **`.openpouch/claim.json`** (`0600`; `.openpouch/` is auto-gitignored — local runtime state, never repo history) and is carried in the deploy `--json` as top-level **`claimUrl`** with **`claimUrlIsPrivate: true`**. So an agent relays the shareable **`url`**, and hands the human the `claimUrl` privately (re-readable later from `.openpouch/claim.json`). **Redeploy semantics (each instant deploy is a fresh preview).** Running `deploy` again in a folder whose `deploy.manifest.json` was written by the instant lane (every env provider `openpouch-run`) **redeploys** — it does not error — so agents iterate deploy → fix → deploy. **But every instant deploy produces a NEW ephemeral URL/slug** (72 h, unclaimed): the instant lane has no in-place "update the same URL" primitive; the manifest is rewritten to point at the newest deploy. To keep one specific preview around longer, **`claim`** it — claiming extends it from 72 h to **7 days** (a claim link comes back with every deploy — see workflow 4); for a stable, *updatable* target, use the **governed lane** (bring-your-own Render/Vercel via `preview`/`prod`), whose URL is fixed. `deploy` only *refuses* (exit 2) when a **governed** manifest exists (an env with a `render`/`vercel` provider) → those projects use `preview`/`prod` instead. (A present-but-invalid manifest doesn't block and is overwritten.) **Unbuilt-frontend guard:** deploying the current folder **without an explicit `dir`** is refused (exit 2) when it looks like an *unbuilt* frontend source tree — an `index.html` referencing source modules (e.g. `