# Headless durable releases The devkit `release` commands use the **same release application, request validation, run store and bounded executors** as the [release console](RELEASE_CONSOLE.md). They invoke its ASGI application inside the current process, with an ephemeral internal token. No listening socket, background server, browser session or externally supplied console URL is used. The development environment's FastAPI/HTTPX dependencies load only when a release command runs; ordinary devkit help does not import them. This is a GovOPlaN-specific provider. Repository and origin authority still comes from the release service's registered catalog. `--project` is explicitly rejected for release commands; a portable project configuration must not silently override that authority. A different workspace path does not authorize arbitrary release repositories, remotes, commands, signing policies or source bindings. The default compact output includes the overall status, selected repository states and versions, source-preflight readiness, bounded gate findings and the recommended next action. Run inspection also shows step-state counts and the first outstanding steps. These are projections of the service response, not new readiness checks. Use `--json` for the complete existing plan or receipt; compact output deliberately omits executor commands, arguments and source bindings. ## Commands and boundaries | Command | Purpose | Effect boundary | | --- | --- | --- | | `release status` | Current release dashboard | Offline by default; explicit remote/catalog flags enable their checks | | `release plan` | Selective repository/version plan | Inspection only; does not create a run | | `release list` | Bounded run history, with `--limit` and `--cursor` | Existing workspace-scoped store | | `release show RUN_ID` | Exact verified run, steps, receipts and required confirmations | No release execution | | `release create` | Freeze a selected repository/version plan | Preview by default; `--apply` persists a run | | `release preview RUN_ID STEP_ID` | Frozen step and its current constraints | No step claim; catalog publication additionally uses the existing validated-candidate preview | | `release execute RUN_ID STEP_ID` | One available durable step | Preview by default; `--apply`, explicit request ID and the step's exact confirmation are required | | `release resume RUN_ID` | Mark persisted running attempts interrupted | Requires `--apply`; never assumes an effect succeeded | | `release retry RUN_ID STEP_ID` | Prepare an eligible failed/read-only-interrupted step | Requires `--apply`; does not execute it | | `release reconcile RUN_ID STEP_ID` | Record a proven uncertain-write outcome | Requires `--apply`, `--confirm RECONCILE` and an explicit outcome | Create and transition commands require caller-chosen `--request-id` values. Retain the same ID for an uncertain replay of the **same** command; changing inputs under an existing ID fails closed. No command automatically retries a mutation. These commands perform one explicit transition, not an implicit "release everything" loop. Read commands do not commit, tag, push, publish or apply database migrations. The existing private run store can initialize its lock directory or upgrade a legacy record while inspecting it; this does not advance release steps. `--include-migrations` requests the existing audits, never migration application. `--online`, `--remote-tags` and `--public-catalog` are explicit network-check choices. A generic step preview describes frozen intent; it is not a claim that live preflight, remote identity or release acceptance has passed. ## Example: review, freeze and execute one step Run the devkit through the workspace `./devkit` entrypoint. These examples put global options before `release`: ```sh ./devkit --workspace-root /path/to/workspace --format json release plan \ --repo-version govoplan-files=0.1.9 ./devkit --workspace-root /path/to/workspace release create \ --repo-version govoplan-files=0.1.9 --request-id files-release-create-0001 ./devkit --workspace-root /path/to/workspace release create \ --repo-version govoplan-files=0.1.9 --request-id files-release-create-0001 --apply ./devkit --workspace-root /path/to/workspace release show RUN_ID ./devkit --workspace-root /path/to/workspace release preview RUN_ID STEP_ID ./devkit --workspace-root /path/to/workspace release execute RUN_ID STEP_ID \ --request-id files-release-step-0001 --confirm REQUIRED_CONFIRMATION --apply ``` `RUN_ID`, `STEP_ID` and `REQUIRED_CONFIRMATION` stand for the actual values returned by the frozen run. For read-only preflight/alignment/install-verification steps, omit `--confirm` when the service reports an empty confirmation. Metadata, commit, release-lock, source-tag, source-push, candidate-generation and catalog publication steps keep the existing `UPDATE`, `COMMIT`, `LOCK`, `TAG`, `PUBLISH`, `GENERATE` and `PUSH` confirmations respectively. Prerequisite ordering is enforced by the same store; a later step cannot be forced through this adapter. Version selection supports repeated `--repo-version REPO=VERSION`, or repeated `--repo REPO` with `--target-version VERSION`. Every created run needs explicit versions for all selected repositories. Conflicting version assignments are rejected. Planning is selective; repositories are never silently selected merely because their worktrees are dirty. ## Candidate publication and recovery Use the frozen run's `catalog:selective-generator` and `catalog:validate-sign-publish` steps, not the disabled legacy mutation endpoints. Generation accepts repeated `--signing-key KEY_ID=PRIVATE_KEY_FILE`; these are operator-owned key-file references, never inline key material. Signing arguments are not emitted in devkit JSON or persisted by the adapter. Publication consumes the candidate receipt created by that run, not an arbitrary candidate directory. The existing source/runtime trust, immutable tag/remote identity, private candidate checks and exact commit-delta checks remain authoritative. After an interrupted write, inspect the run and the actual local/remote effect. Use `resume --apply` if an attempt was left running. Then use `reconcile` with `effect_absent`, `effect_succeeded` or `unresolved`, `--confirm RECONCILE`, a new reconciliation request ID and `--apply`. Successful reconciliation still performs the service's independent receipt checks. An unresolved effect must not be retried or papered over by generating a new request ID. A failed/read-only attempt may use `retry --apply` and a new explicit execute attempt only when the existing lifecycle makes that safe. ## State and limitations Every successful response exposes `state_location` and `candidate_location`. Without `--state-dir`, the adapter uses the console's existing default private, workspace-fingerprinted state directory. With `--state-dir PATH`, it uses `PATH/release-console/workspace-/release-runs`. Workspaces cannot read or resume one another's runs. Existing ownership, symlink, permission, retention and record-integrity checks are unchanged. Release preparation can commit only the recognized, receipt-bound metadata changes its executors produced. This command does **not** stage arbitrary source changes, use `git add -A`, force-push, retarget tags or enable the disabled generic prepare/sync/push endpoints. Normal selected-path maintenance requires its own explicit reviewed-change workflow; it is not silently folded into release.