CLI Release Workflow
How to release a new version of the LearnHouse CLI to npm.
Prerequisites
- npm org
learnhousecreated on npmjs.com NPM_TOKEN(Automation type) added to GitHub repo: Settings > Secrets > ActionsghCLI installed and authenticated (gh auth status)- Push access to the repository
Quick release (recommended)
From the repo root, run the release script with the new version:
./.github/utils/release-cli.sh 1.4.3
Pick the version based on the changes:
| Bump type | When to use | Example |
|---|---|---|
| patch | Bug fixes, small tweaks | 1.4.2 → 1.4.3 |
| minor | New features, non-breaking | 1.4.2 → 1.5.0 |
| major | Breaking changes | 1.4.2 → 2.0.0 |
The script does everything end-to-end:
- Fetches latest from
origin - Bumps
apps/cli/package.jsonandapps/cli/src/constants.ts(keeps them in sync) - Commits the bump on
devand pushes (skipped if already at that version) - Creates and pushes the tag
cli-<version>(e.g.cli-1.4.3) — novprefix - Generates a changelog from
feat/fix/refactor/chorecommits that touchedapps/cli/ - Creates a GitHub Release authored by you (not the bot)
The tag push triggers .github/workflows/cli-publish.yaml, which:
- Checks out the code and sets up Node + Bun
- Installs dependencies (
bun install --frozen-lockfile) - Builds (
bun run build) - Verifies the tag version matches
package.json(fails if mismatched) - Publishes to npm (
npm publish --no-git-checks)
Verify
After the workflow completes (~1-2 minutes):
- npm: https://www.npmjs.com/package/learnhouse — should show the new version
- GitHub: Releases page shows the new release
- Test:
npx learnhouse@latest --versionprints the new version
Manual release (fallback)
If the script can't run (no gh, not on macOS, etc.), do it by hand:
cd apps/cli
bun run version:patch # or version:minor / version:major
git add apps/cli/package.json apps/cli/src/constants.ts
git commit -m "release(cli): bump version to 1.4.3"
git push origin dev
# Tag format is cli-<version> — NO "v" prefix
git tag cli-1.4.3
git push origin cli-1.4.3
The tag push still triggers the publish workflow. You'll need to create the GitHub Release manually if you want one (gh release create cli-1.4.3 --title "CLI 1.4.3" ...).
How it works
Version lives in two places
| File | Field | Why |
|---|---|---|
apps/cli/package.json |
"version" |
npm uses this for publishing |
apps/cli/src/constants.ts |
VERSION |
CLI displays this at runtime (banner, --version) |
The release script (and scripts/bump-version.js) update both at once so they never drift.
Tag format
The workflow only triggers on tags matching cli-[0-9]*. This means:
- Tags must be
cli-1.4.3— notcli-v1.4.3, notv1.4.3 - Regular commits and PRs never trigger a publish
- Only an explicit
cli-<numeric-version>tag push triggers it - Other tags (e.g.
api-1.0.0) are ignored
Safety checks
- Version mismatch guard: the workflow extracts the version from the tag and compares it to
package.json. If they don't match, publish fails. - prepublishOnly: npm runs
tsupbefore every publish, sodist/is always fresh. - frozen lockfile:
bun install --frozen-lockfileprevents silent dependency updates in CI.
Troubleshooting
Workflow didn't trigger
- Tag format must be
cli-<version>with nov(e.g.cli-1.4.3) - Verify the tag was pushed:
git ls-remote --tags origin | grep cli- - If you tagged with a
vby mistake, delete it and re-tag:git tag -d cli-v1.4.3 git push origin :refs/tags/cli-v1.4.3 ./.github/utils/release-cli.sh 1.4.3
Version mismatch error in CI
- You tagged
cli-1.4.3butpackage.jsonsays something else - Fix: run the correct bump, amend the commit, delete and recreate the tag
npm 403 / auth error
- Check that
NPM_TOKENsecret is set in GitHub repo settings - Token must be an Automation type token from the npm org
- Token must have publish permissions for the
learnhousepackage
Build fails
- Run
bun run buildlocally first to catch TypeScript errors - If
bun install --frozen-lockfilefails, updatebun.lockand commit it