diff --git a/insta/cli-reference.md b/insta/cli-reference.md index 758ace8..8414490 100644 --- a/insta/cli-reference.md +++ b/insta/cli-reference.md @@ -93,7 +93,7 @@ keys and raw request data must not be included in source control or approval rep | `insta domain nameservers set ` · `nameservers reset ` — both take [`--org `] [`--json`] | **(CLI ≥ 0.1.1)** delegate a **bought** domain's zone away from InstaCloud **to nameservers of yours**, or put it back (for InstaCloud's own nameservers use `domain delegate`, above — it keeps hostnames serving; `set` does not). The nameservers are space- or comma-separated and **must already host the zone**, because some registries verify before accepting the change. **`set` takes down every hostname the domain serves**, unless the ones you name are the registrar's own: the records `domain attach` published live in the zone you are leaving, so the platform marks each hostname `failed` with the reason and the CLI prints it — that is the answer, not an error. The published records are **left in place**, because a zone nothing answers from is inert; `reset` un-delegates and `domain attach` re-adopts them, so a hostname `set` took down comes back with an attach, not with the reset alone. While a domain is delegated **away** like this, **`domain attach` is refused** (409), and `domain list`/`status` say so on the domain's own line — a domain on a *managed* zone is not in this state. `reset` from a **managed** zone is the mirror move: record custody returns to the registrar and hostnames a managed zone was serving re-verify on their own. `--json` on both is the whole purchased-domain object. **Agent credentials: both answer 403 `unclassified_agent_action`** — the same org-scoped-write rule as `records` above — so hand the exact command to the user. | | `insta --agent domain zone delegate ` · `zone list` · `zone records ` · `zone release ` — all take [`--org `] [`--json`] | **(CLI ≥ 0.1.4; platform BYO zones)** bring-your-own domains on **nameserver delegation** — the BYO twin of `domain delegate`, for a domain owned at an **outside** registrar (a bought domain has its own `delegate` verb above; the two never mix — a BYO claim of a bought name is a 409 naming the right door). `zone delegate` builds an InstaCloud-managed zone for the domain, seeds it from the provider's public-record **scan** (a HEURISTIC: common type/name combinations, not everything) and answers the **two nameservers** to set at the domain's registrar. From then on `domain attach` publishes its records into the zone itself — **apex included**, which the print-the-records path can never serve. **The contract is review-then-switch**: read `zone records ` (every type shows — CAA, SRV included), add anything missing at your **CURRENT** DNS provider, re-run `zone delegate` (idempotent for the owning org; the re-run re-triggers the import), and only then switch the nameservers — records the review misses drop at the switch. A domain carrying **live MX records is refused outright** (moving mail-bearing DNS can drop mail) — as is a domain bought through InstaCloud, one overlapping an existing delegated tree (one zone covers a whole domain tree), one with an open purchase order, the 201st live zone (a 200-per-org quota), a billing-suspended org (release stays available), and a domain whose registry ALREADY answers from InstaCloud's pair with nothing on file (a TXT proof at `_instacloud-zone-challenge.` is demanded — fails closed on resolver trouble, so it is reachable on a blip). **Every refusal sentence names its fix — read it and relay it**; note two are TRANSIENT retries, not verdicts: "could not be checked for mail records just now" and the resolver-blip proof demand. `zone list` shows `waiting for nameservers` (with the pair) vs `delegated`; activation is the platform's ~minutely sweep noticing the registry switch, not a live probe. `zone release ` prunes what the platform published, deletes the zone, and prints the next step — point the nameservers back at your own provider; hostnames re-verify on the records path. `zone delegate` and `zone release` need **org admin** (a member gets 403 `requires admin role`); `zone list` and `zone records` are member-level reads — any member can run the review step. The platform answers 501 when managed DNS is not enabled on the deployment. **Agent credentials: `zone delegate` AND `zone release` are both gated `zone.delegate` and follow the project's agent policy exactly like `domain.delegate`** — `full_access` executes outright, `branch_specific` answers 202 `approval_required` (relay it, not an error), `read_only` refuses; the two reads follow the ordinary member read path. **The projectless-credential rule on the `domain delegate` row applies here verbatim**: an `insta_` key or MCP assertion with no linked project is judged org-wide and anything less than every-project-`full_access` is refused with a misleading `project.billing.update` denial — run it from a linked project. | | `insta domain transfer lock ` · `transfer code ` — both take [`--org `] [`--json`] | **(CLI ≥ 0.1.1)** take a **bought** domain to another registrar. Two steps on purpose: `lock off` opens the **registrar** transfer lock, `code` reads the **EPP authorization code** the gaining registrar asks for, and the code alone moves nothing. **Both need org `admin`** — a `member` gets 403 — because either hands the domain to someone else. **ICANN's own 60-day lock** on a new registration outranks `lock off` and nothing here can waive it: `lock off` prints the date it is held until, when that is still in force. **Nothing refreshes the row after a transfer completes — not even a read** — so do not report the domain as gone. `--json` is the purchased-domain object for `lock` and `{ authCode }` for `code`; plain output for `code` is the bare code alone on a line, so it can be captured. **Agent credentials: both answer 403**, so hand the commands to the user. | -| `insta --agent compute start\|stop\|suspend [service]` · `insta --agent compute status [service]` [`--json`] | control a compute service's lifecycle — **persistent override** of auto scale-to-zero: `stop`/`suspend` take it offline and traffic will **not** wake it until `start`; `status` shows desired vs. live state. All plans; ungated. `[service]` defaults to the project's sole compute service | +| `insta --agent compute start\|stop\|suspend [service]` · `insta --agent compute status [service]` [`--json`] | control a compute service's lifecycle: `stop` keeps it offline until `start`; a normal `suspend` allows traffic to wake it but does not clear an existing stop; `start` clears the stop; `status` shows desired vs. live state. All plans; ungated. `[service]` defaults to the project's sole compute service | | `insta --agent compute restart [service]` [`--branch `] [`--json`] | **(CLI ≥ 0.0.51)** **re-run the image reference the service already runs**, against a freshly resolved env bundle — it asks for no new version and no new spec, though it does **not pin a digest**: a service recorded against a moving tag (`app:latest`) gets whatever that tag resolves to now (source deploys record a unique label and are unaffected). The two reasons to use it: a binding changed and the running app hasn't picked it up (env is baked into the machine at deploy time — a user secret set with `secrets set`/`unset` redeploys itself and does not need this), or the machine is up but **wedged** (`start` no-ops on a machine that is already `started`). The service must be **running**: a deliberately stopped/suspended one 400s and points at `insta --agent compute start`. A never-deployed service 400s like `exec` does. **A running machine is health-gated coming back up** — if the app doesn't answer on its port the machines are rolled back (best-effort) to the config they were serving and the failure is reported (that verdict means the app is broken, not the platform). Whether an **idle machine (a scale-to-zero service between requests) is woken and gated at all depends on the compute plane** (`insta --agent agent manifest --json` names it per compute row — `insta-compute`, a legacy value, or a neutral `compute` when the platform reported none) — a legacy plane hands it the new config without waking, so the command returns fast, bills no uptime, and proves nothing about whether the app boots. Send it a request if you need that proof; see [operate.md](references/operate.md). All plans; **gated: `deploy`** — it lands configuration the way a deploy does, so a policy denying deploys denies this too; `start`/`stop` stay ungated and cycle a wedged machine without one. Refused while the org is billing-suspended; any machine it wakes bills as ordinary uptime, an idle one it leaves asleep costs nothing. WebSocket concurrency **is** re-asserted (it is recorded on the service), so a socket app does not need a redeploy to stay one | | `insta --agent compute exec [service] -- [args...]` [`--branch `] [`--timeout `] [`--json`] | run a **one-shot** command on the service's live machine — no interactive shell, no stdin. Deploy and exec migrations are separate, non-atomic operations; a 502 can follow execution. Check the migration ledger and final schema before retrying (see [Migration recovery](references/deploy.md#database-migrations)). Wakes a scaled-to-zero machine first (the wake counts as billed uptime). `--timeout` bounds the run, **1–180s** (default 30). At most **64 argv entries (the command included), each ≤ 65,536 characters, ~1 MiB in total** — move a larger payload through storage. The CLI's **exit code is the remote command's exit code** — safe for scripts/agents to branch on. stdout/stderr stream to their own local streams verbatim, each capped at **1 MiB** (truncation noted on stderr); `--json` returns the raw response instead of split streams. Gated on **both** `deploy` and `secrets.read` — a deny on either is a 403. A service with no image ever deployed 400s: "this service has no machines yet — deploy an image first, then retry". **`--api-url ` must come before `compute`** here (`insta --api-url --agent compute exec …`) — everything after `--` is the remote command's own argv | | `insta compute ssh [service]` [`--setup`] [`-b, --branch `] [`--json`] | **(CLI ≥ 0.0.71)** issue a **short-lived SSH certificate** for a compute service and print the `ssh` command that uses it. **It does not open a session** — it makes `ssh` work; you then run the printed command yourself. **Agents cannot use this: it requires an interactive login and refuses API keys (403) — use `insta --agent compute exec` for one-shot commands.** Gated on **both** `compute.shell` and `secrets.read` (a shell inherits the service's decrypted env), and `compute.shell` **defaults to `approve`** for branch-specific agents. Bare = mint a certificate (default **1h**, max 24h) and print a self-contained `ssh -i … -o CertificateFile=… -o IdentitiesOnly=yes @`. `--setup` additionally does the **one-time client setup**: generates a dedicated key at `~/.insta/ssh/id_ed25519` (your own keys are never touched), adds one `@cert-authority` line to `~/.ssh/known_hosts` so every region is trusted without per-node fingerprint prompts, and writes a block **at the TOP of `~/.ssh/config`** (first-obtained-value wins in ssh_config) giving the service the alias **`.insta`**. After that it is plain `ssh api.insta`, `scp` and `-L`: the block renews the certificate while OpenSSH parses the config, so the alias keeps working unattended. An alias already pointing at a **different** project/branch/service is **refused**, not silently repointed. **Compute-plane dependent** — a legacy-plane service has no SSH gateway and 400s naming `compute exec` instead (`insta --agent agent manifest --json` names the plane per compute row). On **Windows** the block omits connection multiplexing, which Win32-OpenSSH does not implement. A fourth flag, `--ensure-cert `, exists but is **internal**: it is the renewal hook the generated config invokes (as `insta __ssh-ensure-cert `) and is silent by design — never call it yourself | diff --git a/insta/references/operate.md b/insta/references/operate.md index 79568d6..3fffeda 100644 --- a/insta/references/operate.md +++ b/insta/references/operate.md @@ -170,12 +170,11 @@ to stop; those constraints lift after deletion. ## Pausing & resuming compute -To take a service **offline on purpose** — a maintenance window, cost control, or parking a -preview branch — use the lifecycle controls, which are a *persistent* override: a stopped/suspended -service will **not** be re-woken by incoming traffic (unlike scale-to-zero's auto-wake). +To keep a service **offline until you start it**, use `compute stop`. A normal `compute suspend` +allows incoming traffic to wake the service; it does not clear an existing stop. - `insta --agent compute stop [service]` — clean shutdown; stays down until `start`. -- `insta --agent compute suspend [service]` — snapshot RAM for a faster resume; stays down until `start`. +- `insta --agent compute suspend [service]` — snapshot RAM for a faster resume; traffic can wake it unless it was already stopped. - `insta --agent compute start [service]` — bring it back online and re-enable auto-wake. - `insta --agent compute status [service]` — desired (your intent) vs. live runtime state.