An approved coordinated release publishes directly to npm's latest channel. Tests and review belong before merge;
publication reuses successful CI for the exact source. It does not repeat the suite or require a second
next-to-latest promotion. Dated observations remain in release history.
A merge alone does not authorize publication. Obtain one approval for the intended coordinated release, or use the
approval already given for that scope. The existing GitHub npm environment protection still applies; its approval
executes the same release decision. Do not ask for another conversational approval between already-approved steps.
Before 1.0.0, use ordinary 0.MINOR.PATCH versions: increase MINOR for a breaking compatibility-line change and
PATCH for a backward-compatible change within that line. Never reuse a published version or move a protected
release tag. An unpublished, untagged candidate can retain its proposed version while its source changes.
The published version may remain in source during documentation and test maintenance; recording its release history
does not require preparing another version. Choose an unused version when preparing the next publication.
CLI 0.7.x requires API 0.6.x and Plan firstdraft.foundation-plan.sketch/0.22. CLI 0.7.0 adds --staging
and requires FIRSTDRAFT_STAGING_API_TOKEN for the staging origin, including existing pinned Projects. This token
configuration change warrants a new CLI minor version; the API and Plan contracts stay unchanged. Production
remains the default and uses FIRSTDRAFT_API_TOKEN, as do custom origins. No Project is migrated. The target stays
rails-sketch/2026-09.
Local output remains the default introduced in CLI 0.4.x: firstdraft plan compile is equivalent to
firstdraft plan compile --output ., with GitHub publication selected by explicit --github. The root archive
remains .firstdraft/design. Existing applications and old Plans are not migrated.
release/compatibility.json declares the package version, accepted API-contract range, and accepted Plan formats.
It is source-only metadata, validated by the normal test suite and absent from the npm tarball. Coordinate the
explicit CLI comparator and bundled CLI pin in firstdraft/skills when this version changes. The service's
script/release_compatibility_check compares the three exact revisions; compatibility establishes eligibility,
not authorization or runtime proof. Its closed firstdraft.release-compatibility/1 format rejects unknown keys.
- Update
package.json,package-lock.json, andrelease/compatibility.json, and align the Skills CLI requirement. - Update the command, error, and Skill guidance affected by the change. When onboarding changes, coordinate the
local guide publication from the Service's
docs/guides/local-app.mdbefore the new CLI reacheslatest. Preserve dated release evidence. - Run focused checks while developing and the repository's required CI for the merge candidate. For a fresh
checkout, the complete local check is
npm ci --ignore-scripts,npm audit, thennpm run check. - Review and merge the change. Wait for the existing
CIworkflow to pass for the selectedmainSHA; publication uses that run instead of starting another one.
Use existing smoke evidence when it covers the changed behavior. If changed CLI/Service/Skill behavior warrants a
live smoke, use a simple Plan, compile locally with firstdraft plan compile --output ., and boot the generated app locally
when runtime behavior changed. A CLI dispatch-only change can be covered by local command and packed-package tests.
Do not require Codespaces, GitHub Publication, native builds, or Revyl for a routine release. Codespaces is a fallback
development environment. Additional integration checks belong only to changes affecting those integrations.
From a clean checkout of the selected main revision:
- Confirm the exact package version and
v<package-version>tag are both unused. If either identity is already consumed, prepare the next version required by the pre-1.0 policy rather than moving or reusing it. - Confirm the intended three revisions are compatible and the coordinated release approval covers them.
- Create and push
v<package-version>at that source revision. Push one release tag at a time; the workflow serializes publication and GitHub retains at most one pending run in a concurrency group. - Approve the existing
npmenvironment deployment for that tag. The workflow publishes with provenance underlatest; no separate dist-tag mutation is needed.
The workflow requires a protected v* tag in firstdraft/cli, the matching package.json version, an unchanged
remote tag, and a commit in the first-parent history of protected main. It finds a successful CI push run for
that exact SHA using gh run list, checks the package file allowlist, then rechecks mutable refs after environment
approval. It does not install development dependencies, rerun tests or audit, or request interactive npm login.
Both source checks invoke scripts/check-release-source.sh; the postapproval invocation must remain before publish.
If CI is still running, let that run finish and rerun the failed publication verification job. Resolve failing checks in CI itself; publication does not start a duplicate suite. A source fix after tagging requires a new version. Do not retest unrelated surfaces merely because time has passed since merge.
After publication, inspect the registry before retrying a failed workflow; the immutable version may already exist:
FD_CLI_RELEASE_VERSION="$(node -p "require('./package.json').version")"
npm view "@firstdraft.com/cli@$FD_CLI_RELEASE_VERSION" \
version dist.integrity dist.shasum dist.attestations repository.url engines bin --json
npm dist-tag ls '@firstdraft.com/cli'Confirm the intended version is latest and has integrity/provenance metadata. Install that exact version in a
temporary prefix, confirm firstdraft --version, and run npm audit signatures there to verify the published
artifact. This checks distribution; it does not repeat application qualification. Record the version, source,
package integrity, and any relevant smoke evidence in the dated release record.
If OIDC authentication fails, reconcile the registry version and protected tag before retrying. Correct a broken trusted-publisher relationship when necessary, then rerun failed jobs at the existing tag. If the tagged workflow identity itself is wrong, prepare a new version; never move the tag or add a persistent-token fallback.
For a bad release, move latest to a known-good compatible version as an incident rollback, or deprecate the bad
version and publish a corrected higher version. Unpublishing is exceptional incident response, not routine rollback.
These are durable repository and npm controls, not a per-release account audit. Verify them when provisioning, changing publisher configuration, or diagnosing an actual failure:
firstdraft/cliis public;mainrequires pull requests and CI, and av*ruleset restricts tag mutation.- The
npmGitHub environment is limited to release tags, requires its existing reviewer, disables administrator bypass, and definesNPM_RELEASE_ENABLED=true. - npm trusted publishing identifies package
@firstdraft.com/cli, repositoryfirstdraft/cli, workflowpublish.yml, environmentnpm, and permissioncreatePackage. The publishing account retains the intended organization access and write-protecting 2FA. Configure these with an administrator only when needed. - Publication runs on a GitHub-hosted runner with
id-token: write, pinned Node.js 24.18.0 and npm 11.16.0. npm's short-lived OIDC exchange is the only publication credential; no persistent npm token or Actions secret is used. The CI lookup uses GitHub's read-only workflow token.
Ordinary installation and use require no npm login. Ordinary trusted publication requires no local maintainer login or per-release security-key ceremony. Request npm interaction only when npm requires it for a governance change or an actual authentication failure. See npm trusted publishing.