Skip to content

Add ggt init command for scaffolding new Gadget apps#2252

Open
scott-rc wants to merge 4 commits intosc/add-shell-completionfrom
sc/add-init-command
Open

Add ggt init command for scaffolding new Gadget apps#2252
scott-rc wants to merge 4 commits intosc/add-shell-completionfrom
sc/add-init-command

Conversation

@scott-rc
Copy link
Copy Markdown
Collaborator

@scott-rc scott-rc commented Feb 22, 2026

Adds a ggt init command for scaffolding new Gadget applications from the CLI. Users can create a new app by name, optionally selecting a template (--template) or forking an existing app (--fork), with flags for disabling TypeScript (--no-typescript) or git initialization (--no-git).

The command authenticates the user, creates the app via the Gadget services API, writes an initial .gadget/sync.json, pulls the starter files via FileSync, and optionally runs git init with an initial commit. A --dir flag lets the user specify the target directory (defaults to the app name).

Stacked on the shell completion PR -- review that PR first.

Adds a new `ggt envs` command with subcommands for listing, creating,
deleting, and unpausing Gadget application environments. Unlike
`ggt add environment` which requires a full sync context, `ggt envs`
operates standalone by resolving only the application (via --app flag,
sync.json, or interactive prompt).

Subcommands:
  - list: display all environments with name and type
  - create: create a new environment, optionally cloning from another
  - delete: delete an environment with confirmation (--force to skip)
  - unpause: resume a paused environment

Also extracts `loadApplication` from AppIdentity as a shared export so
both `AppIdentity.load` and `ggt envs` reuse the same app resolution
logic (slug matching, similar-name suggestions, interactive selection).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Feb 22, 2026

🦋 Changeset detected

Latest commit: cd4a3c2

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

method: "POST",
url: `https://${config.domains.services}/auth/api/apps`,
headers: loadAuthHeaders(ctx),
json: { subdomain, appType: "empty", typescript: true, forkFromAppId: String(sourceApp.id) },
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fork flow ignores --no-typescript flag

Medium Severity

The fork flow hardcodes typescript: true in the HTTP request body, completely ignoring the --no-typescript flag. The create flow correctly uses const typescript = !args["--no-typescript"], but the fork branch doesn't reference this flag at all. A user running ggt init my-fork --fork --no-typescript would still get a TypeScript app.

Additional Locations (1)

Fix in Cursor Fix in Web


const appSlug = app.slug;
const appName = args["--dir"] ?? appSlug;
const targetDir = await resolveTargetDirectory({ dir: args["--dir"], appSlug });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directory validation happens after irreversible app creation

Medium Severity

resolveTargetDirectory is called on line 155 after the app-creation API call (lines 116–148). If the target directory already exists and is non-empty, resolveTargetDirectory throws an ArgError, but the app has already been created on Gadget's server. The user is left with an orphaned remote app whose subdomain is now taken, and they can't simply re-run ggt init with the same name. Moving the directory check before the API call (at least when --dir is explicitly provided) would prevent this.

Additional Locations (1)

Fix in Cursor Fix in Web

@scott-rc scott-rc force-pushed the sc/add-shell-completion branch from 8d303bf to dd1eb27 Compare February 22, 2026 17:28
Add structured metadata (descriptions, positionalArgs, valueName,
subcommandDefs, longDescription, sections, examples) to all command
modules and update the usage rendering to use uppercase section
headers, an ARGUMENTS section, and [flags] instead of [options].
Generate completion scripts for bash, zsh, and fish shells.
Uses the declarative command metadata to produce accurate
completions for all commands, subcommands, flags, and positional args.
Introduces `ggt init [app-name]` which creates a new Gadget application
(from a template or by forking an existing app), pulls its initial files
to a local directory, writes `.ignore` and `.gitignore` defaults, and
optionally initializes a git repo with an initial commit. Also adds a
`textInput` output service for free-text prompts.
@scott-rc scott-rc force-pushed the sc/add-shell-completion branch from dd1eb27 to d704041 Compare February 22, 2026 19:29
@scott-rc scott-rc force-pushed the sc/add-init-command branch from 1a93ed1 to cd4a3c2 Compare February 22, 2026 19:29
@scott-rc scott-rc force-pushed the sc/add-shell-completion branch 4 times, most recently from 73882ac to dfaeb3e Compare March 9, 2026 19:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants