Releasing @unbrained/pm-cli
This page is for maintainers cutting npm and GitHub releases. It assumes release work is tracked with pm.
For local progressive-disclosure routing, install guide-shell with pm install guide-shell --project, then use pm guide release.
Agent Quick Context
- Release versioning is calendar SemVer-compatible:
YYYY.M.DorYYYY.M.D-N. - Daily release preparation is owned by the GitHub Actions auto-release workflow.
- Publishing is owned by the tag-driven GitHub Actions release workflow.
- Do not run manual
npm publish. - Run local parity gates before pushing release tags.
- Use
pm guide release --jsonfor machine-readable release docs routing afterguide-shellis installed.
Tracked documentation work: pm-u9d0.
Version Policy
Examples:
- first release on 2026-05-01:
2026.5.1 - second release on 2026-05-01:
2026.5.1-2
Check the next version:
pnpm version:next
Validate the current package version:
pnpm version:check
One-Time Setup
- Use npm provenance publishing for
.github/workflows/release.ymlso GitHub-hosted release jobs publish signed packages. Keepid-token: write, Node 24 or newer, npm 11.5.1 or newer,NODE_AUTH_TOKENfrom thereleaseenvironmentNPM_TOKENsecret, andnpm publish --access public --provenance. The token must authenticate as a maintainer with read-write access to@unbrained/pm-cli. - Add
SENTRY_AUTH_TOKENas an optional GitHub Environment or repository secret when Sentry release creation and sourcemap upload should run. AddSENTRY_PERSONAL_ADMIN_TOKENfor the GitHub-hosted Sentry issue-threshold gate; CI-scoped release tokens may not have issue-read scope. The release workflow skips Sentry upload cleanly whenSENTRY_AUTH_TOKENis absent, but fails the reliability threshold gate whenSENTRY_PERSONAL_ADMIN_TOKENis absent; local maintainers should still run the token-backed Sentry gate before release. - Keep any
releaseenvironment compatible with free GitHub features. This repository is public, so environment secrets and tag/branch deployment rules are compatible with the free GitHub path; do not add paid-only release gates. - Ensure
GITHUB_TOKENhascontents: writefor GitHub Release creation. - Keep
package.jsonrepository, homepage, and bugs URLs aligned withhttps://github.com/unbraind/pm-cli. - Keep npm publishing compatible with provenance. The release workflow must keep
id-token: write, a GitHub-hosted runner, Node 24 or newer, npm 11.5.1 or newer, a validNPM_TOKEN, andnpm publish --access public --provenance.
Automated Daily Driver
.github/workflows/auto-release.yml runs once per day and can also be dispatched manually.
Policy:
- release only when commits exist after the latest release tag
- ignore
.agents/pm-only tracker commits for publish eligibility so post-release evidence and closure updates do not create a package release by themselves - release at most once per UTC day by default
- same-day follow-up release (
YYYY.M.D-N) is manual-only viaallow_same_day_release=true - release preparation must pass all quality and compatibility gates before commit+tag push
CHANGELOG.mdis generated by the latest npmpm-changelogpackage (pm install npm:pm-changelog --project, thenpm changelog generate --mode replace --all-release-tags) from closed tracker items across git release tag windows and checked in CI; do not edit it by hand- release reliability gating requires
SENTRY_PERSONAL_ADMIN_TOKENfor issue-threshold checks; Auto Release fails before creating the version commit/tag when the token is missing andpush=true, while sourcemap upload remains optional throughSENTRY_AUTH_TOKEN - after creating and pushing a new tag, auto-release dispatches
.github/workflows/release.ymlwith that tag and waits for the publish workflow to finish, because GitHub does not start normal push/tag workflows fromGITHUB_TOKENpushes
Pipeline entrypoint:
node scripts/release/run-release-pipeline.mjs
The pipeline performs:
- change detection + one-release-per-day guard
- version bump
- latest
pm-changeloginstall and main changelog refresh through package-owned full-history generation; the release pipeline passes--release-versionwith--all-release-tagsso the pending release section matches post-tag CI checks - strict gates (build, typecheck, docs/skills freshness, coverage, static quality, compatibility, security, smoke checks, reliability gate)
- release note generation from changelog + pm evidence
- commit and tag creation (plus optional push)
The generated changelog includes clickable pm item links to the tracked .toon files. Missing release evidence should be fixed in pm item history, not by hand-editing CHANGELOG.md.
Changelog Classification (Contributor-Facing)
pnpm changelog:pm routes closed pm items into keep-a-changelog sections using pm-changelog classification logic. Use explicit type/tag metadata when you want deterministic section routing.
Signal tiers:
- Strong signals: item
type+tags - Weak signal: item
title(after stripping CLI-flag-like tokens such as--add)
Category precedence (first matching bucket wins):
| Priority | Category | Trigger terms (from strong + weak signals unless noted) |
|---|---|---|
| 1 | Security |
security, cve, vulnerability |
| 2 | Deprecated |
deprecated, deprecation |
| 3 | Removed |
removed, remove, deleted, delete |
| 4 | Fixed |
fix, fixed, bug, bugfix, hotfix, regression |
| 5 | Added |
feature, feat, added, add, new |
| 6 | Changed |
strong-signal change, changed, refactor, update, updated, improve; for non-bug-like types only, title fallback is also used |
| 7 | Other |
no classifier match |
Bug-like default:
- Items with type
Issue,Bug,Bugfix, orDefectdefault toFixedunless a higher-priority category already matched. - This bug-like default runs before title-only
Changedfallback to avoid misrouting command-name issue titles (for example "pm update ..." issue reports).
Practical examples:
Issue+ titlepm update --add-tags fails->FixedTask+ tagrefactor->ChangedFeature+ tagsecurity->SecurityIssue+ tagfeature->Added(explicit stronger signal beats default)
If a changelog routing rule appears incorrect, fix classifier behavior in the pm-changelog package/repo and then consume the updated package here. Do not patch generator internals in this repository.
Local Release Parity Checklist
- Confirm or compute the version.
pnpm version:next
- Verify previous-version tracker compatibility in a temporary project before release asset edits.
Create representative data with the latest published package and then read, mutate, run linked tests, validate, and health-check the same temp PM_PATH with the current build. The temp run must use isolated PM_PATH and PM_GLOBAL_PATH; never point compatibility tests at the repository's real tracker data.
Minimum coverage:
- parent and dependency links
- comments, notes, learnings, body, reminders, events
- linked files, docs, and tests
- legacy markdown item files (including external YAML wrappers before JSON front matter) migrating cleanly to TOON
- closed issue metadata and history drift checks
- current-build write mutation and item-count preservation
- Review private reliability signals.
Use maintainer-only local workflows for reliability checks and incident triage. Keep operational details, infrastructure topology, and raw diagnostics out of tracked release documentation and release notes.
If private reliability checks identify repeated user friction, either confirm the current release already contains the remediation with regression coverage or fix it before continuing.
- Run the same release pipeline locally.
# Read-only parity check
pnpm release:pipeline:dry-run
# Full local preparation (version/changelog mutation + local commit/tag)
pnpm release:pipeline
- Push branch and tag after local green.
git push origin main
git tag v<version>
git push origin v<version>
GitHub Workflow
.github/workflows/release.yml runs on v*.*.* tags and handles:
- full-history checkout
- manual
workflow_dispatchby tag for automation handoff or recovery when a tag already exists - pnpm install with frozen lockfile
- version policy and tag guard
- secret scan
- build, typecheck, test, and coverage
- static quality gate (complexity, duplication, dead/orphan module, file/folder hygiene)
- temporary-project compatibility gate against latest published tracker data
- reliability threshold gate (Sentry severity threshold;
--telemetry-modegate policy:off|best-effort|required) - sandboxed
pmcoverage - optional Sentry release metadata and sourcemap upload when
SENTRY_AUTH_TOKENis configured - npm pack dry run and npx tarball smoke test
- generated release notes from changelog plus sanitized tracker metadata
- artifact uploads
npm publish --access public --provenance, skipped on retry when the exact version is already present on npm- post-publish npm/npx/bunx verification through
scripts/release/verify-published-release.mjs - GitHub Release creation
- GitHub Release metadata verification through the same local verification script
Monitor:
gh run list --workflow Release --limit 5
gh run watch <run-id> --exit-status
Post-Release Verification
npm view @unbrained/pm-cli@<version> version dist.integrity dist.unpackedSize --json
npx --yes --package @unbrained/pm-cli@<version> -- pm --version
bunx --bun @unbrained/pm-cli@<version> pm --version
gh release view v<version> --json tagName,name,isDraft,isPrerelease,url
pnpm release:verify-published -- --version <version>
The executable remains pm even though the npm package is scoped.
Use the npm registry package for maintainer global updates. Do not use npm install -g https://github.com/unbraind/pm-cli.git as the normal update path; npm can leave a stale shim while replacing git-sourced global installs. If a workstation is already in that state, run bash scripts/install.sh --repair or npm uninstall -g @unbrained/pm-cli && npm install -g @unbrained/pm-cli@latest.
Failure Handling
- If local gates fail, fix and rerun before tagging.
- If the tag workflow fails before npm publish, confirm no package was published before moving or replacing a tag.
- If npm publish succeeds but GitHub Release creation fails, rerun
.github/workflows/release.ymlwithworkflow_dispatchandtag=v<version>; the workflow skips duplicate npm publish, reruns public verification, and creates the GitHub Release for the existing tag. - Record failure evidence and remediation in the release
pmitem.
Silent skip debugging
When auto-release exits green but does not cut a version, inspect the pipeline's JSON skip reason from scripts/release/run-release-pipeline.mjs (or rerun locally with pnpm release:pipeline:dry-run -- --json):
- tracker-only skip family:
tracker_only_changes_since_last_tag(all changed paths are.agents/pmonly) - changelog-empty skip family:
empty_generated_changelog_section_for_target_version(generated release section exists but has no non-empty entries)
pm-changelog is maintained in a separate repository/package. Classifier or release-window bugs must be fixed and released there first, then consumed here via the latest npm package (pm install npm:pm-changelog --project) before rerunning release generation.
Before local changelog regeneration diagnostics, always refresh tags first:
git fetch --tags --force
Without a forced tag refresh, local tag windows can drift from origin and produce misleading changelog or skip diagnostics.