diff --git a/.bumpy/readme-and-docs-cleanup.md b/.bumpy/readme-and-docs-cleanup.md
new file mode 100644
index 0000000..547d30a
--- /dev/null
+++ b/.bumpy/readme-and-docs-cleanup.md
@@ -0,0 +1,3 @@
+---
+'@varlock/bumpy': patch
+---
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index f2a8b4e..2a37e88 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -32,7 +32,7 @@ jobs:
# 🐸 This is the important part - checks for missing bump files and posts/updates a PR comment with the release plan
# (use --pat-comments if PAT belongs to dedicated bot, rather than person)
- - run: bunx @varlock/bumpy ci check --fail-on-missing --pat-comments
+ - run: bunx @varlock/bumpy ci check --pat-comments
env:
GH_TOKEN: ${{ github.token }}
BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }} # <- PAT needed so that release PR will trigger CI
diff --git a/README.md b/README.md
index a9c81e6..8b5648f 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,12 @@
-
+
-
+
@@ -18,7 +18,18 @@ A modern package versioning and changelog generation tool — built for monorepo
## How It Works
-Bumpy uses **bump files** (you may know them as "changesets" if coming from that tool) — small markdown files that declare which packages changed and how (patch/minor/major), along with a description that ends up in changelogs. Developers create these files as part of their PRs. As PRs merge to the base branch, a "release PR" is kept up to date showing what packages will be released and their changelogs — including packages bumped automatically due to dependency relationships. When the release PR is merged, bump files are consumed (deleted), and packages are published with updated versions and changelogs.
+Bumpy uses **bump files** (you may know them as "changesets" if coming from [that tool 🦋](https://github.com/changesets/changesets)) — small markdown files that declare an intent to release packages with a bump level (patch/minor/major), and a description that ends up in changelogs. Developers create these files as part of their PRs, and these files are then used to consolidate changes, generate changelogs, and trigger publishing. Specifically:
+
+- Devs/agents create bump files as part of their PRs (using `bumpy add` or manually)
+- A pre-push git hook can enforce bump files exist for changed packages
+- In CI, a workflow checks PRs for bump files, leaves a comment on the PR detailing changed packages
+- As PRs merge to the base branch, a "release PR" is kept up to date
+ - Shows what packages will be released and their changelogs
+ — Including packages bumped automatically due to dependency relationships
+- When release PR is merged, publishing is triggered
+ - Oending bump files are deleted and packages are published with updated versions and changelogs
+
+All of this is automated via two simple GitHub Actions workflows (see [CI setup](#ci--github-actions) below). You can also run everything locally with `bumpy status`, `bumpy version`, and `bumpy publish`.
### Example bump file
@@ -34,18 +45,10 @@ Added user language preference to the core config.
Fixed locale fallback logic in utils.
```
-The typical CI driven workflow is:
-
-1. **`bumpy add`** — developers create bump files as part of their PRs
-2. **`bumpy ci check`** — CI comments on each PR with a release plan preview
-3. **`bumpy ci release`** — on merge to main, CI opens a "Version Packages" PR that bumps versions and updates changelogs. When that PR is merged, it publishes packages.
-
-All of this is automated via two simple GitHub Actions workflows (see [CI setup](#ci--github-actions) below). You can also run everything locally with `bumpy status`, `bumpy version`, and `bumpy publish`.
-
## Features
- **All package managers** — npm, pnpm, yarn, and bun workspaces
-- **Smart dependency propagation** — configurable rules for how version bumps cascade through your dependency graph (see [version propagation docs](docs/version-propagation.md))
+- **Smart dependency propagation** — configurable rules for how version bumps cascade through your dependency graph (see [version propagation docs](https://github.com/dmno-dev/bumpy/blob/main/docs/version-propagation.md))
- **Pack-then-publish** — by default, publishes to npm (resolving `workspace:` and `catalog:` protocols, with OIDC/provenance support). Per-package custom publish commands let you target anything — VSCode extensions, Docker images, JSR, private registries, etc.
- **Flexible package management** — include/exclude any package individually via per-package config, glob patterns, or `privatePackages` setting
- **Non-interactive CLI** — `bumpy add` works fully non-interactively for CI/CD and AI-assisted development
@@ -60,25 +63,27 @@ All of this is automated via two simple GitHub Actions workflows (see [CI setup]
# Install
bun add -d @varlock/bumpy # or npm/pnpm/yarn
-# Initialize (creates .bumpy/ config directory)
-bumpy init
+# Initialize (creates .bumpy/ directory and config, migrates from changesets if applicable)
+bunx bumpy init
# Create a bump file
-bumpy add
+bunx bumpy add
# Preview the release plan
-bumpy status
+bunx bumpy status
```
Then set up CI to automate versioning and publishing (see below).
## CI / GitHub Actions
-No separate action to install — just call `bumpy ci` directly in your workflows. Two commands handle the entire release lifecycle:
+No separate action to rely on — just call `bumpy ci` directly in your workflows. Two commands handle the entire release lifecycle:
- **`bumpy ci check`** — runs on every PR. Computes the release plan from pending bump files and posts/updates a comment on the PR showing what versions would be released. Warns if any changed packages are missing bump files.
- **`bumpy ci release`** — runs on push to main. If pending bump files exist, it opens (or updates) a "Version Packages" PR that applies all version bumps and changelog updates. If the current push _is_ the Version Packages PR being merged, it publishes the new versions, creates git tags, and creates GitHub releases.
+_examples use bun, but works with Node.js_
+
### PR check workflow
```yaml
@@ -98,6 +103,7 @@ jobs:
- run: bunx @varlock/bumpy ci check
env:
GH_TOKEN: ${{ github.token }}
+ BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }} # additional PAT (optional)
```
### Release workflow
@@ -128,6 +134,7 @@ jobs:
- run: bunx @varlock/bumpy ci release
env:
GH_TOKEN: ${{ github.token }}
+ BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }} # additonal PAT, needed to trigger CI checks on release PR
```
> **Trusted publishing setup:** Configure each package on [npmjs.com](https://docs.npmjs.com/trusted-publishers/) → Package Settings → Trusted Publishers → GitHub Actions. Specify your org/user, repo, and the workflow filename (`bumpy-release.yml`). No `NPM_TOKEN` secret needed. Requires npm >= 11.5.1 — bumpy will warn if your version is too old.
@@ -157,6 +164,7 @@ jobs:
- run: bunx @varlock/bumpy ci release
env:
GH_TOKEN: ${{ github.token }}
+ BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
```
@@ -166,7 +174,7 @@ You can also use `bumpy ci release --auto-publish` to version + publish directly
### Token setup
-The default `github.token` works for basic functionality, but GitHub's anti-recursion guard means PRs created by the default token won't trigger other workflows — so your regular CI (tests, linting, etc.) won't run automatically on the Version Packages PR. To fix this, provide a `BUMPY_GH_TOKEN` secret using either a **fine-grained PAT** or a **GitHub App token**. See the [full token setup guide](docs/github-actions.md#token-setup) for details.
+The default `github.token` works for basic functionality, but GitHub's anti-recursion guard means PRs created by the default token won't trigger other workflows — so your regular CI (tests, linting, etc.) won't run automatically on the Version Packages PR. To fix this, provide a `BUMPY_GH_TOKEN` secret using either a **fine-grained PAT** or a **GitHub App token**. See the [full token setup guide](https://github.com/dmno-dev/bumpy/blob/main/docs/github-actions.md#token-setup) for details.
Run `bumpy ci setup` for interactive guidance, or set it up manually:
@@ -206,12 +214,11 @@ The skill teaches the AI to examine git changes, identify affected packages, cho
## Documentation
-- [Bump file format](docs/bump-files.md) — syntax, bump levels, cascade control
-- [Configuration reference](docs/configuration.md) — all `.bumpy/_config.json` and per-package options
-- [CLI reference](docs/cli.md) — every command with flags and examples
-- [GitHub Actions setup](docs/github-actions.md) — CI workflows, token setup, trusted publishing
-- [Version propagation](docs/version-propagation.md) — how dependency bumps cascade through your graph
-- [LLM-friendly reference](./llms.md) — single-file reference optimized for AI tools
+- [Bump file format](https://github.com/dmno-dev/bumpy/blob/main/docs/bump-files.md) — syntax, bump levels, cascade control
+- [Configuration reference](https://github.com/dmno-dev/bumpy/blob/main/docs/configuration.md) — all `.bumpy/_config.json` and per-package options
+- [CLI reference](https://github.com/dmno-dev/bumpy/blob/main/docs/cli.md) — every command with flags and examples
+- [GitHub Actions setup](https://github.com/dmno-dev/bumpy/blob/main/docs/github-actions.md) — CI workflows, token setup, trusted publishing
+- [Version propagation](https://github.com/dmno-dev/bumpy/blob/main/docs/version-propagation.md) — how dependency bumps cascade through your graph
## Why files instead of conventional commits?
@@ -219,9 +226,9 @@ Tools like semantic-release infer version bumps from commit messages (`feat:`
## Why not just use changesets?
-Bumpy is built as a successor to [@changesets/changesets](https://github.com/changesets/changesets). Changesets is mature and widely adopted, but has stagnated — hundreds of open issues around core design problems that are unlikely to be fixed without a rewrite. See [differences from changesets](docs/differences-from-changesets.md) for a detailed comparison with links to specific issues. The biggest pain points bumpy addresses:
+Bumpy is built as a successor to [@changesets/changesets](https://github.com/changesets/changesets). Changesets is mature and widely adopted, but has stagnated — hundreds of open issues around core design problems that are unlikely to be fixed without a rewrite. See [differences from changesets](https://github.com/dmno-dev/bumpy/blob/main/docs/differences-from-changesets.md) for a detailed comparison with links to specific issues. The biggest pain points bumpy addresses:
-- **Sane dependency propagation** — changesets hardcodes aggressive behavior where a minor bump triggers a major bump on all peer dependents. Bumpy uses a [three-phase algorithm](docs/version-propagation.md) with sensible defaults and full configurability.
+- **Sane dependency propagation** — changesets hardcodes aggressive behavior where a minor bump triggers a major bump on all peer dependents. Bumpy uses a [three-phase algorithm](https://github.com/dmno-dev/bumpy/blob/main/docs/version-propagation.md) with sensible defaults and full configurability.
- **Workspace protocol resolution** — changesets uses `npm publish` even in pnpm/yarn workspaces, so `workspace:^` and `catalog:` protocols are NOT resolved, resulting in broken published packages.
- **Custom publish commands** — changesets is hardcoded to `npm publish`. Bumpy supports per-package custom publish for VSCode extensions, Docker images, JSR, etc.
- **Flexible package management** — changesets treats all private packages the same. Bumpy lets you include/exclude any package individually.
@@ -231,14 +238,19 @@ Bumpy is built as a successor to [@changesets/changesets](https://github.com/cha
## Development
```bash
-bun install
-bun test
-bun src/cli.ts --help
+bun install # install deps
+bun test # run tests
+bun run build # build CLI
+bunx bumpy --help # invoke built cli
```
## Roadmap
-- Prerelease mode (for now, use [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new) for preview packages)
-- Bun standalone binary for use outside of JS projects
+- Prerelease mode (for now, use [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new) for branch preview packages)
+- Standalone binary for use outside of JS projects
- Better support for versioning non-JS packages and usage without package.json files
+- Plugin system for different publish targets, and support multiple targets per package
- Tracking workspace-level / non-publishable changes
+- More frogs 🐸
+
+
diff --git a/docs/bump-files.md b/docs/bump-files.md
index 7360f66..8bcc171 100644
--- a/docs/bump-files.md
+++ b/docs/bump-files.md
@@ -20,6 +20,8 @@ Added user language preference to the core config.
Fixed locale fallback logic in utils.
```
+> **Tip:** The description body is optional. If left blank, the bump file still contributes to the release plan (triggering version bumps and dependency propagation), but no entry will appear in the changelog for it.
+
### Bump levels
| Level | When to use |
diff --git a/llms.md b/llms.md
deleted file mode 100644
index 00b3d3b..0000000
--- a/llms.md
+++ /dev/null
@@ -1,712 +0,0 @@
-# 🐸 @varlock/bumpy — LLM Reference
-
-> Bumpy is a modern monorepo versioning and changelog tool. It replaces @changesets/changesets with simpler config, sane defaults, and flexible dependency bump control.
-
-## Quick Start
-
-```bash
-# Initialize in a monorepo root
-bumpy init
-
-# Create a bump file (interactive)
-bumpy add
-
-# Create a bump file (non-interactive, for CI/AI)
-bumpy add --packages "pkg-a:minor,pkg-b:patch" --message "Added feature X" --name "add-feature-x"
-
-# Preview what would be released
-bumpy status
-bumpy status --json
-bumpy status --packages # one name per line, for piping
-
-# Apply bump files — bumps versions, updates changelogs, deletes bump files
-bumpy version
-
-# Publish (pack with PM, publish tarball with npm)
-bumpy publish
-bumpy publish --dry-run
-bumpy publish --tag beta
-```
-
-## How It Works
-
-1. Developers create **bump files** in `.bumpy/` describing what changed and which packages are affected
-2. `bumpy version` reads all pending bump files, calculates version bumps (including dependency propagation), updates `package.json` versions and `CHANGELOG.md` files, then deletes the consumed bump files
-3. `bumpy publish` finds packages with unpublished versions and publishes them in dependency order
-
-## Bump File Format
-
-Bump files are markdown with YAML frontmatter, stored in `.bumpy/.md`.
-
-### Simple format
-
-```yaml
----
-'@myorg/core': minor
-'@myorg/utils': patch
----
-Added new encryption provider for secrets management.
-```
-
-Valid bump types: `major`, `minor`, `patch`, `none`
-
-`none` suppresses a bump on a package that would otherwise be included via propagation. If skipping would leave a broken range, bumpy throws an error.
-
-### Nested format with explicit cascade control
-
-```yaml
----
-'@myorg/core':
- bump: minor
- cascade:
- '@myorg/plugin-*': patch
- '@myorg/cli': minor
-'@myorg/utils': patch
----
-Added new encryption provider. Plugins need a patch bump for compatibility.
-```
-
-## Configuration
-
-### Root config: `.bumpy/_config.json`
-
-```jsonc
-{
- // Branch to compare against (default: "main")
- "baseBranch": "main",
-
- // npm access level for publishing (default: "public")
- "access": "public",
-
- // Auto-commit after `bumpy version` (default: false)
- "commit": false,
-
- // Changelog formatter: "default", "github", ["github", { repo: "..." }], or "./path.ts"
- "changelog": "default",
-
- // Packages whose versions are always bumped together to the same version
- "fixed": [["@myorg/core", "@myorg/types"]],
-
- // Packages whose versions are bumped to the same level but keep independent version numbers
- "linked": [["@myorg/plugin-*"]],
-
- // Package names/globs to exclude from version management
- "ignore": ["@myorg/internal-*", "test-fixtures"],
-
- // Package names/globs to explicitly include (overrides private status and ignore)
- "include": ["my-vscode-ext", "@myorg/app-*"],
-
- // When to update internal dependency version ranges (Phase C)
- // "out-of-range" = only fix broken ranges via Phase A (default)
- // "patch" = also proactively bump dependents on any dep bump
- // "minor" = also proactively bump dependents on minor+ dep bumps
- "updateInternalDependencies": "out-of-range",
-
- // Global rules for how dependency bumps propagate (Phase C only)
- // Each rule is either false (disabled) or { trigger, bumpAs }
- "dependencyBumpRules": {
- // When a regular dependency bumps, what happens to dependents?
- "dependencies": { "trigger": "patch", "bumpAs": "patch" },
- // When a peer dependency bumps, what happens to dependents?
- "peerDependencies": { "trigger": "major", "bumpAs": "match" },
- // Dev dependencies never propagate by default
- "devDependencies": false,
- "optionalDependencies": { "trigger": "minor", "bumpAs": "patch" },
- },
-
- // Whether to version/tag private packages by default
- "privatePackages": { "version": false, "tag": false },
-
- // Per-package config overrides (keys support globs)
- "packages": {
- "my-vscode-ext": {
- "skipNpmPublish": true,
- "publishCommand": ["bun run package", "bunx vsce publish"],
- "buildCommand": "bun run build",
- },
- "@myorg/plugin-*": {
- "access": "public",
- },
- },
-
- // Publish pipeline configuration
- "publish": {
- // Which PM to use for packing ("auto" detects from lockfile)
- "packManager": "auto",
- // Which tool to use for publishing (npm supports OIDC/provenance)
- "publishManager": "npm",
- // Extra args for the publish command
- "publishArgs": ["--provenance"],
- // How to resolve workspace:/catalog: protocols before publish
- // "pack" = PM packs tarball (resolves protocols), then npm publishes tarball (default)
- // "in-place" = rewrite package.json before publish
- // "none" = don't resolve
- "protocolResolution": "pack",
- },
-
- // GitHub release creation (requires gh CLI). Default: individual per package.
- // true = single aggregated release for all packages
- // { enabled: true, title: "Release {{date}}" } = aggregate with custom title
- "aggregateRelease": false,
-
- // Git identity for CI commits (default: bumpy-bot)
- "gitUser": {
- "name": "bumpy-bot",
- "email": "276066384+bumpy-bot@users.noreply.github.com",
- },
-
- // Version PR settings
- "versionPr": {
- // PR title (default: "🐸 Versioned release")
- "title": "🐸 Versioned release",
- // Branch name (default: "bumpy/version-packages")
- "branch": "bumpy/version-packages",
- // Preamble text shown at the top of the PR body
- "preamble": "Merge this PR when you are ready to release...",
- },
-}
-```
-
-### Per-package config: `package.json["bumpy"]`
-
-Any package can have bumpy config in its own `package.json`:
-
-```json
-{
- "name": "@myorg/my-vscode-ext",
- "private": true,
- "bumpy": {
- "managed": true,
- "skipNpmPublish": true,
- "publishCommand": ["bun run package", "bunx vsce publish", "bunx ovsx publish"],
- "buildCommand": "bun run build",
- "cascadeTo": {
- "@myorg/plugin-*": { "trigger": "minor", "bumpAs": "patch" }
- }
- }
-}
-```
-
-#### Per-package config fields
-
-| Field | Type | Description |
-| --------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------- |
-| `managed` | `boolean` | Explicitly opt in (`true`) or out (`false`) of version management. Overrides private/ignore/include. |
-| `access` | `"public" \| "restricted"` | npm access level override |
-| `publishCommand` | `string \| string[]` | Custom publish command(s). Supports `{{version}}` and `{{name}}` template variables. |
-| `buildCommand` | `string` | Build command to run before publishing |
-| `registry` | `string` | Custom npm registry URL |
-| `skipNpmPublish` | `boolean` | Skip npm publish (use with `publishCommand` for non-npm publishing) |
-| `checkPublished` | `string` | Command to check if version is published. Should output the version string. Used for non-npm targets. |
-| `dependencyBumpRules` | `object` | Override global dependency bump rules for this package (or `false` to disable) |
-| `cascadeTo` | `Record` | When this package bumps, cascade to these packages (supports globs) |
-
-## Package Management (include/exclude)
-
-Resolution order (first match wins):
-
-1. `managed: false` in package.json `bumpy` config → **skip**
-2. Matches `ignore` glob → **skip** (unless `managed: true` or `include` glob)
-3. `managed: true` in package.json `bumpy` config → **include**
-4. Matches `include` glob → **include** (overrides private)
-5. Private package + `privatePackages.version: false` → **skip**
-6. Default → **include**
-
-All `ignore`, `include`, `fixed`, `linked`, and per-package config keys support glob patterns: `*` (single segment), `**` (any depth), e.g., `@myorg/plugin-*`, `@myorg/**`.
-
-## Dependency Bump Rules
-
-A `DependencyBumpRule` has two fields:
-
-```json
-{ "trigger": "minor", "bumpAs": "patch" }
-```
-
-- `trigger`: minimum bump level in the dependency that activates propagation. Values: `"major"`, `"minor"`, `"patch"`
-- `bumpAs`: what bump to apply to the dependent. Values: `"major"`, `"minor"`, `"patch"`, `"match"` (same level as triggering bump)
-
-A rule can also be `false` to disable propagation for that dep type entirely.
-
-Note: dependency bump rules only apply in **Phase C** (proactive propagation). **Phase A** (out-of-range fixes) always runs with hardcoded behavior: peer deps get "match", regular deps get "patch", dev deps are skipped.
-
-### Rule resolution order
-
-When package A bumps and package B depends on A, bumpy looks for a Phase C rule in this order:
-
-1. **Per-package dep type rule** — `dependencyBumpRules[depType]` on package B _(most specific)_
-2. **Global dep type rule** — root config `dependencyBumpRules[depType]`
-3. **Built-in defaults** _(least specific)_
-
-Bump file cascades and `cascadeTo` config are separate from dependency bump rules and always apply.
-
-### Built-in defaults (the key difference from changesets)
-
-| Dependency type | Phase C trigger | Phase C bumpAs | Phase A behavior |
-| ---------------------- | --------------- | -------------- | ----------------------- |
-| `dependencies` | patch | patch | patch (on out-of-range) |
-| `peerDependencies` | **major** | **match** | match (on out-of-range) |
-| `devDependencies` | _(disabled)_ | — | _(skipped)_ |
-| `optionalDependencies` | minor | patch | patch (on out-of-range) |
-
-The critical difference: changesets bumps dependents to **major** when a peer dependency gets a **minor** bump. Bumpy's Phase A matches the triggering bump level for peer deps, and Phase C only triggers on major by default.
-
-## CLI Reference
-
-### `bumpy init`
-
-Initialize `.bumpy/` directory. Automatically detects and migrates from `.changeset/` if present. Ensures `@varlock/bumpy` is installed as a dev dependency.
-
-| Flag | Description |
-| --------- | ------------------------ |
-| `--force` | Skip interactive prompts |
-
-### `bumpy add`
-
-Create a new bump file.
-
-| Flag | Description |
-| ------------------- | -------------------------------------------------------- |
-| `--packages ` | Non-interactive: comma-separated `"name:bumpType"` pairs |
-| `--message ` | Bump file summary |
-| `--name ` | Bump file filename (default: random adjective-noun) |
-| `--empty` | Create an empty bump file (no packages, for CI skip) |
-
-Interactive mode prompts for: packages, bump type per package, cascade options, summary, and filename for the bump file.
-
-### `bumpy status`
-
-Show pending releases.
-
-| Flag | Description |
-| --------------------- | ------------------------------------------------------------------- |
-| `--json` | Full JSON output with `releases[]`, `bumpFiles[]`, `packageNames[]` |
-| `--packages` | One package name per line (for piping to other commands) |
-| `--bump ` | Filter by bump type: `"major"`, `"minor,patch"` |
-| `--filter ` | Filter by package name/glob: `"@myorg/*"` |
-| `--verbose` | Show bump file details |
-
-Exit codes: `0` = releases pending, `1` = no releases pending.
-
-JSON output shape:
-
-```json
-{
- "changesets": [{ "id": "...", "summary": "...", "releases": [{ "name": "...", "type": "..." }] }],
- "releases": [
- {
- "name": "...",
- "type": "...",
- "oldVersion": "...",
- "newVersion": "...",
- "dir": "...",
- "changesets": [],
- "isDependencyBump": false,
- "isCascadeBump": false
- }
- ],
- "packageNames": ["pkg-a", "pkg-b"]
-}
-```
-
-### `bumpy check`
-
-Verify that all changed packages on the current branch have corresponding bump files. Compares files changed vs the base branch, maps them to managed packages, and exits non-zero if any are missing bump files.
-
-Designed for pre-push hooks — no GitHub API needed.
-
-```yaml
-# lefthook.yml
-pre-push:
- jobs:
- - name: bumpy-check
- run: bunx @varlock/bumpy check
-```
-
-### `bumpy version`
-
-Apply all pending bump files: bump versions in `package.json`, update `CHANGELOG.md`, delete consumed bump files. Optionally creates a git commit if `commit: true` in config.
-
-### `bumpy publish`
-
-Publish packages with unpublished versions.
-
-| Flag | Description |
-| ------------- | --------------------------------------- |
-| `--dry-run` | Preview without publishing |
-| `--tag ` | npm dist-tag (`"next"`, `"beta"`, etc.) |
-| `--no-push` | Skip pushing git tags to remote |
-
-Default flow: detects PM → packs tarball (resolves workspace:/catalog: protocols) → publishes tarball with npm → creates git tags → pushes tags → creates GitHub releases (if `gh` CLI is available).
-
-### `bumpy ci check`
-
-PR check — reports pending bump files and optionally comments on the PR with the release plan.
-
-| Flag | Description |
-| ------------------- | --------------------------------------------------------------------- |
-| `--comment` | Force PR commenting on/off (auto-detected in CI environments) |
-| `--fail-on-missing` | Exit 1 if no bump files found |
-| `--pat-comments` | Post PR comments using `BUMPY_GH_TOKEN` instead of default `GH_TOKEN` |
-
-Auto-detects PR number from `GITHUB_REF` in GitHub Actions. Also checks `BUMPY_PR_NUMBER` and `PR_NUMBER` env vars.
-
-### `bumpy ci release`
-
-Release automation — either creates a "Version Packages" PR or auto-publishes directly.
-
-| Flag | Description |
-| ----------------- | -------------------------------------------------------------- |
-| `--auto-publish` | Version + publish directly instead of creating a PR |
-| `--tag ` | npm dist-tag for auto-publish mode |
-| `--branch ` | Branch name for version PR (default: `bumpy/version-packages`) |
-| `--pat-pr` | Create/edit the version PR using `BUMPY_GH_TOKEN` |
-
-Default mode (`version-pr`): creates a branch, runs `bumpy version`, commits, and opens/updates a PR via `gh`. Merging that PR triggers publish.
-
-Auto-publish mode: runs `bumpy version`, commits, pushes, then `bumpy publish` in one step.
-
-## Changelog Customization
-
-The `changelog` config controls how CHANGELOG.md entries are formatted.
-
-### Built-in formatters
-
-```json
-{ "changelog": "default" }
-```
-
-Simple format: version heading, date, bullet points from bump file summaries.
-
-```json
-{ "changelog": "github" }
-{ "changelog": ["github", { "repo": "dmno-dev/bumpy" }] }
-```
-
-GitHub-enhanced: adds PR links and author attribution (`- Added feature (#123) by @user`). Looks up PRs via `gh` CLI by finding the commit that introduced each bump file.
-
-### Custom formatter (TypeScript or JavaScript)
-
-```json
-{ "changelog": "./my-changelog.ts" }
-{ "changelog": ["./my-changelog.ts", { "someOption": true }] }
-```
-
-A custom formatter exports a function that receives full context and returns the complete changelog entry:
-
-```ts
-// my-changelog.ts
-import type { ChangelogContext } from '@varlock/bumpy';
-
-export default function (ctx: ChangelogContext): string {
- const { release, changesets, date } = ctx;
- const lines = [`## [${release.newVersion}] - ${date}\n`];
-
- const relevant = changesets.filter((cs) => release.changesets.includes(cs.id));
- for (const cs of relevant) {
- if (cs.summary) lines.push(`- ${cs.summary.split('\n')[0]}`);
- }
-
- lines.push('');
- return lines.join('\n');
-}
-```
-
-The `ChangelogContext` interface:
-
-```ts
-interface ChangelogContext {
- release: PlannedRelease; // name, type, oldVersion, newVersion, etc.
- changesets: Changeset[]; // all changesets (filter by release.changesets for relevant ones)
- date: string; // ISO date (YYYY-MM-DD)
-}
-```
-
-If the config is `["./my-changelog.ts", { ... }]`, the options object is passed to the exported function. If the function returns another function, it's treated as a factory pattern.
-
-## Publish Pipeline
-
-The publish pipeline is configurable via `publish` in root config:
-
-### Default: pack-then-publish
-
-1. **Build** — runs `buildCommand` if configured on the package
-2. **Pack** — runs `bun pm pack` / `pnpm pack` / `npm pack` (auto-detected). This resolves `workspace:` and `catalog:` protocols into the tarball.
-3. **Publish** — runs `npm publish ` (supports OIDC `--provenance`)
-4. **Tag** — creates git tag `pkg-name@version`
-
-### Custom publish commands
-
-For non-npm packages (VSCode extensions, Docker images, etc.):
-
-```json
-{
- "bumpy": {
- "skipNpmPublish": true,
- "buildCommand": "bun run build",
- "publishCommand": ["bunx vsce publish", "bunx ovsx publish"]
- }
-}
-```
-
-Custom commands support `{{version}}` and `{{name}}` template variables. Bumpy resolves `workspace:`/`catalog:` protocols in-place before running custom commands.
-
-#### Publish detection
-
-When running `bumpy publish` or `bumpy ci release`, bumpy checks which packages need publishing using a layered strategy:
-
-1. **Custom `checkPublished` command** — if set, bumpy runs it and compares the output to the current version
-2. **Non-npm packages** (`skipNpmPublish` or custom `publishCommand`) — checks for a git tag (`@`)
-3. **Default (npm packages)** — checks the npm registry via `npm info`
-
-For VS Code extensions, you can provide a check command:
-
-```json
-{
- "bumpy": {
- "skipNpmPublish": true,
- "publishCommand": "bunx vsce publish",
- "checkPublished": "bunx vsce show my-ext --json | jq -r '.versions[0].version'"
- }
-}
-```
-
-Or simply rely on git tags (the default for non-npm packages) — no extra config needed.
-
-## workspace: and catalog: Protocol Handling
-
-Both `workspace:` (pnpm, bun, yarn) and `catalog:` (pnpm, bun) protocols are resolved before publishing.
-
-- **Pack mode** (default): the PM's pack command handles resolution automatically
-- **In-place mode**: bumpy rewrites package.json directly (used for custom publish commands)
-- **Catalog sources**: pnpm reads from `pnpm-workspace.yaml`; bun reads from root `package.json` (`catalog`/`catalogs` keys or inside `workspaces`)
-
-## Common Patterns
-
-### Monorepo with a core package that drives plugin versions
-
-```json
-// In @myorg/core's package.json
-{
- "bumpy": {
- "cascadeTo": {
- "@myorg/plugin-*": { "trigger": "minor", "bumpAs": "patch" }
- }
- }
-}
-```
-
-### Private package that needs version management (e.g., VSCode extension)
-
-```json
-{
- "private": true,
- "bumpy": {
- "managed": true,
- "skipNpmPublish": true,
- "publishCommand": "bunx vsce publish"
- }
-}
-```
-
-### Internal packages that should never propagate bumps
-
-Configure via per-package dependency bump rules:
-
-```json
-// In root .bumpy/_config.json
-{
- "packages": {
- "@myorg/internal-*": {
- "dependencyBumpRules": {
- "dependencies": false
- }
- }
- }
-}
-```
-
-### CI: conditionally run tests based on affected packages
-
-```bash
-# Get list of packages that would be released
-PACKAGES=$(bumpy status --packages 2>/dev/null)
-
-if echo "$PACKAGES" | grep -q "@myorg/core"; then
- echo "Core changed — running full test suite"
- bun test
-fi
-```
-
-### CI: publish preview packages
-
-```bash
-bumpy version
-bumpy publish --tag preview --no-push
-```
-
-### GitHub Actions — PR check + version PR workflow
-
-```yaml
-# .github/workflows/bumpy-check.yml
-name: Bumpy Check
-on: pull_request
-
-jobs:
- check:
- runs-on: ubuntu-latest
- permissions:
- pull-requests: write
- steps:
- - uses: actions/checkout@v6
- - uses: oven-sh/setup-bun@v2
- - run: bun install
- - run: bunx @varlock/bumpy ci check
- env:
- GH_TOKEN: ${{ github.token }}
-```
-
-```yaml
-# .github/workflows/bumpy-release.yml — trusted publishing (OIDC, no secret needed)
-name: Bumpy Release
-on:
- push:
- branches: [main]
-
-jobs:
- release:
- runs-on: ubuntu-latest
- permissions:
- contents: write
- pull-requests: write
- id-token: write # required for npm trusted publishing (OIDC)
- steps:
- - uses: actions/checkout@v6
- with:
- fetch-depth: 0
- - uses: oven-sh/setup-bun@v2
- - uses: actions/setup-node@v6
- with:
- node-version: lts/*
- - run: bun install
- - run: bunx @varlock/bumpy ci release
- env:
- GH_TOKEN: ${{ github.token }}
-```
-
-Trusted publishing setup: configure each package on npmjs.com → Package Settings → Trusted Publishers → GitHub Actions.
-Specify your org/user, repo, and the workflow filename. No NPM_TOKEN secret needed. Requires npm >= 11.5.1 (included in Node.js LTS).
-
-Alternative: token-based auth (uses `NPM_TOKEN` secret instead of OIDC):
-
-```yaml
-# .github/workflows/bumpy-release.yml — token-based auth
-name: Bumpy Release
-on:
- push:
- branches: [main]
-
-jobs:
- release:
- runs-on: ubuntu-latest
- permissions:
- contents: write
- pull-requests: write
- steps:
- - uses: actions/checkout@v6
- with:
- fetch-depth: 0
- - uses: oven-sh/setup-bun@v2
- - run: bun install
- - run: bunx @varlock/bumpy ci release
- env:
- GH_TOKEN: ${{ github.token }}
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
-```
-
-### Non-interactive bump file creation (AI/CI)
-
-```bash
-bumpy add \
- --packages "@myorg/core:minor,@myorg/cli:patch" \
- --message "Added new API for encryption providers" \
- --name "add-encryption-api"
-```
-
-### Aggregate GitHub releases
-
-By default, `bumpy publish` creates one GitHub release per package (requires `gh` CLI). To create a single aggregated release instead:
-
-```json
-// .bumpy/_config.json
-{
- "aggregateRelease": true
-}
-```
-
-Or with a custom title:
-
-```json
-{
- "aggregateRelease": {
- "enabled": true,
- "title": "Release {{date}}"
- }
-}
-```
-
-### Migrating from changesets
-
-```bash
-bumpy init
-```
-
-If `.changeset/` is detected, `bumpy init` will automatically:
-
-1. Rename `.changeset/` to `.bumpy/` (keeping pending bump files)
-2. Convert `config.json` to `_config.json` (migrating compatible fields)
-3. Offer to uninstall `@changesets/cli` and install `@varlock/bumpy`
-4. Warn about changeset references in GitHub workflows
-
-Key behavioral differences after migration:
-
-- Out-of-range peer dep bumps match the triggering bump level (not always major)
-- Use `none` to suppress a propagated bump
-- Per-package config moves to `package.json["bumpy"]` instead of root config only
-
-## AI Integration
-
-Bumpy ships with an AI skill that teaches LLMs how to create bump files.
-
-### Claude Code (plugin)
-
-```bash
-claude plugin install @varlock/bumpy
-```
-
-Then use `/bumpy:add-change` in Claude Code to create a bump file.
-
-### OpenCode / Cursor / Codex (setup command)
-
-```bash
-# OpenCode (creates .opencode/commands/add-bumpy-change.md)
-bumpy ai setup --target opencode
-
-# Cursor (creates .cursor/rules/add-bumpy-change.mdc)
-bumpy ai setup --target cursor
-
-# Codex (creates .codex/add-bumpy-change.md)
-bumpy ai setup --target codex
-```
-
-### Any AI tool (non-interactive CLI)
-
-Any LLM can create bump files using the non-interactive CLI:
-
-```bash
-bumpy add \
- --packages "@myorg/core:minor,@myorg/cli:patch" \
- --message "Added new encryption API" \
- --name "add-encryption-api"
-```
-
-See the "Non-interactive bump file creation" section above for details.
diff --git a/packages/bumpy/package.json b/packages/bumpy/package.json
index 949005b..a86149c 100644
--- a/packages/bumpy/package.json
+++ b/packages/bumpy/package.json
@@ -37,6 +37,7 @@
},
"scripts": {
"build": "tsdown",
+ "prepack": "cp ../../README.md .",
"check": "bun run tsc --noEmit",
"test": "bun test"
},
diff --git a/packages/bumpy/src/types.ts b/packages/bumpy/src/types.ts
index 006b365..5f2f37f 100644
--- a/packages/bumpy/src/types.ts
+++ b/packages/bumpy/src/types.ts
@@ -158,7 +158,7 @@ export const DEFAULT_CONFIG: BumpyConfig = {
preamble: [
`
`,
'',
- `This PR was created and will be kept in sync by [bumpy](https://bumpy.varlock.dev) based on your .bumpy bump files. Merge it when you are ready to release the packages listed below:`,
+ `This PR was created and will be kept in sync by [bumpy](https://bumpy.varlock.dev) based on your bump files (in \`.bumpy/\`). Merge it when you are ready to release the packages listed below:`,
'
',
].join('\n'),
},