cli-forge Publish
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.yml or takeover-receipt.yml), and optional extend-receipt.yml against the provenance snapshot recorded in validation-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
- 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
- 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: run npm run release:rehearse locally. This builds every target, syncs platform packages, and runs npm publish --dry-run for each. No tag, no GitHub Release, no real npm publication. - prepublish: run npm run release:prepublish locally. 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 interactive npm login, surface the verification URL, and continue only after the user completes browser verification. - live_release: push to main (or workflow_dispatch) so the target repository's .github/workflows/release.yml, restored from the installer-safe asset-pack resource dot-github/workflows/release.yml, drives the end-to-end run. Do not proceed to live_release until 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.