Commands
Lifecycle commands for build, release, run, and post-start stages. Each value is a string (shorthand) or an object with command, optional timeout, and optional capture.
Platforms execute well-known commands in this order: build → release → start → (bootstrap on user request). The seed, test, and bootstrap commands are invoked on demand, not as part of the standard deploy lifecycle.
| Stage | Purpose | When |
|---|---|---|
build |
Install dependencies, compile | Every deploy |
release |
Migrations, cache clear, asset compilation | Every deploy, after build |
start |
Start the application | Every deploy, after release |
bootstrap |
Post-start setup that must run against a running component: create the first admin user, generate an initial invite link, write runtime config that depends on the deploy URL | On demand after start (user-invoked, re-runnable, non-deploy-failing). See Bootstrap stage below. |
seed |
Seed the database with initial data | On demand (first deploy or explicit trigger) |
test |
Run the test suite | On demand (CI or explicit trigger) |
Additional named commands are allowed and invoked on demand.
commands:
build: "npm install"
release: "npx prisma migrate deploy"
start: "node server.js"
test: "npm test"With timeout:
commands:
release:
command: "npx prisma migrate deploy"
timeout: "5m"Bootstrap stage
The bootstrap stage is for imperative post-start setup that can only run against a running component. Typical uses:
- Creating the first admin user via a CLI that's only available inside the container
- Generating a one-time invite link or password reset token the user needs to see
- Writing runtime configuration whose values depend on the deployment's public URL (via
$app.url) and must be picked up by an already-running process
Unlike release, which runs before start in an ephemeral container and fails the whole deploy on error, bootstrap runs after start against the running component, is invoked on user request (not automatically after deploy), is re-runnable, and failures are reported rather than deploy-failing. It is the place to encode operational knowledge that today lives in READMEs ("after deploying, run docker exec … <app-cli> create-admin").
Bootstrap commands should be written to be idempotent — running them a second time should either no-op or produce a new one-time credential, not corrupt state. The spec recommends idempotency; it does not enforce it.
commands:
start: "node server.js"
bootstrap:
command: "my-app-cli create-admin --url $app.url"
capture:
invite_link:
pattern: "https?://\\S+"
description: "One-time invite link"
sensitive: true
### Command Capture
Any command that uses the expanded form can declare **captures** — named values extracted from the command's stdout via regex patterns. The platform matches each capture's regex against the command's stdout and stores the first capture group's value (or, if the pattern has no capture group, the full match).
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `pattern` | `string` | **yes** | -- | Regex matched line-by-line against the command's stdout |
| `description` | `string` | no | -- | Human-readable description of the captured value |
| `sensitive` | `boolean` | no | `false` | If `true`, value is masked in API/UI unless explicitly revealed |
Captured values are surfaced by the platform under a `$outputs.*` namespace and made available through the platform's API or UI. If a pattern does not match any line, the capture is absent (not an error).
Capture is most commonly used with `release` (for migration-time generated values) and `bootstrap` (for post-start admin creation and invite flows), but is allowed on any command that uses the expanded form:
```yaml
commands:
release:
command: "./setup.sh"
capture:
admin_password:
pattern: "Admin password: (.+)"
description: "Generated admin password from initial setup"
sensitive: true
admin_url:
pattern: "Dashboard: (https?://\\S+)"
description: "URL to the admin dashboard"
bootstrap:
command: "my-app-cli create-invite --url $app.url"
capture:
invite_link:
pattern: "https?://\\S+"
description: "One-time invite link — open in a browser to register"
sensitive: trueNote on D-23 placement supersede. Earlier versions of this spec documented capture via a top-level
outputs:field at component level. That placement has been superseded by the nestedcapture:form documented above. The capture mechanism (pattern/description/sensitive) is preserved verbatim; only the location of the capture block in the schema has changed. See DESIGN.md D-34 for the migration rationale.