The Stackable CLI provides commands to create, develop, validate, and deploy extensions. This reference covers all available commands, options, and usage examples.

## create

Scaffold a new extension project:

```bash
pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest create <extension-name>
```

**Arguments:**

| Argument | Description |
|----------|-------------|
| `extension-name` | Name for your extension (saved as the manifest's `name`; kebab-cased to derive the directory and extension ID) |

**Options:**

| Flag | Description |
|------|-------------|
| `--template <flavor>` | Template flavor (see below) |
| `--app-id <id>` | Skip App selection |
| `--extension-port <port>` | Extension dev server port (default: 6543) |
| `--preview-port <port>` | Preview dev server port |
| `--skip-install` | Skip package manager install |
| `--skip-git` | Skip git initialization |

**Template flavors:**

| Flavor | Description |
|--------|-------------|
| `minimal` | Bare minimum — single surface, hello-world component |
| `starter` | Common patterns — store, api helpers, menu (default) |
| `kitchen-sink` | Everything — every component, capability, surface, and hook |

**Example:**
```bash
pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest create order-lookup
cd order-lookup
pnpm install
```

## dev

Start dev servers with a public tunnel for live preview:

```bash
pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest dev
```

**Options:**

| Flag | Description |
|------|-------------|
| `--dir <path>` | Project root (default: cwd) |
| `--extension-port <port>` | Override extension port |
| `--preview-port <port>` | Override preview port |
| `--no-tunnel` | Skip tunnel, just run vite dev |

**What it does:**
1. Reads `.env.stackable` for cached App/Extension context (prompts if missing)
2. Creates Cloudflare tunnels for the extension dev server
3. Starts Vite dev servers with hot reload
4. Displays a `_stackable_dev` query param to append to a host site's URL

### Host-Site Override

The CLI outputs a query param you append to your deployed host site's URL (the site or product where your extension is installed/authorized) to load your local extension instead of the production bundle. The override is browser-session only — no DB changes, no shared state. Each developer gets isolated overrides.

**Blob format (default — when authenticated):** the value after the colon is a `base64url`-encoded JSON `{url, token}` blob; the token is verified by the host:

```
?_stackable_dev=ext-123:eyJ1cmwiOiJodHRwczovL2FiYy50cnljbG91ZGZsYXJlLmNvbSIsInRva2VuIjoiZXlKaGJHY2lPaUpJVXp...
```

**Legacy format (fallback — when no token):** plain URL after the colon:

```
?_stackable_dev=ext-123:https://abc.trycloudflare.com
```

The CLI also surfaces a `_stackable_staging=...` variant (blob-only) for testing against staging-mode handling. For multiple extensions, comma-join entries in a single param — mixed blob + legacy is fine.

## validate *(coming soon)*

> *NOTE: manifests are validated server-side during the marketplace submission flow, in the AI Studio, or can be validated using the `validate_manifest` MCP tool — see [AI-Accelerated Development](/docs/reference/ai-accelerated-development#live-mcp-server).*

When shipped, the `validate` command will check your extension for common errors locally before submission:

```bash
pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest validate
```

**What it checks:**

| Check | Description |
|-------|-------------|
| Manifest structure | Valid JSON, required fields present |
| Permission usage | Capabilities used in code have matching permissions in manifest |
| Surface targets | Each `<Surface id="...">` has a matching target in manifest |
| Import validation | Uses `ui.*` namespace, no direct component imports |
| Domain configuration | `data.fetch` calls match `allowedDomains` entries |
| Sandbox compliance | No `document` or `window.location` access |

**Exit codes:**
- `0` — all checks pass
- `1` — errors found (must fix before deploying)

## deploy *(future)*

> *This command is on the roadmap. Currently build, deployment and hosting are the responsibility of the extension developer with your hosted Bundle URL being updated via the admin dashboard or via CLI.*

When shipped, the `deploy` command will package and ship your extension straight from the terminal:

```bash
pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest deploy
```

**Planned behavior:**
1. Run validation checks (same as `validate`)
2. Build the extension for production
3. Package the build output
4. Upload to the Stackable extension registry

## scaffold

Scaffold a local project from an existing extension:

```bash
pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest scaffold [extensionId]
```

**Options:**

| Flag | Description |
|------|-------------|
| `--app-id <id>` | App ID (auto-resolved from extensionId if omitted) |
| `--project-id <id>` | Studio project ID (fetches files/manifest from Studio) |
| `--skip-install` | Skip package manager install |
| `--skip-git` | Skip git initialization |

## update

Update an existing extension:

```bash
pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest update [extensionId]
```

**Options:**

| Flag | Description |
|------|-------------|
| `--app-id <id>` | App ID (auto-resolved from extensionId if omitted) |
| `--name <name>` | New extension name |
| `--targets <targets>` | Comma-separated target slots |
| `--bundle-url <url>` | New bundle URL |
| `--enabled <bool>` | Enable/disable extension |
| `--dir <path>` | Project root (default: cwd) |

## auth

Manage CLI authentication. Subcommands open a browser-based OAuth flow against the Stackable platform and store the resulting credentials locally.

**Subcommands:**

| Subcommand | Description |
|------------|-------------|
| `login` | Authenticate with Stackable via browser-based OAuth |
| `logout` | Clear stored CLI credentials |
| `status` | Show current authentication status (signed-in user, org, token expiry) |

**Examples:**

```bash
# First-time setup
pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest auth login

# Check who's signed in
pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest auth status

# Sign out
pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest auth logout
```

## ai

Manage AI editor configuration in your Extension project. Subcommands write Stackable's [AI tooling](/docs/reference/ai-accelerated-development) (Skills + MCP server config) into your project.

**Subcommands:**

| Subcommand | Description |
|------------|-------------|
| `scaffold` | Download Stackable Skills into your project's `.claude/`, `.cursor/`, `.windsurf/`, etc. |
| `mcp` | Add Stackable MCP server config to your project so any MCP-compatible AI client can connect |

**Options:**

| Flag | Description | Applies to |
|------|-------------|------------|
| `--version <version>` | AI docs version (semver or `latest`, default: `latest`) | both |
| `--dir <path>` | Project root directory (default: cwd) | `mcp` only |

**Examples:**

```bash
# Add the latest Stackable Skills to your project
pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest ai scaffold

# Pin a specific version
pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest ai scaffold --version 0.2.0

# Configure your project to talk to the Stackable MCP server
pnpm --config.dlx-cache-max-age=0 dlx @stackable-labs/cli-app-extension@latest ai mcp
```
