name: npm-release-contract-guard description: Use when publishing NextClaw NPM packages or NPM runtime update channels, including beta/stable dist-tags, nextclaw@beta validation, runtime bundle manifests, packaged update public keys, and npm registry closure checks.
NPM Release Contract Guard
Overview
- Use this skill for NextClaw NPM package releases and NPM runtime update channel releases.
- Keep desktop release work in
desktop-release-contract-guard; do not add another release orchestration layer. - The goal is to prevent three mistakes:
- treating an NPM package publish as complete before registry verification
- publishing top-level
nextclawwhile leaving runtime workspace dependencies stale - shipping
nextclawwithout the packaged runtime update public key - treating an env-only runtime update test as a real user beta validation
Scope
nextclawNPM package publishing, including beta and stable dist-tags.- Workspace package release batches when they include NPM packages.
- NPM runtime update bundles under
npm-runtime-updates/<channel>. - User-facing validation of
nextclaw@betaor stable NPM installs. - Not desktop DMG/installer/update-manifest publishing.
Primary Contracts
- Prefer the repo release flow; do not publish from package folders with raw
npm publish. - Before any publish attempt, verify npm auth with the same npm config source that the publish command will use. If publishing from a temp worktree or copied checkout, first check whether the project root has a private
.npmrc; when it does, run publish and post-publish registry/install verification withNPM_CONFIG_USERCONFIG=<project-root>/.npmrcinstead of assuming the user-level npm login is the source of truth. - A published
nextclawpackage must includeresources/update-bundle-public.pem. - Publishing, build, and verification commands must not leave generated artifacts in the active worktree. After release commands finish, run
git status --short; every generated change must either be intentionally committed as part of the release record or removed/restored before final response. - The published package must include both launcher and app runtime entries:
dist/cli/launcher/index.jsdist/cli/app/index.js
- Do not treat
nextclawas a standalone CLI package. Its real installed behavior comes from the published dependency closure, especially runtime packages such as kernel, service, server, NCP packages, runtime adapters, and UI assets when applicable. - If
nextclawdepends on a workspace package whose local source changed meaningfully, or whose local version has not been published, that package must be versioned and published in the same batch beforenextclaw. - NPM runtime update manifests must use
hostKind: "npm-runtime-bundle". minimumLauncherVersionfor NPM runtime bundles comes frompackages/nextclaw/npm-runtime-compatibility.json.- Do not raise
minimumLauncherVersionunless the launcher-side contract really broke.
Release Range Decision
Before deciding the package range, write down the release range and the reason. Do not infer it from the visible package name alone.
- Identify whether users install through
nextclaw, a runtime update channel, or a lower-level@nextclaw/*package. - If the release includes
nextclaw, inspectpackages/nextclaw/package.jsonruntime dependencies. Treat allworkspace:*@nextclaw/*dependencies, plus any changed transitive runtime package they depend on, as the candidate release closure. - Run
pnpm release:report:healthand compare the output with the closure. Any dependency with meaningful unpublished drift must either be included in the release batch or explicitly proven irrelevant to the installed user path. - If the user says "全部发布", "直接发布", "完成全部", or reports a hard-to-debug installed-version mismatch, prefer the full public workspace batch through the repo release flow. Do not hand-pick only
nextclaw. - A narrower-than-closure release is allowed only when all of these are true:
- the user explicitly wants a narrow release,
- every excluded workspace dependency is already published at the exact version referenced by the candidate package,
- a packed or temporary install proves the installed dependency closure contains the required runtime APIs/assets,
- the final answer names the intentionally excluded packages and why they are safe to exclude.
Never justify a single-package nextclaw release only because packages/nextclaw contains copied ui-dist or because nextclaw --version will show the new version. The UI version label, CLI version, and actual runtime behavior can diverge when kernel/service/NCP/UI dependency packages remain stale.
Package Release Flow
- Prefer the reusable beta owner when the request is specifically "发布 beta / 统一 beta 发版":
pnpm release:betapnpm release:beta:npmpnpm release:beta:runtime
- Sync and check package README content:
pnpm release:sync-readmespnpm release:check-readmes
- Decide and prepare the release range:
- for full public workspace release:
pnpm release:auto:changeset - for a narrow release: create or inspect the changeset and document why the excluded dependency closure is safe
- for full public workspace release:
- Prepare versions with the repo release flow:
pnpm release:version
- For a release batch that includes
nextclaw, make sure the packaged update public key exists before publish:NEXTCLAW_UPDATE_BUNDLE_PRIVATE_KEY=... pnpm -C packages/nextclaw runtime-update:build -- --channel beta --skip-build --output-dir tmp/npm-runtime-update-key-check- Use
--channel stablefor stable releases.
- Publish through the repo release flow:
pnpm release:publish
- Verify the registry state:
pnpm release:verify:publishednpm view nextclaw dist-tags --json- For a first publish of a scoped standalone package, an immediate
npm viewornpm installmay briefly return 404 after a successful publish. Retry with the same npm config used for publish before declaring failure; do not rerun publish unless registry verification proves the version is absent after propagation.
- Close generated artifacts:
- Run
git status --shortin every worktree used for release or verification. - If release commands refreshed tracked publish assets such as
packages/nextclaw/ui-dist, decide explicitly whether they are part of the release record. - Commit intended release artifacts before final response; restore tracked drift and remove untracked generated files when they are only local build hash churn.
- Never leave dirty generated publish assets for the user to notice after a claimed release closeout.
- Run
Branch And Source Closure
- If publishing from a temporary worktree, release branch, detached HEAD, or any branch other than the user's current target branch, do not close after registry verification alone.
- Before the final answer, explicitly compare the target branch with the release branch and classify the remaining delta:
- source code needed for the user-visible fix,
- version / changelog / generated package artifacts,
- historical release baseline commits,
- unrelated changes.
- If user-facing source code is missing from the target branch, merge or cherry-pick it before saying the task is done, unless the user explicitly rejects that.
- If only release metadata or generated artifacts remain outside the target branch, say that plainly and name the exact follow-up: merge the release branch, cherry-pick the release commit, or intentionally leave release history separate.
- The final release notes must answer: "Is the target branch missing functional code?" and "Is the target branch missing published release records/artifacts?" Avoid wording that makes the user infer this from branch names or commit hashes.
Beta Package Rule
- Prefer the repo changeset/pre-release flow for beta releases.
- Prefer
pnpm release:betafor the full reusable closure when the batch may includenextclaw; by default this means one full public workspace beta batch, not a hand-picked subset. - Prefer
pnpm release:beta:npmonly when the need is “publish beta packages now, do not yet open the runtime update channel”; it still inherits the full-public-batch expectation unless the user explicitly asks for a narrower scope. - Prefer
pnpm release:beta:runtimewhennextclaw@betais already published and the remaining work is only the runtime update channel. - Use a hand-authored changeset or dedicated one-off flow for narrower scope only after telling the user the release is not a full public beta batch.
- If a single-package beta publish is unavoidable, use pnpm:
pnpm -C packages/nextclaw publish --tag beta
- After publish, verify the tag directly:
npm view nextclaw@beta versionnpm view nextclaw dist-tags --json
Pre-Publish Blocker Scan
Before publishing nextclaw@beta, run a blocker scan and resolve everything found:
- workspace dependency closure: compare
nextclawimports against changed workspace packages; any package providing a new runtime API must get its own beta version and dist-tag, - for stable
nextclaw@latest, prove any narrower-than-closure release with a packed install dependency check; otherwise use the affected public workspace batch, - packed API check: install the exact packed or published dependency closure in a temp prefix and verify critical APIs exist, especially recently added methods,
- real install smoke: from a temp prefix, install
nextclaw@betaor the candidate tarball and run at leastnextclaw --versionplus one minimal command path touching the changed runtime area, - for stable
nextclaw@latestpublishes, the real install smoke must includenextclaw update --checkfrom an isolatedNEXTCLAW_HOMEwithoutNEXTCLAW_UPDATE_BUNDLE_PUBLIC_KEYorNEXTCLAW_UPDATE_BUNDLE_PUBLIC_KEY_PATH; this proves the packaged public key is discoverable by the published package, - runtime update smoke: after channel publication, run check/download/apply/new-process from a temp
NEXTCLAW_HOME.
For the published beta install smoke, prefer the repo command:
pnpm -C packages/nextclaw validation:npm-update -- --published-beta
If a scan item would be slow manually, create or improve a script instead of skipping it. The goal of the retrospective loop is to turn slow release surprises into one-command preflight checks.
Retrospective Loop
After every NPM beta/stable release attempt, record the blockers that consumed time and convert at least one repeated blocker into a concrete mechanism:
- skill rule update,
- release preflight script,
- CI gate,
- smoke command,
- or explicit follow-up if the improvement is larger than the current release window.
Do not close a release attempt with only a narrative retrospective when the blocker can be cheaply automated or encoded as a release gate.
Runtime Update Channel Flow
- Trigger
.github/workflows/npm-runtime-update-release.ymlfor the target channel.- Or use the reusable owner command:
pnpm release:beta:runtime
- Or use the reusable owner command:
- Wait for the workflow conclusion to be
success; dispatch alone is not a release. - Verify
gh-pagescontains the channel files:npm-runtime-updates/<channel>/manifest-<channel>-<platform>-<arch>.jsonnpm-runtime-updates/<channel>/nextclaw-runtime-<platform>-<arch>-<version>.zipnpm-runtime-updates/update-bundle-public.pem
- Verify the public GitHub Pages URL reflects the same manifest version.
- Confirm the manifest has the expected
latestVersion,minimumLauncherVersion, andhostKind.
User-Facing Beta Validation
- Validate the exact published package, not a workspace link or local source build. Install or reinstall the published version first:
npm install -g nextclaw@beta
npm ls -g nextclaw --depth=0
nextclaw --version
- Confirm the running non-dev service uses the global npm package path, for example
.../lib/node_modules/nextclaw/dist/..., not.../Projects/nextbot/packages/nextclaw/dist/.... - Validate from an isolated home when testing update behavior so local development state is not involved:
export NEXTCLAW_HOME="$(mktemp -d)"
nextclaw update --channel beta --check
nextclaw update --channel beta --download-only
nextclaw update --apply
nextclaw --version
- Expected behavior:
--checkdetects the beta update without downloading.update --channel beta --download-onlydownloads and verifies the runtime bundle without switching the active runtime.update --applyswitches the active runtime pointer.- the next
nextclawprocess runs the downloaded runtime version.
For split download/apply smoke tests, do not run plain nextclaw update --channel beta before --apply: plain update may download and apply in one step, leaving no pending downloaded version for the later --apply command.
Completion Gate
- The NPM registry shows the intended package version and dist-tag.
- The published
nextclawdependency closure contains the runtime APIs used by thenextclawpackage. - The runtime update workflow finished successfully.
- The public manifest URL shows the expected version and compatibility floor.
- A real
nextclaw@betaor stable install can check, download, and apply without custom manifest URL or public key env vars. - Every release/target worktree used in the task is clean, or the final response explicitly names a user-owned WIP that was intentionally preserved. Generated artifacts from the release itself are never left dirty: they are either committed or cleaned.
- Final release notes must include:
- NPM package version
- dist-tag
- workflow URL
- public manifest URL
- exact user-facing validation commands and result
Forbidden Shortcuts
- Do not use raw
npm publishas the default release path. - Do not publish
nextclawwithoutresources/update-bundle-public.pem. - Do not claim release success after workflow dispatch only.
- Do not count an env-only
NEXTCLAW_UPDATE_MANIFEST_URLtest as user beta validation. - Do not raise
minimumLauncherVersionjust because a new package version exists.