Beads 版本发布流程全指南:从 release 脚本到多渠道自动化发布
Beads 版本发布流程全指南:从 release 脚本到多渠道自动化发布
本指南以 Beads 开源仓库中的发布流程文档为核心,完整讲解如何为 Beads 发布一个新版本:从推荐的一键发布脚本、手动分步流程、版本号同步机制,到 GitHub Releases、Homebrew、PyPI(MCP 服务器)等多渠道的发布与验证。读完本文,你将掌握 Beads 完整的版本发布链路、底层脚本与 CI 自动化的实现原理,并能独立完成一次从版本升级到渠道验证的正式发布。
发布总览:Beads 的多分发渠道
Beads(CLI 工具名为 bd)是一个面向编码 Agent 的内存升级工具,其发布不是单一的二进制上传,而是覆盖多个分发渠道的协同过程:
- GitHub Release —— 面向所有平台(Linux / macOS / Windows,amd64 / arm64)的二进制下载;
- Homebrew —— macOS / Linux 的包管理器分发(
brew install beads); - PyPI —— Python 生态的 MCP 服务器包
beads-mcp(位于 integrations/beads-mcp); - npm —— 面向 Node.js 环境的包装包
@beads/bd(位于 npm-package); - 插件市场元数据 —— Claude / Codex 插件及市场清单的版本号;
- 文档站 —— CLI 文档与发布 pin(
docs/cli-docs.pin)的同步。
发布流程文档位于仓库 engdocs/staged-for-removal/RELEASING.md,根目录下另有内容更完整的 RELEASING.md 可作为交叉参考;脚本使用说明见 scripts/README.md。
推荐方式:一键发布脚本
对于常规发布,Beads 提供了"一键发布"的自动化脚本:
./scripts/release.sh 0.9.3
该脚本会完成一切:版本升级、测试、git tag、Homebrew 更新、本地安装。从源码看(scripts/release.sh),它实际上是一个"发布分子(release molecule)的网关"——它调用 bd mol wisp beads-release --var version=<版本> 创建一个带步骤清单、可观测、可断点续传的发布工作流,而不是传统意义上一次性跑完的批处理脚本。
脚本内部的选择逻辑也值得注意:
- 若环境变量
BD已设置且其指向的bd能解析仓库内的beads-releaseformula,则优先使用; - 否则回退到
PATH中的bd,再到仓库根目录编译出的./bd; - 最后兜底使用
go run -tags gms_pure_go ./cmd/bd(源码见 scripts/release.sh)。
常用的两个调用形式:
# 完整发布(做所有事情)
./scripts/release.sh 0.9.3
# 预演:只显示将要发生什么,不产生任何实际变更
./scripts/release.sh 1.0.0 --dry-run
脚本完成后的自动化接力:
- GitHub Actions 构建全平台二进制(约 5 分钟);
- PyPI 包自动发布;
- Homebrew core formula 被验证或跟踪其正式 PR;
- GitHub Release 附带二进制与 changelog 自动创建。
为什么用"发布分子"而不是脚本
scripts/release.sh 头部注释解释了这一设计决策:Orchestrator(编排器)在多步骤工作流中使用 molecule 而非批处理脚本,原因有四:
- 账本(LEDGER):每个步骤都是工作历史中的一条带时间戳记录,脚本则完全不可见;
- 可续跑(RESUMABILITY):发布在第 17 步失败时,可从第 17 步继续,脚本则必须从头再来;
- 可观测(OBSERVABILITY):
bd activity --follow可实时查看进度,脚本在结束前是黑盒; - 门禁(GATES):发布分子通过门禁等待 CI 完成,而不是轮询式忙等。
此外,脚本明确警告不要用 gh run watch 或循环轮询 CI 状态——GitHub API 每小时仅 5000 次请求,历史上多次发布因轮询耗尽整个配额、阻塞全体成员长达一小时。等待 CI 应交由分子门禁系统处理。
手动方式:逐步控制
若偏好逐步控制,Beads 也提供了完整的手动发布流程。
预发布检查清单
1. 停止所有正在运行的 Dolt 服务器(关键步骤)
# 停止所有工作区中的 Dolt 服务器
bd dolt stop
# 或按进程查找并停止
pkill -f "dolt sql-server" 2>/dev/null
pgrep -lf "dolt sql-server" || echo "No Dolt servers running ✓"
为什么这很重要:旧版本服务器会引发三类问题——
- 自动刷新(auto-flush)竞态条件,导致提交后工作树仍然脏;
- 客户端(新版)与服务器(旧版)之间的版本不匹配;
- 变更看似同步错误的神秘行为。
2. 运行测试与构建
make test
golangci-lint run ./...
make build
./bd version # 验证显示新版本号
3. 跳过本地安装(避免 go install 与 brew 冲突)
- 直接使用仓库中的
./bd进行测试; - 系统级
bd将在 Homebrew formula 更新后通过 brew 更新; - 如需临时使用,可
alias bd="$PWD/bd"。
4. 更新 CHANGELOG.md
- 添加版本标题:
## [0.9.X] - YYYY-MM-DD; - 按 Added、Fixed、Changed、Performance、Community 分类汇总变更;
- 更新 Version History 章节;
- 如有需要,添加 Upgrade Guide 章节。
5. 提交 changelog
git add CHANGELOG.md
git commit -m "Add 0.9.X release notes"
版本升级(Version Bump)
手动流程使用自动化脚本更新所有版本文件:
./scripts/bump-version.sh 0.9.X --commit
git push origin main
从源码看,scripts/bump-version.sh 目前已被标记为 DEPRECATED(已弃用)——它现在只是一个提示脚本,引导用户改用发布分子 bd mol wisp beads-release --var version=X.Y.Z,或使用纯本地版本升级脚本 scripts/update-versions.sh。这体现了发布体系从"手工脚本"向"分子编排"的演进。
当前实际负责版本同步的是 scripts/update-versions.sh,它会更新以下文件(较旧文档的清单更完整):
| 文件 | 说明 |
|---|---|
cmd/bd/version.go |
bd CLI 版本常量(当前仓库为 Version = "1.2.2",见 cmd/bd/version.go) |
plugins/beads/.claude-plugin/plugin.json |
Claude 插件版本 |
plugins/beads/.codex-plugin/plugin.json |
Codex 插件版本 |
plugins/beads/.copilot-plugin/plugin.json |
Copilot 插件版本 |
.claude-plugin/marketplace.json |
Claude 市场版本 |
integrations/beads-mcp/pyproject.toml |
MCP 服务器版本 |
integrations/beads-mcp/src/beads_mcp/__init__.py |
MCP Python __version__ |
npm-package/package.json |
npm 包版本 |
README.md |
README 中的 Alpha 版本徽章 |
default.nix |
Nix 打包版本 |
.githooks/* |
托管 git-hook 的 BEGIN/END BEADS INTEGRATION vX.Y.Z --- 标记 |
cmd/bd/winres/winres.json、cmd/bd/winres/manifest.xml |
Windows PE 资源元数据 |
脚本还会同步 integrations/beads-mcp/uv.lock(MCP 锁文件),并支持 prerelease 标识符(如 1.1.0-rc.1)。Windows PE 的数字字段(file_version / product_version / manifest 版本)只写入不含后缀的基础版本号,因为 PE 版本必须是纯数字——构建时 scripts/gen-winres.sh 也会以同样方式剥离 prerelease 后缀。
重要:版本升级后必须重新构建本地二进制:
make build
./bd version # 应显示新版本
版本一致性校验
scripts/check-versions.sh 是发布前必须通过的校验门:它以 cmd/bd/version.go 中的版本为唯一权威(canonical)来源,逐一比对 MCP pyproject.toml、__init__.py、Claude/Codex 插件 JSON、市场清单、npm package.json、MCP uv.lock(按 PEP 440 规范化后比较,1.1.0-rc.1 → 1.1.0rc1)以及 .githooks/* 标记版本,任何不一致都会以非零退出码失败。
锁文件过期曾付出过真实代价:uv sync --locked 只在 tag 触发的发布运行中失败,而 tag 已存在无法重写——这曾烧掉 v1.1.1 tag,并让 v1.1.0 与 v1.1.2 的首次发布运行失败。因此现在版本升级脚本会主动刷新锁文件,check-versions.sh 也会在 tag 创建前就拦住过期锁。
发布到所有渠道
1. 创建 Git Tag
git tag v0.9.X
git push origin main
git push origin v0.9.X
推送 tag 后,GitHub Actions 会自动处理其余部分:
- GoReleaser 构建二进制并发布到 GitHub Releases;
- PyPI 发布任务上传 MCP 服务器包到 PyPI。
发布自动化只对 v* tag 生效。应保持 refs/tags/v* 受保护,只有可信的发布维护者才能创建、更新或删除发布 tag。手动触发工作流只能从 tag 重跑发布,而不是从分支。
2. GitHub Secrets 设置(一次性)
自动化需要一个密钥:
PYPI_API_TOKEN:在 PyPI 账户管理页生成 API token,添加到仓库的 Actions secrets 设置中,命名为 PYPI_API_TOKEN,值为完整的 pypi-... token。
3. 手动 PyPI 发布(如自动化失败)
cd integrations/beads-mcp
# 清理并重建
rm -rf dist/ build/ src/*.egg-info
uv build
# 上传到 PyPI
TWINE_USERNAME=__token__ TWINE_PASSWORD=pypi-... uv tool run twine upload dist/*
详细的 PyPI 指南见 integrations/beads-mcp/PYPI.md。核心要点:
- 构建产生 wheel(
dist/beads_mcp-X.Y.Z-py3-none-any.whl)与源码包(dist/beads-mcp-X.Y.Z.tar.gz); - 先上传 Test PyPI 验证,再传生产 PyPI(
twine upload --repository testpypi dist/*); - 认证统一使用
__token__作为用户名、完整 token 作为密码; - 发布后在全新虚拟环境中
pip install beads-mcp验证beads-mcp --help与python -c "import beads_mcp; print(beads_mcp.__version__)"。
4. 验证 Homebrew 更新
Homebrew formula 位于 homebrew-core,随 GitHub Release 产物自动更新:
brew update
brew upgrade beads # 或: brew install beads
bd version # 应显示 v0.9.X
注意:如果 PATH 中残留旧的 go install 安装的 bd 二进制,需要移除以避免冲突:
# 查找 bd 安装位置
which bd
# 若在 Go 工具链路径中(如 ~/go/bin/bd 或 mise 管理的 Go),移除它
# 常见位置:
rm ~/go/bin/bd # 标准 go install 位置
rm ~/.local/share/mise/installs/go/*/bin/bd # mise 管理的 Go 安装
# 验证使用的是正确版本
which bd # 应显示 /opt/homebrew/bin/bd 或包管理器路径
bd version # 应显示最新版本
有趣的是,bd version 命令本身会检测 PATH 中的重复二进制并给出警告(见 cmd/bd/version.go 的 findDuplicateBinaries),这正是多安装来源冲突的常见场景。
5. GitHub Releases(自动化)
推送 tag 后 GoReleaser 自动创建 release。.github/workflows/release.yml 工作流:
- 由
v*tag 触发; - 构建跨平台二进制(Linux、macOS、Windows 的 amd64/arm64);
- 生成校验和(checksums);
- 用二进制与 changelog 创建 GitHub Release;
- 自动发布。
只需推送 tag 并等待约 5 分钟:
git push origin v0.9.X
tag 工作流在发布前会重跑关键发布包门禁:
make ci-package-mcp:构建并校验 MCP 包,PyPI 任务发布的是该门禁产生的已验证dist/*产物;make ci-package-npm:在 npm 发布前校验 npm 包装包。
npm 发布任务还会等待 macOS 发布产物就绪,因为 npm 包的 postinstall 脚本需要从 GitHub Release 下载平台专属归档。
6. 文档站同步
发布流程文档提到文档站是版本化的:未发布的编辑位于 website/docs/(标记为 Next),每次发布都应生成快照:
cd website
npm ci
npm run docusaurus docs:version X.Y.Z
然后在 website/docusaurus.config.ts 中设置 lastVersion 为 X.Y.Z,让访客默认看到最新稳定版文档而非 Next。随发布提交 website/versioned_docs/、website/versioned_sidebars/ 与 website/versions.json。
需要注意的是,仓库现状中文档体系已进一步演进:根目录 RELEASING.md 说明当前文档站为 Mintlify(docs/),随 main 分支自动部署,无需发布时快照;但 发布 pin 是发布时的必需步骤——docs/cli-docs.pin 记录了文档语料生成与校验所依据的发布 tag:
# tag 之后执行:
echo "v0.22.0" > docs/cli-docs.pin
./scripts/generate-cli-docs.sh
git add docs/cli-docs.pin docs/CLI_REFERENCE.md docs/cli-reference docs/docs.json
git commit -m "docs: bump CLI docs pin to v0.22.0"
git push origin main
跳过此步不会快速失败——scripts/check-doc-flags.sh 的第 4 项检查会基于旧 pin 保持绿色,直到下次 bump 时,跨越的多次发布中新增的所有命令会一次性堆积成大量 "missing from docs/CLI_REFERENCE.md" 失败,且难以定位是哪次发布导致的。
预发布(RC)工作流
发布候选(RC)让构建经过完整发布管线验证,但不推送到稳定渠道。RC 携带 SemVer 预发布标识符(如 1.1.0-rc.1);Python 工具链会将其规范化为 PEP 440 形式(1.1.0rc1)。
预发布 tag 与稳定发布的关键差异:
- GitHub Release 发布并被标记为 prerelease(GoReleaser
release.prerelease: auto),含全平台二进制; - Homebrew 不更新(GoReleaser
brews.skip_upload: true,core formula 只跟踪稳定发布); - PyPI 与 npm 发布任务被跳过——
publish-pypi和publish-npm任务以!contains(github.ref_name, '-')为门,含-的 tag 永远不会进入稳定包渠道; - 文档不受影响。
切一个 RC:
# 1. 更新 CHANGELOG.md 与 cmd/bd/info.go 的 RC 说明(手动步骤),为 CHANGELOG 章节标注日期
# 2. 升级版本,update-versions.sh 接受预发布标识符
./scripts/update-versions.sh 1.1.0-rc.1
# Windows PE 数字字段(winres file_version/product_version 及 manifest
# <assemblyIdentity> 版本)设为基础版本 1.1.0,因为 PE 版本必须为纯数字
# 3. 保持 MCP 锁文件同步(PEP 440 规范化为 1.1.0rc1),否则 Package Gate (MCP) 检查变红
(cd integrations/beads-mcp && uv lock)
# 4. 本地校验
./scripts/check-versions.sh
# 5. 为 RC 准备打开 PR 并评审,RC 准备应走正常评审而非自动合并
RC 准备合并到 main 后,从合并提交切 tag:
git checkout main && git pull
git tag -a v1.1.0-rc.1 -m "Release candidate v1.1.0-rc.1"
git push origin v1.1.0-rc.1
验证与提升(promote):从 GitHub prerelease 产物安装 RC 并充分验证;要提升为稳定版,用不带后缀的基础版本 bump(./scripts/update-versions.sh 1.1.0),稳定发布会真正推送 Homebrew/PyPI/npm。
热修复与回滚
热修复发布
# 从 tag 创建热修复分支
git checkout -b hotfix/v0.22.1 v0.22.0
# 进行修复
# ... 编辑文件 ...
# 升级版本到 0.22.1
./scripts/bump-version.sh 0.22.1 --commit
# 打 tag 并发布
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
# 遵循正常发布流程
goreleaser release --clean
# 合并回 main
git checkout main
git merge hotfix/v0.22.1
git push origin main
回滚流程
若发布存在严重问题:
- 将 GitHub Release 标记为 prerelease:
gh release edit v0.22.0 --prerelease - 创建热修复版本:按上述热修复流程发布 0.22.1;
- 弃用 npm 包(如需):
npm deprecate @beads/bd@0.22.0 "Critical bug, please upgrade to 0.22.1"; - Yank PyPI 版本(如需):PyPI 不允许删除,但可以 yank(从
pip install隐藏)。
版本号规则与发布节奏
Beads 遵循语义化版本(Semantic Versioning):
- MAJOR(x.0.0):破坏性变更;
- MINOR(0.x.0):向后兼容的新功能;
- PATCH(0.0.x):向后兼容的缺陷修复。
示例:0.21.5 → 0.22.0 为小版本(新功能);0.22.0 → 0.22.1 为补丁(缺陷修复);0.22.1 → 1.0.0 为大版本(稳定发布)。预发布追加 SemVer 预发布标识符(如 1.1.0-rc.1),只发布 GitHub prerelease,不进入稳定 Homebrew/PyPI/npm 渠道。
发布节奏:小版本每 2-4 周;补丁按需发布;大版本在出现破坏性变更时发布。
发布后操作
- 停止旧 Dolt 服务器,确保本地立即使用新版本:
bd dolt stop pkill -f "dolt sql-server" 2>/dev/null pgrep -lf "dolt sql-server" || echo "No Dolt servers running ✓" - 验证安装:
# Homebrew brew update && brew upgrade beads && bd version # PyPI pip install --upgrade beads-mcp beads-mcp --help - 发布公告(可选):项目 Discord/Slack、社交媒体、README 徽章。
排障指南
过期的 dist/ 目录
上传前始终 rm -rf dist/,避免上传旧版本。
PyPI 版本冲突
PyPI 不允许重复上传同一版本。即使只是修复也要递增版本号。
Homebrew SHA256 不匹配
推送 tag 后等待几秒,让 GitHub 生成 tarball,再重新计算 SHA256。
缺少 PyPI 凭据
在 PyPI 账户管理页设置 API token,并使用 __token__ 作为用户名。
"Tag already exists"
git tag -d v0.22.0
git push origin :refs/tags/v0.22.0
git tag -a v0.22.0 -m "Release v0.22.0"
git push origin v0.22.0
"npm publish fails with EEXIST"
版本已发布过,执行 npm version patch 后重新 npm publish。
npm postinstall 二进制下载失败
确保 GitHub Release 先发布,检查二进制 URL 正确,确认 package.json 与 GitHub Release 中的版本一致。
GoReleaser 构建失败
goreleaser check # 检查 .goreleaser.yml 语法
goreleaser build --snapshot --clean # 本地测试构建
自动化状态一览
已自动化:
- GitHub Releases 含二进制(GoReleaser + GitHub Actions);
- PyPI 发布(经 GitHub Actions 自动化);
- 跨平台构建(Linux、macOS、Windows);
- 校验和与 changelog 生成;
- Windows 二进制签名(scripts/sign-windows.sh,经 GoReleaser 自动调用,未配置签名密钥时优雅降级为不签名)。
TODO:
- 自动更新 Homebrew formula(当前由 GitHub Release 产物驱动 homebrew-core 更新)。
相关文档
- CHANGELOG.md —— 发布历史;
- scripts/README.md —— 版本升级脚本与一键发布脚本细节;
- integrations/beads-mcp/PYPI.md —— 详细 PyPI 发布指南;
- RELEASING.md —— 根目录下内容更完整的发布流程(含 RC、热修复、回滚全流程)。