---
name: release
description: Bump VibeFrame versions, regenerate release artifacts, run verification, and prepare a version commit.
---

# Release

Use this skill when the user asks Codex to cut a VibeFrame release.

The bump is one of `patch`, `minor`, or `major`. **Default to `patch`** when
no bump is specified or when there is any doubt.

## When Bumps Happen

**Once per release, not once per PR.** Ordinary `feat:` / `fix:` PRs merge to
`main` without a version bump. This skill runs when you decide to release, and
the single bump it produces must cover *every* commit since the last tag -
`git-cliff` handles that automatically in step 7.

Check what the release will cover before starting:

```bash
bash scripts/release-status.sh
```

That script is the single source of truth for release state. The push gate, the
tag workflow, and the daily drift check all call it, so its answer is the same
one CI will give.

## Version Policy

VibeFrame is still in `0.x`. **`patch` is the default and by far the most
common bump.** `minor` is rare and must be explicitly justified — the shared
push gate (`scripts/pre-push-validate.sh`) blocks a non-patch bump that lacks a
`Release-Type:` trailer (see step 10).

- `patch`: bug fixes, docs/tooling, UX polish, internal refactors, and most
  ordinary `feat:` / `fix:` commits. **Use this unless a rule below clearly
  applies.**
- `minor`: new public CLI command namespace, new MCP tool family, public API
  contract additions, or a large product milestone.
- `major`: breaking changes or an intentional 1.0 milestone.

When unsure, use `patch`.

## Steps

1. Read the current root version:

   ```bash
   jq -r '.version' package.json
   ```

2. Bump the root package:

   ```bash
   npm version <patch|minor|major> --no-git-tag-version
   ```

3. Read the exact new version:

   ```bash
   NEW_VERSION=$(jq -r '.version' package.json)
   ```

4. Set every workspace package to that exact version. Do not use `pnpm -r exec
npm version` for this step because recursive pnpm includes the root package.

   ```bash
   for dir in packages/cli packages/core packages/ai-providers packages/mcp-server packages/ui apps/web; do
     (cd "$dir" && npm version "$NEW_VERSION" --no-git-tag-version)
   done
   ```

5. Verify all package versions match:

   ```bash
   for f in package.json packages/*/package.json apps/*/package.json; do
     jq -r '.version' "$f"
   done | sort -u
   ```

   The output must contain exactly one version.

6. Build, regenerate references, lint, and test:

   ```bash
   pnpm build
   pnpm gen:reference
   pnpm lint
   pnpm -F @vibeframe/cli exec vitest run --bail 1
   ```

7. Generate the changelog for the new version:

   ```bash
   git-cliff --tag v$NEW_VERSION -o CHANGELOG.md
   ```

8. Run the shared push gate:

   ```bash
   bash scripts/pre-push-validate.sh
   ```

9. Stage the release files:

   ```bash
   git add package.json packages/*/package.json apps/*/package.json CHANGELOG.md docs/cli-reference.md
   ```

10. Commit. For a `patch` bump, a plain message:

```bash
git commit -m "chore: bump version to $NEW_VERSION"
```

   For a `minor` or `major` bump, the push gate requires a justification
   trailer in the commit body, or it blocks the push:

```bash
git commit -m "chore: bump version to $NEW_VERSION" -m "Release-Type: minor: <why this is not a patch>"
```

Do not create a local tag. Do not push unless the user explicitly asks.

11. The version commit reaches `main` **via a PR**, never a direct push (even
    though `main` allows admin bypass). Put it on a `chore/release-$NEW_VERSION`
    branch, open a PR, let CI go green, and merge:

```bash
git switch -c chore/release-$NEW_VERSION
git push -u origin chore/release-$NEW_VERSION
gh pr create --fill --base main
```

12. Tagging is automatic. Once the version commit lands on `main` and CI passes,
    the `Create release tag` workflow creates `vX.Y.Z` on its own. Before
    tagging it re-runs `scripts/release-status.sh` and **refuses** if `feat:` /
    `fix:` commits landed after the bump, or if `CHANGELOG.md` has no
    `## [X.Y.Z]` entry. Do not create the tag by hand.

13. Publishing stays manual. Run the `Publish to npm` workflow with the new tag.

    Tags pushed by a workflow cannot trigger another workflow, so the automatic
    tag never dispatches `publish.yml` - that is what keeps the "CI never
    publishes" policy intact. A human-created `git push origin vX.Y.Z` *does*
    trigger `publish.yml`, so do not push release tags manually.

If publishing is forgotten, the daily `Release drift check` workflow opens an
issue comparing `main`, the latest tag, and the published npm versions.
