Use this stage when a compliant generated CLI skill needs to adopt standard release automation, prepare a new version, or execute the paired GitHub Release + multi-package npm publication flow.
Purpose
Manage the release pipeline for a generated cli-forge skill.
This stage owns the bootstrap + production publication flow:
- a required local prepublish step for the main package plus all platform packages
- the paired repo-native GitHub Release plus platform-split npm publication from the later semantic-release event
One production release produces:
- git tag
v<version>+ GitHub Release (archive + sha256 per target) - 6 per-platform npm packages (
<pkg>-darwin-arm64/-darwin-x64/-linux-arm64/-linux-x64/-win32-arm64/-win32-x64) carrying the native binaries - 1 main npm package (JS shim,
optionalDependenciespinned to the same version) CHANGELOG.mdentry +chore(release): <version> [skip ci]commit
All npm packages publish in one semantic-release run and share the
version with the git tag + GitHub Release. The total count is
1 + config.targets.length (default: 7).
Canonical References
./instructions/release/skill-release-runbook.md./planning-brief.md./shared-planning-brief.md./contracts/release-receipt.yml.tpl./templates/
Entry Gate
| # | Check | Source |
|---|---|---|
| 1 | validation-report.yml exists, is fresh, and result == compliant or warning |
Validate |
| 2 | Target repository path is explicitly known | Router / User |
| 3 | Requested publish mode is explicit | Router / User |
| 4 | npm package naming contract, CLI name, and scope decisions are explicit | User |
Scope decisions are required inputs at this stage. Collect the main package
name plus the scope policy for both the main package and the platform
packages. The main package and platform packages may use different scopes, but
platform names must still derive from the main package body plus
-<target-suffix>.
Required Inputs
- Validation outcome plus provenance snapshot (refusal to publish if
non_compliant, stale, or provenance-mismatched) - Publish mode:
report_only,dry_run,prepublish, orlive_release - Source project path
cliName— the CLI binary namemainPackageName— the main npm package name (with scope prefix if scoped)mainNpmScope—nullfor unscoped, or the scope string for the main packageplatformNpmScope—nullfor unscoped platform packages, or a separate scope stringsourceRepository—owner/repoon GitHub
Workflow
- Read
./planning-brief.mdfor publish-specific planning constraints. - Accept the inbound
validation-report.yml. Refuse to proceed if validation failed; do not re-run validation here. - Verify validation freshness before any publish-mode action:
- compare the current
.cli-forge/design-contract.yml,.cli-forge/cli-plan.yml, baseline receipt (scaffold-receipt.ymlortakeover-receipt.yml), and optionalextend-receipt.ymlagainst the provenance snapshot recorded invalidation-report.yml - for takeover-adopted baselines, require the report provenance to match the current adopted contract + receipt set exactly; do not rely only on the aggregate validation result
- if any required baseline artifact is missing, has a different receipt, or takeover recorded contract/baseline rewrites after validation, stop and route back to Validate
- compare the current
- Ask the user for the inputs listed above if not already collected. If the
mode is
report_only, skip to step 7. - If the skill project lacks the release automation assets, adopt them by
copying the contents of
./templates/to the project root while restoring the install-safedot-*resource aliases to their real dot-prefixed target paths (dot-releaserc.json -> .releaserc.json,dot-github/ -> .github/,npm/platforms/dot-gitkeep -> .gitkeep). The adopted asset pack does NOT contain Scaffold-stage source templates (*.tpl). - Fill
release/config.jsonandnpm/main/package.jsonwith the collected inputs.release/config.jsonmust explicitly recordmainPackageName,mainNpmScope, andplatformNpmScope. - Verify the target repository has:
- GitHub Actions enabled on a GitHub-hosted runner with
id-token: write - npm trusted publishing configured on npmjs.com for the main package and
for each of the 6 platform packages, every entry pointing at
release.yml
- GitHub Actions enabled on a GitHub-hosted runner with
- Follow the mode path defined in
./instructions/release/skill-release-runbook.md:report_only: audit readiness only. Read config and repository state, report blockers and next actions. Do NOT copy files, fill placeholders, or alter the repository in any way.dry_run: runnpm run release:rehearselocally. This builds every target, syncs platform packages, and runsnpm publish --dry-runfor each. No tag, no GitHub Release, no real npm publication.prepublish: runnpm run release:prepublishlocally. This performs a real public npm bootstrap publish for every platform package and the main package using a dedicated bootstrap prerelease version. If local auth is missing, pause for interactivenpm login, surface the verification URL, and continue only after the user completes browser verification.live_release: push tomain(orworkflow_dispatch) so the target repository's.github/workflows/release.yml, restored from the installer-safe asset-pack resourcedot-github/workflows/release.yml, drives the end-to-end run. Do not proceed tolive_releaseuntil prepublish bootstrap has completed for the configured package set.
- Generate
.cli-forge/release-receipt.ymlfrom the template at./contracts/release-receipt.yml.tpl.
Outputs
- A verified prepublish bootstrap for 1 main + N platform npm packages (if
prepublish) - A verified GitHub Release with archives + checksums (if
live_release) - 1 main + N platform npm packages published at the same production version (if
live_release) - Updated
CHANGELOG.mdand release commit onmain .cli-forge/release-receipt.yml
Exit Gate
| # | Check |
|---|---|
| 1 | The requested mode was executed |
| 2 | For report_only: no files were written to the target repository |
| 3 | For dry_run / prepublish / live_release: asset pack adopted and filled |
| 4 | For prepublish: the bootstrap npm prerelease completed without creating a tag or GitHub Release |
| 5 | For live_release: version, tag, main package, platform packages agree |
| 6 | release-receipt.yml generated |
Guardrails
- All npm packages (main + platforms) MUST share the version chosen by
semantic-release. The two release scripts enforce this by consuming
${nextRelease.version}from semantic-release hooks. - The bootstrap prepublish step MUST use a dedicated prerelease version such as
0.0.0-prepublish.N. It is not a production release. - Main and platform packages may differ only by scope. Do not introduce arbitrary per-platform package base names.
- Do not bypass stale validation. If the codebase changed since the last validation report, route back to Validate.
- For takeover-adopted repositories, freshness checks MUST verify provenance
against the current contract + receipt set, not just
validation-report.ymlaggregate status or timestamp. - Do not hand-bump
npm/main/package.json#version, hand-editCHANGELOG.mdrelease entries, or create tags outside semantic-release. - Interactive
npm loginguidance belongs only to localprepublish. Production CI publication must continue to rely on trusted publishing. - Do not leave
dot-*alias names in the target repository. Those names exist only inside this skill package so.agentsinstallers preserve the assets. - The asset pack's
npm/platforms/directory is generated at release time. Do not check generated platform package directories into source control beyond the.gitkeepplaceholder.
Next Step
This is a terminal stage.