RELEASING.md
This document describes the complete release process for beads, including GitHub releases, Homebrew, PyPI (MCP server), and npm packages.
A beads release involves multiple distribution channels:
beads-mcp)@beads/bd)git with push access to gastownhall/beadsgoreleaser for building binariesnpm with authentication (for npm releases)python3 and twine (for PyPI releases)gh CLI (GitHub CLI, optional but recommended)beads-mcp package@beads organization# Check git
git remote -v # Should show gastownhall/beads
# Check goreleaser
goreleaser --version
# Check GitHub CLI (optional)
gh auth status
# Check npm
npm whoami # Should show your npm username
# Check Python/twine (for MCP releases)
python3 --version
twine --version
Before starting a release:
go test ./...)cd npm-package && npm run test:all)make test-upgrade) — see Release Stability Gatemake test-regression)main branch and up to date with originIMPORTANT: Do this FIRST before running bump-version script.
Add release notes to CHANGELOG.md:
## [0.22.0] - 2025-11-04
### Added
- New feature X
- New command Y
### Changed
- Improved performance of Z
### Fixed
- Bug in component A
### Breaking Changes
- Changed behavior of B (migration guide)
Commit the CHANGELOG changes:
git add CHANGELOG.md
git commit -m "docs: Add CHANGELOG entry for v0.22.0"
git push origin main
Use the version bump script to update all version references and create the release tag:
# Dry run - shows what will change
./scripts/bump-version.sh 0.22.0
# Full release with all local installations
./scripts/bump-version.sh 0.22.0 --commit --tag --push --all
Available flags:
| Flag | Description |
|---|---|
--commit | Create a git commit with version changes |
--tag | Create annotated git tag (requires --commit) |
--push | Push commit and tag to origin (requires --tag) |
--install | Build and install bd to ~/go/bin AND ~/.local/bin |
--mcp-local | Install beads-mcp from local source via uv/pip |
--upgrade-mcp | Upgrade beads-mcp from PyPI (after PyPI publish) |
--restart-servers | Restart all Dolt servers to pick up new version |
--all | Shorthand for --install --mcp-local --restart-servers |
This updates:
cmd/bd/version.go - CLI version constantintegrations/beads-mcp/pyproject.toml - MCP server versionintegrations/beads-mcp/src/beads_mcp/__init__.py - MCP Python versionclaude-plugin/.claude-plugin/plugin.json - Plugin version.claude-plugin/marketplace.json - Marketplace versionnpm-package/package.json - npm package versioncmd/bd/templates/hooks/* - Git hook versionsREADME.md - Documentation versionPLUGIN.md - Version requirementsCHANGELOG.md - Creates release entry from [Unreleased]The --commit --tag --push flags will:
v0.22.0This triggers GitHub Actions to build release artifacts automatically.
Recommended workflow:
# 1. Update CHANGELOG.md and cmd/bd/info.go with release notes (manual step)
# 2. Bump version and install everything locally
./scripts/bump-version.sh 0.22.0 --commit --all
# 3. Test locally, then tag and push
git tag -a v0.22.0 -m "Release v0.22.0"
git push origin main
git push origin v0.22.0
Alternative (step-by-step):
# Just commit
./scripts/bump-version.sh 0.22.0 --commit
# Then manually tag and push
git tag -a v0.22.0 -m "Release v0.22.0"
git push origin main
git push origin v0.22.0
GoReleaser automates binary building and GitHub release creation:
# Clean any previous builds
rm -rf dist/
# Create release (requires GITHUB_TOKEN)
export GITHUB_TOKEN="your-github-token"
goreleaser release --clean
# Or use gh CLI for token
gh auth token | goreleaser release --clean
This will:
If goreleaser doesn't work:
# Build for all platforms
./scripts/build-all-platforms.sh
# Create GitHub release
gh release create v0.22.0 \
--title "v0.22.0" \
--notes-file CHANGELOG.md \
dist/*.tar.gz \
dist/*.zip \
dist/checksums.txt
beads_0.22.0_darwin_amd64.tar.gzbeads_0.22.0_darwin_arm64.tar.gzbeads_0.22.0_linux_amd64.tar.gzbeads_0.22.0_linux_arm64.tar.gzbeads_0.22.0_windows_amd64.zipchecksums.txtHomebrew formula is now in homebrew-core. Updates are handled automatically via GitHub Release artifacts.
After the GitHub Release is published, verify the Homebrew package:
# Update Homebrew
brew update
# Install/upgrade
brew upgrade beads # or: brew install beads
# Verify
bd version # Should show 0.22.0
The MCP server is a Python package published separately to PyPI.
# Install build tools
pip install build twine
# Verify PyPI credentials
cat ~/.pypirc # Should have token or credentials
# Navigate to MCP server directory
cd integrations/mcp/server
# Verify version was updated
cat pyproject.toml | grep version
# Clean old builds
rm -rf dist/ build/ *.egg-info
# Build package
python -m build
# Verify contents
tar -tzf dist/beads-mcp-0.22.0.tar.gz
# Upload to PyPI (test first)
twine upload --repository testpypi dist/*
# Verify on test PyPI
pip install --index-url https://test.pypi.org/simple/ beads-mcp==0.22.0
# Upload to production PyPI
twine upload dist/*
# Check package page
open https://pypi.org/project/beads-mcp/
# Install and test
pip install beads-mcp==0.22.0
python -m beads_mcp --version
Update the Claude Code marketplace metadata files:
# Update .claude-plugin/marketplace.json
# Change version to match current release
vim .claude-plugin/marketplace.json
# Update claude-plugin/.claude-plugin/plugin.json if needed
vim claude-plugin/.claude-plugin/plugin.json
# Commit changes
git add .claude-plugin/ claude-plugin/.claude-plugin/
git commit -m "chore: Update Claude Code marketplace to v0.22.0"
Note: These files define how beads appears in Claude Code's plugin marketplace. Version should match the release version.
The npm package wraps the native binary for Node.js environments.
# Verify npm authentication
npm whoami # Should show your username
# Verify you're in @beads org
npm org ls beads
# Navigate to npm package
cd npm-package
# Version should already be updated by bump-version.sh
cat package.json | grep version
# Run all tests
npm run test:all
# Should see:
# ✅ All unit tests passed
# ✅ All integration tests passed
# Pack the package
npm pack
# Install globally from tarball
npm install -g ./beads-bd-0.22.0.tgz
# Verify binary downloads correctly
bd version # Should show 0.22.0
# Test in a project
mkdir /tmp/test-npm-bd
cd /tmp/test-npm-bd
git init
bd init
bd create "Test issue" -p 1
bd list
# Cleanup
npm uninstall -g @beads/bd
rm -rf /tmp/test-npm-bd
cd -
rm beads-bd-0.22.0.tgz
# IMPORTANT: Ensure GitHub release with binaries is live first!
# The postinstall script downloads from GitHub releases
# Publish to npm (first time use --access public)
npm publish --access public
# Or for subsequent releases
npm publish
# Check package page
open https://www.npmjs.com/package/@beads/bd
# Install and test
npm install -g @beads/bd
bd version # Should show 0.22.0
# Test postinstall downloaded correct binary
which bd
bd --help
After all distribution channels are updated, verify each one:
# Download and test binary
wget https://github.com/gastownhall/beads/releases/download/v0.22.0/beads_0.22.0_darwin_arm64.tar.gz
tar -xzf beads_0.22.0_darwin_arm64.tar.gz
./bd version
brew update
brew upgrade beads
bd version
pip install --upgrade beads-mcp
python -m beads_mcp --version
npm install -g @beads/bd
bd version
# Test quick install script
curl -fsSL https://raw.githubusercontent.com/gastownhall/beads/main/scripts/install.sh | bash
bd version
For urgent bug fixes:
# Create hotfix branch from tag
git checkout -b hotfix/v0.22.1 v0.22.0
# Make fixes
# ... edit files ...
# Bump version to 0.22.1
./scripts/bump-version.sh 0.22.1 --commit
# Tag and release
git tag -a v0.22.1 -m "Hotfix release v0.22.1"
git push origin hotfix/v0.22.1
git push origin v0.22.1
# Follow normal release process
goreleaser release --clean
# Merge back to main
git checkout main
git merge hotfix/v0.22.1
git push origin main
If a release has critical issues:
gh release edit v0.22.0 --prerelease
Follow hotfix procedure above to release 0.22.1.
npm deprecate @beads/[email protected] "Critical bug, please upgrade to 0.22.1"
# Can't delete, but can yank (hide from pip install)
# Contact PyPI support or use web interface
Create .github/workflows/release.yml:
name: Release
on:
push:
tags:
- 'v*'
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
- uses: goreleaser/goreleaser-action@v4
with:
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
npm:
needs: goreleaser
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
registry-url: 'https://registry.npmjs.org'
- run: cd npm-package && npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
pypi:
needs: goreleaser
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- run: |
cd integrations/mcp/server
pip install build twine
python -m build
twine upload dist/*
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
After a successful release:
Upgrade local beads-mcp installation to the new version:
# Option 1: Use the bump-version.sh script (recommended during version bump)
./scripts/bump-version.sh <version> --upgrade-mcp
# Option 2: Manual upgrade via pip (if installed globally)
pip install --upgrade beads-mcp
# Option 3: Manual upgrade via uv tool (if installed as a tool)
uv tool upgrade beads-mcp
# Verify the new version
pip show beads-mcp | grep Version
# Restart Claude Code or MCP session to pick up the new version
# The MCP server will load the newly installed version
Note: The --upgrade-mcp flag can be combined with other flags:
# Update versions, commit, install bd binary, and upgrade beads-mcp all at once
./scripts/bump-version.sh 0.24.3 --commit --install --upgrade-mcp
Verify the upgraded CLI:
bd version
bd doctor quick
Announce on relevant channels (Twitter, blog, etc.)
Update documentation if needed
Close milestone on GitHub if using milestones
Update project board if using project management
Monitor for issues in the first 24-48 hours
# Delete tag locally and remotely
git tag -d v0.22.0
git push origin :refs/tags/v0.22.0
# Recreate
git tag -a v0.22.0 -m "Release v0.22.0"
git push origin v0.22.0
# Version already published, bump version
npm version patch
npm publish
# Ensure GitHub release is published first
# Check binary URL is correct
# Verify version matches in package.json and GitHub release
# Check .goreleaser.yml syntax
goreleaser check
# Test build locally
goreleaser build --snapshot --clean
Beads follows Semantic Versioning:
Examples:
0.21.5 → 0.22.0: New features (minor bump)0.22.0 → 0.22.1: Bug fix (patch bump)0.22.1 → 1.0.0: Stable release (major bump)