Releasing heptabase-cli-skills
This repo ships a public plugin package installed via the Claude Code marketplace, Cursor, npx skills, and OpenCode. Claude Code caches installed plugins by resolved plugin version, so users only receive updates when the version changes — pushing commits without a bump ships nothing.
Conventions (and why)
.claude-plugin/plugin.jsonversionis the single source of truth. Claude Code resolves the version as:plugin.json→marketplace.jsonplugin entry → commit SHA. Never add aversionto amarketplace.jsonplugin entry — it would silently shadow future strategy changes..cursor-plugin/plugin.jsonmust mirror the same version on every release (Cursor reads its version from that file).- Tag format:
vX.Y.Zmatching the manifest version. - GitHub release title:
Compatible with CLI v<range>, where<range>ismetadata.heptabase-cli-version-rangefromskills/heptabase-cli/SKILL.md(e.g.0.4.x→ "Compatible with CLI v0.4.x"). The title states compatibility, not features, and stays identical across releases in the same CLI range. - Release notes are auto-generated from merged PR titles (
--generate-notes). There is no CHANGELOG file. This means changes should land via PRs with clear conventional-commit titles (feat: ...,fix: ...) — the PR title is the changelog entry.
Version bump rules
| Bump | When |
|---|---|
| patch | Documentation-only skill fixes; no CLI compatibility change |
| minor | New CLI commands supported, new non-breaking CLI behavior, or a new CLI compatibility range |
| major | Rare package-level changes only: plugin rename, removing the primary skill, changing the distribution model |
Bundled scripts
Run from anywhere inside the repo; they locate the repo root themselves.
scripts/bump-version.mjs <patch|minor|major|X.Y.Z> [--dry-run]— updates both plugin manifests together (prepares both replacements, writes both, then re-reads to verify). Refuses to run if the manifests are out of sync, the target version does not advance, or a manifest does not contain exactly one"version": "…"needle. Prints JSON. It does NOT touchmetadata.heptabase-cli-version-range— that is a judgment call (step 5).scripts/preflight.mjs [--skip-validators]— read-only release-readiness report: manifest sync, marketplace version rule, CLI range consistency (frontmatter vs prose), installed CLI vs declared range, clean tree, branch, tag availability, version advances past the latest origin tag (falls back to local tags only when origin is unreachable), and the three official validators (skills-ref,claude plugin validate, Cursor manifest). Exits non-zero on any FAIL. Prints the exact release-plan commands only when tag-ready: no FAILs, clean tree, onmain, not behindorigin/main, and validators were not skipped. On a feature branch it may still pass with no FAILs and tell you to land the PR first.
Release process
- Review what shipped since the last release to choose the bump:
git log $(git describe --tags --abbrev=0)..HEAD --oneline gh pr list --state merged --limit 20 - Decide the bump type using the rules above. If the changes span categories, the highest category wins. Confirm with the maintainer when ambiguous.
- Create a feature branch from updated
main(do not bump or commit release changes directly onmain):git checkout main && git pull git checkout -b release/vX.Y.Z - Bump the version:
node .claude/skills/release/scripts/bump-version.mjs patch - Only if the supported CLI range changed (e.g. CLI 0.4.x → 0.5.x): update
metadata.heptabase-cli-version-rangeinskills/heptabase-cli/SKILL.md— in both the frontmatter and the prose sentence under Prerequisites that repeats the range. Preflight verifies they agree. - Commit the bump (and any CLI-range edit). Preflight requires a clean tree, so do not run it against uncommitted manifest edits.
- Run preflight and fix any FAILs:
On a feature branch,node .claude/skills/release/scripts/preflight.mjson-mainis a WARN and the release plan is withheld — that is expected before the PR merges. - Land the changes via a PR with a conventional-commit title (it becomes the release-notes entry). CI runs the same three validators. Wait for merge.
- On updated main, pull, rerun preflight (it should now be tag-ready and print the release plan), then tag — this is public, so ask the maintainer for explicit confirmation first:
git tag vX.Y.Z && git push origin vX.Y.Z - Publish the GitHub release — again only with explicit confirmation. Use the exact command from preflight's release plan; it looks like:
gh release create vX.Y.Z --title "Compatible with CLI v0.4.x" --generate-notes - Verify:
gh release view vX.Y.Z. Installed users pick it up through the plugin update flows documented in README.md.
Safety
- Tagging, pushing tags, and publishing releases are public and effectively irreversible. Never run steps 9–10 without the maintainer's explicit go-ahead in the current conversation, and never batch them silently with other work.
- If preflight reports FAIL on anything, stop and fix it — do not tag around a failing check.
- Never tag from a run that withheld the release plan (not tag-ready).