From 1e4c710b3ab813becfb77cc555c10fb06faa6f1c Mon Sep 17 00:00:00 2001 From: CarmenDou <15951653662@163.com> Date: Tue, 6 Oct 2026 00:01:56 -0700 Subject: [PATCH 1/4] docs(insta): manifest pgVersion, storage buckets and strict service keys The template manifest section shows a postgres pgVersion and a public storage bucket bound through env.platform, lists the five storage keys, and adds the storage and unknown-key rows to the rules table with the CLI version floor for storage. A bucket takes no region. --- insta/cli-reference.md | 47 ++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/insta/cli-reference.md b/insta/cli-reference.md index ccc2215..a65cb2e 100644 --- a/insta/cli-reference.md +++ b/insta/cli-reference.md @@ -82,8 +82,8 @@ keys and raw request data must not be included in source control or approval rep | `insta --agent build [dir]` [`--explain`] [`--port `] [`--json`] | **verify before you deploy** — local, offline, deploys nothing, needs no login: prints the detection plan (builder, install/build/start commands, port **with the reason it was chosen**, `.env.example` keys), the Dockerfile (yours, or — **if nixpacks is installed**, never auto-installed — the one nixpacks would generate; `--explain` includes its content), and static checks each with a next action (missing Dockerfile/start command, port mismatch, `node_modules` shipping in the build context). **Verdict semantics (CLI ≥ 0.0.48): only a Dockerfile IN the directory can make a dir `deployable`.** A dir with no Dockerfile where nixpacks detects the app gets `builder: nixpacks` but its Dockerfile check is a ⚠ warning and the verdict stops at `needs-attention` (exit 0) — the command is local and cannot know which compute plane the target runs on, and the answer differs: an insta-compute service deploys such a dir as-is (the gateway runs nixpacks), a legacy-plane one refuses it. Read `needs-attention` as "depends on the target", not as "will fail". The nixpacks Dockerfile shown by `--explain` is **for inspection, not standalone** (it `COPY`s `.nixpacks/` support files the dir does not have) — do NOT save it as `Dockerfile`; use the detected install/start commands as the starting point for your own. Verdict `failed` (exit 1) = no Dockerfile and nixpacks missing/undetected, or no start command. For a Dockerfile-less dir that `failed` says only that nixpacks is not installed on THIS machine: an insta-compute target still deploys it, because the gateway runs nixpacks, so do not add a Dockerfile just to satisfy the local check. Run it before `insta --agent deploy ` instead of finding out from a burned remote build | | `insta --agent build logs ` [`--source `] [`--follow`] [`--json`] | read output from a **source build** — the remote build a `deploy`/`compute connect-repo` push kicked off, not the local, offline `build` check above. `--source archive` (default) reads a **deploy operation's** build: `` is that operation id, printed as soon as `insta --agent deploy` accepts the operation (stderr with `deploy --json`). `--source github` reads a **GitHub-triggered** build: `` is the GitHub build id — read `build.buildId` from `insta --agent compute connect-repo --json`, or `builds[].id` from `GET /projects/{id}/github/builds`. Prints one snapshot by default; `--follow` polls while building and briefly after it ends, for output that lands late (cannot be combined with `--json`). Governed by `logs.read`; no Depot credentials needed locally. Needs login and a linked project — unlike the offline `build` check above | | `insta --agent deploy ` / `--image ` [`--branch `] [`--group `] [`--port `] [`--websocket`] [`--replace-source`] [`--json`] | deploy to a compute service — a **source dir** (**whether it needs a `Dockerfile` depends on where the service runs**: on an insta-compute service one is *optional* — the CLI packs the directory, uploads it, and the build gateway builds it with nixpacks when there is no Dockerfile; on a legacy-plane service one is still *required*, and without it the command exits 1 naming the options: write a Dockerfile, `--image `, or connect the repo to the service (`insta --agent compute connect-repo [service]`). The CLI asks the platform which lane serves the target rather than guessing. A CLI that predates this lane answers `source builds are not supported on the insta-compute provider yet` for such a target: run `insta --agent upgrade` and retry. Either way the build is remote — no local Docker; against a local insta-oss daemon the CLI builds with your local docker instead, same command) or a **prebuilt image**. Defaults to the branch's sole compute service; `--group` picks by name (gated: `deploy`). If the installed `deploy --help` advertises worker port zero, `--port 0` deploys a portless worker on insta-compute with no public URL; otherwise use a [template worker](#templates) or the [source-only listener fallback](references/deploy.md#workers-without-a-routed-port). See [worker ports](references/deploy.md#workers-without-a-routed-port) for CLI/platform prerequisites. `--websocket` runs it as a WebSocket app (larger guest + connection-based concurrency); the setting is recorded on the service, so a later `compute restart` or flagless redeploy keeps it (see [operate.md](references/operate.md)). A service connected to a GitHub repo refuses a dir/image deploy (409) unless `--replace-source` is passed (admin): the image then replaces the repo connection. `--json` prints one `{image, machineId, url, branch, group, nextActions}` document on stdout — build progress moves to stderr so stdout stays parseable | -| `insta --agent template list` [`--json`] · `insta --agent template info ` [`--json`] | browse the platform **template registry**: one row per template (code / version / category / required-var count / deploy count / name — tagline), and the detail view — version, maintainer, source, upstream pin, a services summary (types, ports, volumes), and every required/optional variable with its description, generator or default | -| `insta --agent template deploy ` [`--branch `] [`--region `] [`--set `] [`-y`, `--yes`] [`--json`] | deploy a template's whole service set onto a branch (default: current) — a **registry code**, a **local directory** carrying `insta.template.yaml`, or a **github.com URL** (⚠️ **preview**, needs a recent CLI and `git` on `PATH` — see [Templates](#templates); `https://github.com//`, `/tree/`, `/tree//`, or a `/blob/…/insta.template.yaml` file link). A bare word is **always** a registry code; local mode needs a path-looking target (`./dir`, `/abs/dir`, `~/dir`, `sub/dir`), so a same-named directory in the working dir can never shadow a registry template. The GitHub form shallow-clones on **your machine** with **your** git credentials — private repositories work when git can already read them (`gh auth login` then `gh auth setup-git`) — reads the manifest from the named directory (never scanning the tree, never following a symlink out of the clone), deletes the clone, and sends the manifest inline. Missing required variables are prompted for on a terminal; `--yes` or no TTY fails with the exact `--set NAME=value` list instead. `secret:N`-generated and defaulted variables are resolved **by the platform** — generated secrets never transit. Renders the 4-step pipeline (create services → write variables → deploy → health check), then the per-service URLs; `--json` replaces all of that with one document, which in GitHub mode carries a leading `source: {repo, ref, path, commit}` where `commit` is the commit that was checked out. May come back `approval_required` (hint on stderr, envelope on stdout with `--json`, **exit 2** — as every gated command). `--region ` places **every** service the template creates in that region (a slug from `insta --agent config regions`, default `us-east`). One region per template deployment, not per service, and it cannot be changed afterwards. A retry (same deployment) may omit it or repeat it, a different value is refused with 409. See [Templates](#templates) | +| `insta --agent template list` [`--json`] · `insta --agent template info ` [`--json`] | browse the platform **template registry**: one row per template (code / version / category / required-var count / deploy count / name — tagline), and the detail view — version, maintainer, source, upstream pin, a services summary (types, ports, volumes, a Postgres service's major as `postgres 17`, and `public` or `private` for a storage bucket, **CLI ≥ @CLI_VERSION@**), and every required/optional variable with its description, generator or default | +| `insta --agent template deploy ` [`--branch `] [`--region `] [`--set `] [`-y`, `--yes`] [`--json`] | deploy a template's whole service set onto a branch (default: current) — a **registry code**, a **local directory** carrying `insta.template.yaml`, or a **github.com URL** (⚠️ **preview**, needs a recent CLI and `git` on `PATH` — see [Templates](#templates); `https://github.com//`, `/tree/`, `/tree//`, or a `/blob/…/insta.template.yaml` file link). A bare word is **always** a registry code; local mode needs a path-looking target (`./dir`, `/abs/dir`, `~/dir`, `sub/dir`), so a same-named directory in the working dir can never shadow a registry template. The GitHub form shallow-clones on **your machine** with **your** git credentials — private repositories work when git can already read them (`gh auth login` then `gh auth setup-git`) — reads the manifest from the named directory (never scanning the tree, never following a symlink out of the clone), deletes the clone, and sends the manifest inline. Missing required variables are prompted for on a terminal; `--yes` or no TTY fails with the exact `--set NAME=value` list instead. `secret:N`-generated and defaulted variables are resolved **by the platform** — generated secrets never transit. Renders the 4-step pipeline (create services → write variables → deploy → health check), then the per-service URLs; `--json` replaces all of that with one document, which in GitHub mode carries a leading `source: {repo, ref, path, commit}` where `commit` is the commit that was checked out. May come back `approval_required` (hint on stderr, envelope on stdout with `--json`, **exit 2** — as every gated command). `--region ` places **every** service the template creates in that region (a slug from `insta --agent config regions`, default `us-east`), except a storage bucket, which has no region. One region per template deployment, not per service, and it cannot be changed afterwards. A retry (same deployment) may omit it or repeat it, a different value is refused with 409. See [Templates](#templates) | | `insta --agent domain search ` [`--tlds com,dev`] [`--org `] [`--json`] | **buy a domain THROUGH InstaCloud** (a developer-owned/BYO domain skips `search`/`buy` entirely — go straight to `domain attach` below): purchasable names with the price you pay and the yearly renewal. A label (`myapp`) comes back across the extensions the registrar suggests, or the ones `--tlds` names (at most 50); a full name (`myapp.com`) is always in the answer unless `--tlds` leaves its extension out, even when it cannot be bought, so a plain name you typed is never answered with silence — but only a plain one: a pasted `www.myapp.com`, or a trailing dot, is answered for the label alone and the string you typed is absent. An extension is sold unless registering it needs something InstaCloud does not collect (registrant or residency fields, a registry notice or acknowledgement — `.ca`, `.fr`, …). Such a name is `unavailable` wherever you asked for it, and a suggestion in one is dropped. **`premium: true` is a registry premium name**, buyable when `purchasable` at its own price — say so when you relay the price. It is in `--json` only: the table prints a premium row as a plain price with no `(renews …)`. Its row carries no `renewalPriceCents`; the `buy` order may. **Read `reason`** — one with no price and a registrar refusal each say so in their own words. `unavailable` is the fallback, and the one to be careful with: it does **not** distinguish "the registrar says it is taken" from "a name we cannot sell", so do not report either as the reason when that is all you have | | `insta --agent domain buy ` [`--years n`] [`--no-open`] [`--json`] | **(CLI ≥ 0.0.80 — older builds call routes the platform has removed)** order it. **A domain belongs to the ORG** — the one your linked project is in. `list`, `status`, `search` and `records` take `--org ` to name another; `buy` and `attach` do not, because both bind the linked project: buying spends that org's money under that project's policy, and attaching names one of its services. Your agent policy is read at the project your session is bound to (`insta agent setup`), and that project must be in the org paying. A credential that names no project — an `insta_` key, MCP — is judged on the whole org instead: every project in it must be `full_access`. **Buying binds nothing**: the registered name serves nothing until `domain attach` says what it should serve. Answers a **Stripe Checkout URL a human must open** — nothing is registered until they pay, and registrations are **non-refundable**, so relay the URL and stop. Gated: `domain.purchase` — **`full_access`, which a new project starts on, allows it outright**; `branch_specific` answers `approval_required` (202 + exit 2, see [Approval relay](SKILL.md#approval-relay-critical--gated-actions)); `read_only` refuses. Paying the Checkout link needs a human either way. Some registries take fixed terms (`.ai` is 2-year only) — a term they refuse is a 400 **before** any payment. **Pass `--no-open`**: by default this spawns the host's browser at the Checkout link, which on an agent's machine opens a window nobody is watching — you want the URL printed so you can relay it | | `insta --agent domain status ` [`--org `] [`--json`] · `insta --agent domain list` [`--org `] [`--json`] | **(CLI ≥ 0.0.80 — older builds call routes the platform has removed)** every domain the ORG owns, not just ones this project uses — `--org ` targets one other than the linked project's default (see the `buy` row above for which verbs take it). After payment the platform registers the name and stops — the domain is inventory, listed with no hostnames, until an `attach`. Poll `status`: the order runs `pending_payment` → `paid` → `registering` → `registered`, and then, once something is attached, → `attaching` → `active`; each hostname runs `pending` → `attached` → `active` (`failed` carries the reason; `insta --agent domain attach ` on that hostname retries it). Each hostname names **its own** service, because one domain can serve several. Minutes, not seconds | @@ -499,7 +499,7 @@ and health-checks them, instead of a hand-rolled `service add` + `secrets set` + contain `insta.template.yaml` (validated locally, then sent inline). A `github.com` URL fetches that file from the repository with your own git credentials and sends it the same way. So a local directory never shadows a registry template — `./` is how you opt into the local one. -- **One region for the whole template.** `--region ` (values from `insta --agent config regions`) puts every service the template creates in that region, postgres and compute alike. Omitted, the platform default `us-east` applies. The region is fixed at deploy: there is no change-region operation, so a template wanted elsewhere is a fresh deployment. Deploying the same template again into the branch mints an independent copy, which may take a different region. +- **One region for the whole template.** `--region ` (values from `insta --agent config regions`) puts every service the template creates in that region, postgres and compute alike, and a storage bucket takes none. Omitted, the platform default `us-east` applies. The region is fixed at deploy: there is no change-region operation, so a template wanted elsewhere is a fresh deployment. Deploying the same template again into the branch mints an independent copy, which may take a different region. - **GitHub URLs** (⚠️ **preview**, see the note below). `insta --agent template deploy https://github.com///tree//` reads `insta.template.yaml` from exactly that directory (the repository root when the URL names none), and a `/blob/…/insta.template.yaml` link works too. The clone happens on your machine and is @@ -535,7 +535,11 @@ code: my-app # a-z 0-9 -, ≤39 chars; becomes the service/br version: "1.0" # your own; bump it when the manifest changes services: db: # a managed postgres: declare it BARE and the platform owns it - type: postgres # no image, port, volume or env — anything else here is refused + type: postgres # no image, port, volume or env, and pgVersion is the one field it takes + pgVersion: 17 # optional: the Postgres major, an integer the platform offers. Omit it for the default + files: # an object-storage bucket, also bare: no image, port, volume, env or region + type: storage + public: true # optional: anonymous public-read, anyone can read the files. Omit it for private web: # the key is the service name type: web image: ghcr.io/me/my-app:1.4.0 # MUST be publicly pullable, and MUST be pinned @@ -545,6 +549,10 @@ services: env: platform: # credentials the platform mints, wired in at deploy time DATABASE_URL: ${{services.db.DATABASE_URL}} + S3_KEY: ${{services.files.AWS_ACCESS_KEY_ID}} + S3_SECRET: ${{services.files.AWS_SECRET_ACCESS_KEY}} + S3_ENDPOINT: ${{services.files.AWS_ENDPOINT_URL_S3}} + S3_BUCKET: ${{services.files.BUCKET_NAME}} fixed: DATA_DIR: /data # baked in, the deployer never sees or sets it required: @@ -554,10 +562,14 @@ services: SMTP_HOST: One-line description, the shorthand for a var with no other keys ``` -**`env.platform` is how a managed service reaches the app, and a template with a database needs -it.** The value is a reference, `${{services..}}`, naming another service in this -same manifest and the credential key it mints (a postgres service mints `DATABASE_URL`). The -platform resolves it while writing variables, before the app starts. +**`env.platform` is how a managed service reaches the app, and a template with a database or a +bucket needs it.** The value is a reference, `${{services..}}`, naming another service +in this same manifest and the credential key it mints. A postgres service mints `DATABASE_URL`. A +storage service mints `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_ENDPOINT_URL_S3`, +`BUCKET_NAME` and `AWS_REGION`. The platform resolves the reference while writing variables, before +the app starts. A database and a bucket have no address, so `${services..url}` and `.host` +are refused for them. A public bucket's address is not a reference either: the app builds it from +`BUCKET_NAME`, see [Public vs private](references/storage.md#public-vs-private). Do not plan to run `insta --agent secrets bind` afterwards instead: `template deploy` creates the services and immediately deploys and health-checks the web one, so an app that needs `DATABASE_URL` would @@ -579,22 +591,27 @@ services: Other optional top-level keys: `maintainer`, `sourceRepo`, `upstream` (what you packaged and its pin), `constraints` (`oneOf` / `allOf` over variable names, for variables that only make sense together), and `meta` (`name`, `tagline`, `category`, `tags`) which only the registry renders. +Unknown keys at the top level and under `meta` and `upstream` are not refused. Only a service entry is strict. -**Four rules that are easy to get wrong, and where you find out:** +**Six rules that are easy to get wrong, and where you find out:** | Rule | Where it bites | |---|---| | The image must be **publicly pullable**. A private repository is fine, a private image is not: the platform pulls anonymously, with no credential field anywhere. | Not at validation. The deploy creates services, then the machine fails to pull and the health gate fails. GHCR package visibility is separate from repository visibility, so a private repo can publish a public package. | | Use `image:`, never `build:`. The platform does not build from source for template deploys. Push the image yourself first. | Server-side, immediately: `services. uses build: — server-side template deploys support image services only`. | -| Deployable types are `web`, `worker`, and bare `postgres` / `redis` / `mysql` / `mongodb`. A `worker` is portless and always-on: it must not declare `port`, `healthcheck` or `alwaysOn: false`, nothing is routed to it, and no other service can reference its `url`/`host`. | Locally, before the upload: `services..port: a worker has no routed port — remove it`. | -| A `postgres` service must be **bare** (`{ type: postgres }`) and needs **CLI ≥ 0.0.62**. Older CLIs reject it locally, `services..type must be web or worker`, even though the platform accepts it. | Locally on an old CLI, which is why the error names a type the platform does in fact take. `insta --agent upgrade`. | +| Deployable types are `web`, `worker`, `storage`, and bare `postgres` / `redis` / `mysql` / `mongodb`. A `worker` is portless and always-on: it must not declare `port`, `healthcheck` or `alwaysOn: false`, nothing is routed to it, and no other service can reference its `url`/`host`. | Locally, before the upload: `services..port: a worker has no routed port — remove it`. | +| A `postgres` service is **bare** (`{ type: postgres }`) apart from one optional field, `pgVersion`, an integer Postgres major. Omitted, the platform default applies. It needs **CLI ≥ 0.0.62**. Older CLIs reject it locally, `services..type must be web or worker`, even though the platform accepts it. | Locally on an old CLI, which is why the error names a type the platform does in fact take. `insta --agent upgrade`. | +| A `storage` service is a bucket, bare apart from one optional field, `public: true` for anonymous public-read (omit it for private). It takes no `env`, `image`, `port`, `volume` or region, and its credentials are reached through `env.platform`. `public` belongs to `storage` and `pgVersion` to `postgres`, on no other type. A public bucket is readable by anyone, so tell the person you deploy for, and know that deploying one also needs the `service.setAccess` approval. It needs **CLI ≥ @CLI_VERSION@**. | By the platform, after the upload: `invalid template manifest: services..public: only a storage service can be public`. A CLI older than the floor stops earlier, locally, with `services..type must be one of web, worker, postgres, redis, mysql, mongodb`. `insta --agent upgrade`. | +| A service carries only keys the platform knows. A misspelt key is refused by name, where it used to be ignored. | By the platform, after the upload: `invalid template manifest: services.. is not a template field`. | Validate before you push by deploying the directory: `insta --agent template deploy ./my-template -y` reports manifest problems first, so getting past them to the `--set` list (or, for a manifest with -no unset required variables, to the deploy itself) means it parsed and validated. That covers -structure, pinned images (`:latest` and tagless are rejected) and described variables. It does -**not** cover the first two rows above, which pass locally and fail later: a private image and a -`build:` key. +no unset required variables, to the deploy itself) means it parsed and validated locally. That +covers the structure of `web` and `worker` services, pinned images (`:latest` and tagless are +rejected) and described variables. The CLI no longer judges any other service type or field, so a +bucket, a `pgVersion` or a misspelt key is first answered by the platform when the deploy is +submitted, the last rows above. It also does **not** cover the first two rows, which pass locally +and fail later: a private image and a `build:` key. ## Feedback From b718f0ac619e4d4582792500beb81b018b325cd7 Mon Sep 17 00:00:00 2001 From: CarmenDou <15951653662@163.com> Date: Tue, 6 Oct 2026 00:05:28 -0700 Subject: [PATCH 2/4] docs(insta): public bucket address needs the public storage host A public bucket's URL is built from BUCKET_NAME plus the platform's public storage host, which no env.platform key carries. Say so and point at the storage reference section that explains where the host comes from. --- insta/cli-reference.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/insta/cli-reference.md b/insta/cli-reference.md index a65cb2e..8c23e6e 100644 --- a/insta/cli-reference.md +++ b/insta/cli-reference.md @@ -569,7 +569,8 @@ storage service mints `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_ENDPOIN `BUCKET_NAME` and `AWS_REGION`. The platform resolves the reference while writing variables, before the app starts. A database and a bucket have no address, so `${services..url}` and `.host` are refused for them. A public bucket's address is not a reference either: the app builds it from -`BUCKET_NAME`, see [Public vs private](references/storage.md#public-vs-private). +`BUCKET_NAME` plus the platform's public storage host, which no `env.platform` key carries, see +[Public vs private](references/storage.md#public-vs-private) for where the host comes from. Do not plan to run `insta --agent secrets bind` afterwards instead: `template deploy` creates the services and immediately deploys and health-checks the web one, so an app that needs `DATABASE_URL` would From 674b792e60d0c95b423c03712dd47b638bbac4a1 Mon Sep 17 00:00:00 2001 From: CarmenDou <15951653662@163.com> Date: Tue, 6 Oct 2026 09:48:54 -0700 Subject: [PATCH 3/4] docs(insta): private bucket in the manifest sample, quote the platform's real refusals The complete minimal manifest set public: true uncommented, so an agent copying it created a world-readable bucket. Show public as a comment and leave the bucket private. Bind AWS_REGION through env.platform like the other storage keys, since many S3 SDKs refuse to start without a region. The public rule quoted the oss runtime's sentence. Quote the platform's own, one for a web or worker and one for a managed database, and say the deploy is gated by service.setAccess rather than that it always needs an approval. --- insta/cli-reference.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/insta/cli-reference.md b/insta/cli-reference.md index 8c23e6e..93b1230 100644 --- a/insta/cli-reference.md +++ b/insta/cli-reference.md @@ -539,7 +539,7 @@ services: pgVersion: 17 # optional: the Postgres major, an integer the platform offers. Omit it for the default files: # an object-storage bucket, also bare: no image, port, volume, env or region type: storage - public: true # optional: anonymous public-read, anyone can read the files. Omit it for private + # public: true # optional: anonymous public-read, anyone can read the files. Leave it out for private web: # the key is the service name type: web image: ghcr.io/me/my-app:1.4.0 # MUST be publicly pullable, and MUST be pinned @@ -553,6 +553,7 @@ services: S3_SECRET: ${{services.files.AWS_SECRET_ACCESS_KEY}} S3_ENDPOINT: ${{services.files.AWS_ENDPOINT_URL_S3}} S3_BUCKET: ${{services.files.BUCKET_NAME}} + S3_REGION: ${{services.files.AWS_REGION}} fixed: DATA_DIR: /data # baked in, the deployer never sees or sets it required: @@ -602,7 +603,7 @@ Unknown keys at the top level and under `meta` and `upstream` are not refused. O | Use `image:`, never `build:`. The platform does not build from source for template deploys. Push the image yourself first. | Server-side, immediately: `services. uses build: — server-side template deploys support image services only`. | | Deployable types are `web`, `worker`, `storage`, and bare `postgres` / `redis` / `mysql` / `mongodb`. A `worker` is portless and always-on: it must not declare `port`, `healthcheck` or `alwaysOn: false`, nothing is routed to it, and no other service can reference its `url`/`host`. | Locally, before the upload: `services..port: a worker has no routed port — remove it`. | | A `postgres` service is **bare** (`{ type: postgres }`) apart from one optional field, `pgVersion`, an integer Postgres major. Omitted, the platform default applies. It needs **CLI ≥ 0.0.62**. Older CLIs reject it locally, `services..type must be web or worker`, even though the platform accepts it. | Locally on an old CLI, which is why the error names a type the platform does in fact take. `insta --agent upgrade`. | -| A `storage` service is a bucket, bare apart from one optional field, `public: true` for anonymous public-read (omit it for private). It takes no `env`, `image`, `port`, `volume` or region, and its credentials are reached through `env.platform`. `public` belongs to `storage` and `pgVersion` to `postgres`, on no other type. A public bucket is readable by anyone, so tell the person you deploy for, and know that deploying one also needs the `service.setAccess` approval. It needs **CLI ≥ @CLI_VERSION@**. | By the platform, after the upload: `invalid template manifest: services..public: only a storage service can be public`. A CLI older than the floor stops earlier, locally, with `services..type must be one of web, worker, postgres, redis, mysql, mongodb`. `insta --agent upgrade`. | +| A `storage` service is a bucket, bare apart from one optional field, `public: true` for anonymous public-read (omit it for private). It takes no `env`, `image`, `port`, `volume` or region, and its credentials are reached through `env.platform`. `public` belongs to `storage` and `pgVersion` to `postgres`, on no other type. A public bucket is readable by anyone, so tell the person you deploy for, and know that deploying one is gated by `service.setAccess`. It needs **CLI ≥ @CLI_VERSION@**. | By the platform, after the upload: on a `web` or `worker`, `invalid template manifest: services..public: public access is only supported for storage services`, and on a managed database, `invalid template manifest: services..public: a postgres service is platform-managed and carries no public`, which goes on to say how to declare it bare. A CLI older than the floor stops earlier, locally, with `services..type must be one of web, worker, postgres, redis, mysql, mongodb`. `insta --agent upgrade`. | | A service carries only keys the platform knows. A misspelt key is refused by name, where it used to be ignored. | By the platform, after the upload: `invalid template manifest: services.. is not a template field`. | Validate before you push by deploying the directory: `insta --agent template deploy ./my-template -y` From 5f6a1e330d40f793b23c5aabe224d06c7316b3e5 Mon Sep 17 00:00:00 2001 From: CarmenDou <15951653662@163.com> Date: Tue, 6 Oct 2026 14:46:08 -0700 Subject: [PATCH 4/4] docs(insta): the CLI floor for storage and template info is 0.1.19 The two compatibility notices name the released CLI that carries InsForge/instacloud-cli#351, in place of the placeholder. --- insta/cli-reference.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/insta/cli-reference.md b/insta/cli-reference.md index 93b1230..ab4e48c 100644 --- a/insta/cli-reference.md +++ b/insta/cli-reference.md @@ -82,7 +82,7 @@ keys and raw request data must not be included in source control or approval rep | `insta --agent build [dir]` [`--explain`] [`--port `] [`--json`] | **verify before you deploy** — local, offline, deploys nothing, needs no login: prints the detection plan (builder, install/build/start commands, port **with the reason it was chosen**, `.env.example` keys), the Dockerfile (yours, or — **if nixpacks is installed**, never auto-installed — the one nixpacks would generate; `--explain` includes its content), and static checks each with a next action (missing Dockerfile/start command, port mismatch, `node_modules` shipping in the build context). **Verdict semantics (CLI ≥ 0.0.48): only a Dockerfile IN the directory can make a dir `deployable`.** A dir with no Dockerfile where nixpacks detects the app gets `builder: nixpacks` but its Dockerfile check is a ⚠ warning and the verdict stops at `needs-attention` (exit 0) — the command is local and cannot know which compute plane the target runs on, and the answer differs: an insta-compute service deploys such a dir as-is (the gateway runs nixpacks), a legacy-plane one refuses it. Read `needs-attention` as "depends on the target", not as "will fail". The nixpacks Dockerfile shown by `--explain` is **for inspection, not standalone** (it `COPY`s `.nixpacks/` support files the dir does not have) — do NOT save it as `Dockerfile`; use the detected install/start commands as the starting point for your own. Verdict `failed` (exit 1) = no Dockerfile and nixpacks missing/undetected, or no start command. For a Dockerfile-less dir that `failed` says only that nixpacks is not installed on THIS machine: an insta-compute target still deploys it, because the gateway runs nixpacks, so do not add a Dockerfile just to satisfy the local check. Run it before `insta --agent deploy ` instead of finding out from a burned remote build | | `insta --agent build logs ` [`--source `] [`--follow`] [`--json`] | read output from a **source build** — the remote build a `deploy`/`compute connect-repo` push kicked off, not the local, offline `build` check above. `--source archive` (default) reads a **deploy operation's** build: `` is that operation id, printed as soon as `insta --agent deploy` accepts the operation (stderr with `deploy --json`). `--source github` reads a **GitHub-triggered** build: `` is the GitHub build id — read `build.buildId` from `insta --agent compute connect-repo --json`, or `builds[].id` from `GET /projects/{id}/github/builds`. Prints one snapshot by default; `--follow` polls while building and briefly after it ends, for output that lands late (cannot be combined with `--json`). Governed by `logs.read`; no Depot credentials needed locally. Needs login and a linked project — unlike the offline `build` check above | | `insta --agent deploy ` / `--image ` [`--branch `] [`--group `] [`--port `] [`--websocket`] [`--replace-source`] [`--json`] | deploy to a compute service — a **source dir** (**whether it needs a `Dockerfile` depends on where the service runs**: on an insta-compute service one is *optional* — the CLI packs the directory, uploads it, and the build gateway builds it with nixpacks when there is no Dockerfile; on a legacy-plane service one is still *required*, and without it the command exits 1 naming the options: write a Dockerfile, `--image `, or connect the repo to the service (`insta --agent compute connect-repo [service]`). The CLI asks the platform which lane serves the target rather than guessing. A CLI that predates this lane answers `source builds are not supported on the insta-compute provider yet` for such a target: run `insta --agent upgrade` and retry. Either way the build is remote — no local Docker; against a local insta-oss daemon the CLI builds with your local docker instead, same command) or a **prebuilt image**. Defaults to the branch's sole compute service; `--group` picks by name (gated: `deploy`). If the installed `deploy --help` advertises worker port zero, `--port 0` deploys a portless worker on insta-compute with no public URL; otherwise use a [template worker](#templates) or the [source-only listener fallback](references/deploy.md#workers-without-a-routed-port). See [worker ports](references/deploy.md#workers-without-a-routed-port) for CLI/platform prerequisites. `--websocket` runs it as a WebSocket app (larger guest + connection-based concurrency); the setting is recorded on the service, so a later `compute restart` or flagless redeploy keeps it (see [operate.md](references/operate.md)). A service connected to a GitHub repo refuses a dir/image deploy (409) unless `--replace-source` is passed (admin): the image then replaces the repo connection. `--json` prints one `{image, machineId, url, branch, group, nextActions}` document on stdout — build progress moves to stderr so stdout stays parseable | -| `insta --agent template list` [`--json`] · `insta --agent template info ` [`--json`] | browse the platform **template registry**: one row per template (code / version / category / required-var count / deploy count / name — tagline), and the detail view — version, maintainer, source, upstream pin, a services summary (types, ports, volumes, a Postgres service's major as `postgres 17`, and `public` or `private` for a storage bucket, **CLI ≥ @CLI_VERSION@**), and every required/optional variable with its description, generator or default | +| `insta --agent template list` [`--json`] · `insta --agent template info ` [`--json`] | browse the platform **template registry**: one row per template (code / version / category / required-var count / deploy count / name — tagline), and the detail view — version, maintainer, source, upstream pin, a services summary (types, ports, volumes, a Postgres service's major as `postgres 17`, and `public` or `private` for a storage bucket, **CLI ≥ 0.1.19**), and every required/optional variable with its description, generator or default | | `insta --agent template deploy ` [`--branch `] [`--region `] [`--set `] [`-y`, `--yes`] [`--json`] | deploy a template's whole service set onto a branch (default: current) — a **registry code**, a **local directory** carrying `insta.template.yaml`, or a **github.com URL** (⚠️ **preview**, needs a recent CLI and `git` on `PATH` — see [Templates](#templates); `https://github.com//`, `/tree/`, `/tree//`, or a `/blob/…/insta.template.yaml` file link). A bare word is **always** a registry code; local mode needs a path-looking target (`./dir`, `/abs/dir`, `~/dir`, `sub/dir`), so a same-named directory in the working dir can never shadow a registry template. The GitHub form shallow-clones on **your machine** with **your** git credentials — private repositories work when git can already read them (`gh auth login` then `gh auth setup-git`) — reads the manifest from the named directory (never scanning the tree, never following a symlink out of the clone), deletes the clone, and sends the manifest inline. Missing required variables are prompted for on a terminal; `--yes` or no TTY fails with the exact `--set NAME=value` list instead. `secret:N`-generated and defaulted variables are resolved **by the platform** — generated secrets never transit. Renders the 4-step pipeline (create services → write variables → deploy → health check), then the per-service URLs; `--json` replaces all of that with one document, which in GitHub mode carries a leading `source: {repo, ref, path, commit}` where `commit` is the commit that was checked out. May come back `approval_required` (hint on stderr, envelope on stdout with `--json`, **exit 2** — as every gated command). `--region ` places **every** service the template creates in that region (a slug from `insta --agent config regions`, default `us-east`), except a storage bucket, which has no region. One region per template deployment, not per service, and it cannot be changed afterwards. A retry (same deployment) may omit it or repeat it, a different value is refused with 409. See [Templates](#templates) | | `insta --agent domain search ` [`--tlds com,dev`] [`--org `] [`--json`] | **buy a domain THROUGH InstaCloud** (a developer-owned/BYO domain skips `search`/`buy` entirely — go straight to `domain attach` below): purchasable names with the price you pay and the yearly renewal. A label (`myapp`) comes back across the extensions the registrar suggests, or the ones `--tlds` names (at most 50); a full name (`myapp.com`) is always in the answer unless `--tlds` leaves its extension out, even when it cannot be bought, so a plain name you typed is never answered with silence — but only a plain one: a pasted `www.myapp.com`, or a trailing dot, is answered for the label alone and the string you typed is absent. An extension is sold unless registering it needs something InstaCloud does not collect (registrant or residency fields, a registry notice or acknowledgement — `.ca`, `.fr`, …). Such a name is `unavailable` wherever you asked for it, and a suggestion in one is dropped. **`premium: true` is a registry premium name**, buyable when `purchasable` at its own price — say so when you relay the price. It is in `--json` only: the table prints a premium row as a plain price with no `(renews …)`. Its row carries no `renewalPriceCents`; the `buy` order may. **Read `reason`** — one with no price and a registrar refusal each say so in their own words. `unavailable` is the fallback, and the one to be careful with: it does **not** distinguish "the registrar says it is taken" from "a name we cannot sell", so do not report either as the reason when that is all you have | | `insta --agent domain buy ` [`--years n`] [`--no-open`] [`--json`] | **(CLI ≥ 0.0.80 — older builds call routes the platform has removed)** order it. **A domain belongs to the ORG** — the one your linked project is in. `list`, `status`, `search` and `records` take `--org ` to name another; `buy` and `attach` do not, because both bind the linked project: buying spends that org's money under that project's policy, and attaching names one of its services. Your agent policy is read at the project your session is bound to (`insta agent setup`), and that project must be in the org paying. A credential that names no project — an `insta_` key, MCP — is judged on the whole org instead: every project in it must be `full_access`. **Buying binds nothing**: the registered name serves nothing until `domain attach` says what it should serve. Answers a **Stripe Checkout URL a human must open** — nothing is registered until they pay, and registrations are **non-refundable**, so relay the URL and stop. Gated: `domain.purchase` — **`full_access`, which a new project starts on, allows it outright**; `branch_specific` answers `approval_required` (202 + exit 2, see [Approval relay](SKILL.md#approval-relay-critical--gated-actions)); `read_only` refuses. Paying the Checkout link needs a human either way. Some registries take fixed terms (`.ai` is 2-year only) — a term they refuse is a 400 **before** any payment. **Pass `--no-open`**: by default this spawns the host's browser at the Checkout link, which on an agent's machine opens a window nobody is watching — you want the URL printed so you can relay it | @@ -603,7 +603,7 @@ Unknown keys at the top level and under `meta` and `upstream` are not refused. O | Use `image:`, never `build:`. The platform does not build from source for template deploys. Push the image yourself first. | Server-side, immediately: `services. uses build: — server-side template deploys support image services only`. | | Deployable types are `web`, `worker`, `storage`, and bare `postgres` / `redis` / `mysql` / `mongodb`. A `worker` is portless and always-on: it must not declare `port`, `healthcheck` or `alwaysOn: false`, nothing is routed to it, and no other service can reference its `url`/`host`. | Locally, before the upload: `services..port: a worker has no routed port — remove it`. | | A `postgres` service is **bare** (`{ type: postgres }`) apart from one optional field, `pgVersion`, an integer Postgres major. Omitted, the platform default applies. It needs **CLI ≥ 0.0.62**. Older CLIs reject it locally, `services..type must be web or worker`, even though the platform accepts it. | Locally on an old CLI, which is why the error names a type the platform does in fact take. `insta --agent upgrade`. | -| A `storage` service is a bucket, bare apart from one optional field, `public: true` for anonymous public-read (omit it for private). It takes no `env`, `image`, `port`, `volume` or region, and its credentials are reached through `env.platform`. `public` belongs to `storage` and `pgVersion` to `postgres`, on no other type. A public bucket is readable by anyone, so tell the person you deploy for, and know that deploying one is gated by `service.setAccess`. It needs **CLI ≥ @CLI_VERSION@**. | By the platform, after the upload: on a `web` or `worker`, `invalid template manifest: services..public: public access is only supported for storage services`, and on a managed database, `invalid template manifest: services..public: a postgres service is platform-managed and carries no public`, which goes on to say how to declare it bare. A CLI older than the floor stops earlier, locally, with `services..type must be one of web, worker, postgres, redis, mysql, mongodb`. `insta --agent upgrade`. | +| A `storage` service is a bucket, bare apart from one optional field, `public: true` for anonymous public-read (omit it for private). It takes no `env`, `image`, `port`, `volume` or region, and its credentials are reached through `env.platform`. `public` belongs to `storage` and `pgVersion` to `postgres`, on no other type. A public bucket is readable by anyone, so tell the person you deploy for, and know that deploying one is gated by `service.setAccess`. It needs **CLI ≥ 0.1.19**. | By the platform, after the upload: on a `web` or `worker`, `invalid template manifest: services..public: public access is only supported for storage services`, and on a managed database, `invalid template manifest: services..public: a postgres service is platform-managed and carries no public`, which goes on to say how to declare it bare. A CLI older than the floor stops earlier, locally, with `services..type must be one of web, worker, postgres, redis, mysql, mongodb`. `insta --agent upgrade`. | | A service carries only keys the platform knows. A misspelt key is refused by name, where it used to be ignored. | By the platform, after the upload: `invalid template manifest: services.. is not a template field`. | Validate before you push by deploying the directory: `insta --agent template deploy ./my-template -y`