| name | plasmite-release-manager |
| description | Carefully run Plasmite releases end-to-end with fail-closed pre-release QA, split build/publish workflow mechanics, provenance validation, and post-release delivery verification across crates.io, npm, PyPI, Homebrew, and release artifacts. Use when asked to prepare, dry-run, execute, audit, or recover a release (including publish-only reruns after credential fixes). |
Plasmite Release Manager
Authoritative runbook for Plasmite releases. Keep execution fail-closed and aligned with workflow behavior.
Required Inputs
release_target (for example v0.4.0)
mode (dry-run or live)
agent_id (model@host)
Release Invariants (Non-Negotiable)
- Publish only from a successful
release build run with matching release metadata.
release-publish must gate registry publish on Homebrew tap sync/alignment.
- Release remains fail-closed across channels (no partial success treated as done).
- Registry/package versions must equal
release_target.
- Secrets must exist:
NPM_TOKEN, PYPI_API_TOKEN, CARGO_REGISTRY_TOKEN.
- Homebrew tap is updated locally (not via CI secret). The maintainer pushes the formula from their
../homebrew-tap checkout; the sync-homebrew-tap CI job verifies alignment.
- Tooling pins in workflows are policy:
RELEASE_RUST_TOOLCHAIN=1.88.0
- Do not release from a commit with red or missing
ci.yml; the release commit must have a completed/successful CI run.
Pre-Release Setup
- Confirm runtime/auth:
- Confirm version alignment:
bash scripts/check-version-alignment.sh
- Finalize the changelog:
- Rename
## [Unreleased] to ## [<version>] - <YYYY-MM-DD> in CHANGELOG.md.
- Review that the section accurately covers all notable changes since the previous release (check
git log <base_tag>..HEAD --oneline).
- Add a fresh empty
## [Unreleased] heading above the new section.
- The changelog must be committed and pushed before tagging. The
release job extracts it for GitHub Release notes.
- Bump version:
bash scripts/bump_version.sh <version>
- Initialize/reopen release evidence (derives
base_tag):
bash skills/plasmite-release-manager/scripts/init_release_evidence.sh --release-target <vX.Y.Z> --mode <dry-run|live> --agent <model@host>
- Confirm the release commit is green in
ci.yml before tagging/publishing:
release_sha="$(git rev-parse HEAD)"
gh run list --workflow ci.yml --commit "$release_sha" --limit 5 --json headSha,status,conclusion,url
- Require one run where
headSha == release_sha, status == completed, and conclusion == success.
Required QA Gates
Run before any publish dispatch:
- Changelog: verify
CHANGELOG.md has a ## [<version>] - <date> section (not [Unreleased]) and the version matches the release target.
- Canonical gate:
just release-gate
- This is the single source of truth for required deterministic pre-release checks.
- Includes
bindings-test (which runs node_pack_smoke.sh and node_remote_only_smoke.sh) plus python_wheel_smoke.sh.
- Keep this recipe aligned with release policy instead of duplicating command lists in multiple docs.
Run conditional gates when relevant:
- dependency/security changes:
cargo audit --db .scratch/advisory-db --no-fetch --ignore yanked
- hot-path/storage changes:
bash skills/plasmite-release-manager/scripts/compare_local_benchmarks.sh --base-tag <base_tag> --runs 3
- server/UI/auth changes:
cargo test -q --test remote_integration
Any failed required gate blocks release progression.
Build And Publish Procedure
- Ensure release source is pushed and tag exists/planned.
- Run
release.yml (tag push or manual dispatch with tag). Wait for all matrix jobs to succeed.
- Update the Homebrew formula locally and push:
bash scripts/update_homebrew_formula.sh <release_target> ../homebrew-tap --build-run-id <build_run_id>
cd ../homebrew-tap && git add Formula/plasmite.rb && git commit -m "plasmite: update to <version>" && git push
- Rehearse publish (recommended before first live dispatch):
gh workflow run release-publish.yml -f release_tag=<release_target> -f rehearsal=true
- Run live publish:
gh workflow run release-publish.yml -f release_tag=<release_target> -f rehearsal=false
Dispatch policy:
- Prefer
release_tag dispatch for normal operation.
- Use explicit
build_run_id only for incident recovery reruns.
- Optional explicit provenance proof:
bash skills/plasmite-release-manager/scripts/inspect_release_build_metadata.sh --run-id <build_run_id> --expect-tag <release_target>
Failure Handling
On any release workflow failure:
- Stop progression.
- Collect evidence:
gh run view <run-id> --json url,jobs --jq '{url,jobs:[.jobs[]|select(.conclusion=="failure")|{name,url:.url}]}'
gh run view <run-id> --log-failed
- If
sync-homebrew-tap fails: update and push the formula from the local ../homebrew-tap checkout (see Build And Publish Procedure step 3), then rerun.
- If registries fail with "already published" (npm 403, crates.io "already exists"): the packages are live. Create the GitHub Release manually with
gh release create using artifacts downloaded from the build run (gh run download <build_run_id>).
- If incident-class failure, file a blocker:
bash skills/plasmite-release-manager/scripts/file_release_blocker_with_evidence.sh --release-target <release_target> --check "<gate>" --title "<title>" --summary "<summary>" --run-id <run-id> --agent <model@host>
Resume Checkpoint
If interrupted:
git status --short --branch
gh run list --workflow release --limit 1 --json databaseId,conclusion
gh run list --workflow release-publish --limit 1 --json databaseId,conclusion
Post-Release Verification
Mandatory checks:
- GitHub release + assets:
gh release view <release_target>
- crates.io:
- npm:
npm view plasmite version
- PyPI:
curl -sS https://pypi.org/pypi/plasmite/json | jq -r '.info.version'
- Homebrew formula:
gh api repos/sandover/homebrew-tap/contents/Formula/plasmite.rb -H "Accept: application/vnd.github.raw"
- CI status for the release commit:
release_sha="$(git rev-list -n 1 <release_target>)"
gh run list --workflow ci.yml --commit "$release_sha" --limit 5 --json headSha,status,conclusion,url
- Require one run where
headSha == release_sha, status == completed, and conclusion == success.
- Delivery smoke script (required for live releases):
- fast lane (default):
bash scripts/post_release_delivery_smoke.sh --version <X.Y.Z>
- deep lane (slower, includes cargo-install validation):
bash scripts/post_release_delivery_smoke.sh --version <X.Y.Z> --channels npm,pypi,crates,homebrew
- CI option (ubuntu-safe default):
gh workflow run post-release-smoke.yml -f release_version=<X.Y.Z>
- Today that workflow defaults to
npm,homebrew; use the local smoke script on a wheel-supporting host for PyPI runtime validation.