From 05077a469115eee246b2856d5710e6438954e7af Mon Sep 17 00:00:00 2001 From: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Date: Tue, 28 Jul 2026 09:06:42 +0800 Subject: [PATCH] feat(cli,client)!: drop `os environments create --template` and the `template_id` body field (#3731) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CLI advertised `--template` as "Built-in template id (e.g. crm, todo, blank)" and forwarded it as `template_id` on `projects.create()`. Nothing consumes it: `template_id`/`templateId` appears in zero non-test files in the `cloud` repo, `sys_environment` has no such column, and the create route whitelists what it reads (displayName, organizationId, isDefault, hostname, metadata, environmentType) — `template_id` is not in the list. The blank/crm/todo registry the flag named was the `apps/server` `createTemplatesRoutePlugin` snapshot, removed when the control plane moved to cloud; the flag outlived it. So it was accepted, transmitted, and dropped — no seeding, no error, no stored trace. Worse than the 404 its listing counterpart returned (#3702): a 404 tells the caller something is wrong, a silently ignored flag reports success. That is the "never advertise a capability the runtime doesn't deliver" corollary of Prime Directive #10. Starter content comes from the App Marketplace instead — `sys_package` rows with `is_starter = true`, installed via `projects.packages.install`, which is what the console already does. NOT the same `--template` as `os init` / `create-objectstack` (app/plugin/empty scaffolds); those are local scaffolding and are untouched. No doc references `os environments create --template`, so nothing to sweep. Closes #3731 Co-Authored-By: Claude --- .changeset/drop-dead-env-template-flag.md | 34 +++++++++++++++++++ .../cli/src/commands/environments/create.ts | 9 +++-- packages/client/src/index.ts | 9 ++++- 3 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 .changeset/drop-dead-env-template-flag.md diff --git a/.changeset/drop-dead-env-template-flag.md b/.changeset/drop-dead-env-template-flag.md new file mode 100644 index 0000000000..d4ab0c927f --- /dev/null +++ b/.changeset/drop-dead-env-template-flag.md @@ -0,0 +1,34 @@ +--- +"@objectstack/client": minor +"@objectstack/cli": minor +--- + +feat(cli,client)!: drop `os environments create --template` and the +`template_id` body field — no control plane has ever read them (#3731) + +The CLI advertised `--template` as *"Built-in template id (e.g. crm, todo, +blank)"* and forwarded it as `template_id` on `projects.create()`. Nothing +consumes it: `template_id` / `templateId` appears in **zero** non-test files in +the `cloud` repo, `sys_environment` has no such column, and the create route +whitelists what it reads (`displayName`, `organizationId`, `isDefault`, +`hostname`, `metadata`, …) — `template_id` is not in the list. The +`blank`/`crm`/`todo` registry the flag named was the `apps/server` +`createTemplatesRoutePlugin` snapshot, removed when the control plane moved to +`cloud`; the flag outlived it. + +So the flag was accepted, transmitted, and dropped — no seeding, no error, no +stored trace. That is worse than the 404 its listing counterpart returned +(`projects.listTemplates`, deleted in #3702): a 404 tells the caller something +is wrong, a silently ignored flag reports success. + +**Migration.** `os environments create --template ` → drop the flag; it +never did anything. Starter content comes from the App Marketplace: create the +environment, then install the package (`sys_package` rows with +`is_starter = true`, i.e. `client.projects.packages.install(envId, { packageId })`). +Callers passing `template_id` to `client.projects.create()` should delete the +property — TypeScript now rejects it, which is the point: an unknown field was +being silently discarded on the wire. + +Note this is **not** the same `--template` as `os init` / `create-objectstack` +(`app` / `plugin` / `empty` scaffolds) — those are local scaffolding templates +and are untouched. diff --git a/packages/cli/src/commands/environments/create.ts b/packages/cli/src/commands/environments/create.ts index 65c25d4774..f84ce1d823 100644 --- a/packages/cli/src/commands/environments/create.ts +++ b/packages/cli/src/commands/environments/create.ts @@ -31,7 +31,13 @@ export default class ProjectsCreate extends Command { name: Flags.string({ description: 'Display name', required: true }), plan: Flags.string({ description: 'Billing plan', default: 'free' }), driver: Flags.string({ description: 'Data-plane driver id' }), - template: Flags.string({ description: 'Built-in template id (e.g. crm, todo, blank)' }), + // No `--template`. It advertised "Built-in template id (e.g. crm, todo, + // blank)" and sent `template_id`, which the control plane has never read — + // the `blank`/`crm`/`todo` registry it named died with the `apps/server` + // templates route. Removed in #3731: an accepted-and-dropped flag reports + // success for work that never happened. Starter content is installed from + // the App Marketplace instead (`os packages install`, `sys_package` with + // `is_starter = true`). artifact: Flags.string({ description: 'Path to a locally-compiled objectstack.json artifact to bind into this project', }), @@ -80,7 +86,6 @@ export default class ProjectsCreate extends Command { display_name: flags.name, plan: flags.plan, driver: flags.driver, - template_id: flags.template, clone_from_environment_id: flags['clone-from'], ...(metadata ? { metadata } : {}), }); diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index e50aa8203d..6bca02ab97 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -1064,6 +1064,14 @@ export class ObjectStackClient { /** * Provision a new project. Delegates to * `ProjectProvisioningService.provisionProject` on the server. + * + * No `template_id`: it was removed in #3731 because no control plane has + * ever read it — the `blank`/`crm`/`todo` registry it addressed died with + * the `apps/server` templates route, and `sys_environment` has no such + * column, so the field was accepted, transmitted, and dropped. Starter + * content is installed from the App Marketplace (`sys_package` with + * `is_starter = true`), which `projects.packages.install` already does. + * Its listing counterpart went the same way in #3702. */ create: async (req: { organization_id: string; @@ -1078,7 +1086,6 @@ export class ObjectStackClient { is_system?: boolean; storage_limit_mb?: number; clone_from_environment_id?: string; - template_id?: string; metadata?: Record; }) => { const res = await this.fetch(`${this.baseUrl}/api/v1/cloud/environments`, {