Beads 多仓库路由(Multi-Repo Routing)实战指南:让bd create智能决定每个 bead 归属的仓库
【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads
导读:当同一个开发者在多个仓库之间工作(OSS fork + 私有规划仓库、规划仓库驱动实现仓库、一台机器上的多个项目检出)时,Beads 的路由(Routing)机制决定每个新创建的 bead 写入哪个仓库的数据库。本文以 docs/multi-agent/routing.md 为核心,结合仓库源码讲解路由决策的优先级、角色检测、bd init --contributor向导、逐 bead 覆盖(--repo)与多仓库水合(Hydration),读完你可以在不污染上游 PR 的前提下自由规划、并在多个仓库之间维持统一视图。
为什么需要路由:贡献者困境
路由要解决的是一个非常具体的场景:你 fork 了一个使用 beads 的 OSS 项目,然后开始在 fork 上工作。如果没有路由,你在 fork 中创建的每一个规划类 bead 都会写入 fork 的.beads/数据,于是你的 fork 的问题数据库在每次向 upstream 开 PR 时都与上游不断分叉——你只是想关于这个项目做规划,却不得不在项目里做规划。
路由通过检测你的身份(maintainer / contributor)来解决这个问题:将bd create重定向到一个独立于项目的规划仓库(默认~/.beads-planning),这个仓库永远不会被 push 到上游。
路由是**opt-in(可选启用)**的。没有任何路由配置时,每个 bead 都落在当前仓库——本页所述的一切都不会改变单仓库工作流的行为。这一点在源码层面也有体现:internal/routing/routing.go中DetermineTargetRepoWithRule在没有配置任何规则时返回"."(当前仓库)并标记为RuleNone。
路由如何决策:严格的优先级
运行bd create时,目标仓库按照严格优先级选择:
--repo <path>—— 显式覆盖,永远优先routing.mode: auto—— 按检测到的角色(maintainer 或 contributor)路由routing.default—— 其余一切情况(默认.,即当前仓库)
这一优先级在 cmd/bd/create.go 中有完整的源码实现:bd create首先检查--repoflag 是否被显式设置(cmd.Flags().Changed("repo")),若设置则直接使用该值作为目标仓库;否则调用routing.DetectUserRole(".")检测角色,并从 config.yaml / 数据库配置中读取routing.mode、routing.default、routing.maintainer、routing.contributor,最终调用routing.DetermineTargetRepo(routingConfig, userRole, ".")得出落点。
决策内核在 internal/routing/routing.go:
func DetermineTargetRepoWithRule(config *RoutingConfig, userRole UserRole, repoPath string) (string, RoutingRule) { // Explicit override takes precedence if config.ExplicitOverride != "" { return config.ExplicitOverride, RuleExplicitOverride } // Auto mode: route based on user role if config.Mode == "auto" { if userRole == Maintainer && config.MaintainerRepo != "" { return config.MaintainerRepo, RuleMaintainer } if userRole == Contributor && config.ContributorRepo != "" { return config.ContributorRepo, RuleContributor } } // Fall back to default repo if config.DefaultRepo != "" { return config.DefaultRepo, RuleDefault } // No routing configured - use current repo return ".", RuleNone }该函数还返回一个RoutingRule枚举(RuleNone/RuleExplicitOverride/RuleMaintainer/RuleContributor/RuleDefault),用于在 CLI 输出中准确说明"为什么被路由走了",而不是硬编码成 contributor 一种原因。
读取同样遵循路由:路由启用时,bd list和bd ready从被路由到的仓库读取;而bd show <id>之类的 ID 查询在当前仓库找不到时,会回退到被路由的仓库。这一逻辑位于 cmd/bd/routing_read.go 的openRoutedReadStore:它通过determineAutoRoutedRepoPath解析目标仓库路径,若结果为空或"."则保持本地读取(RuleNone),否则打开目标仓库的.beads/目录作为只读 store。特别地,bd stats和bd show <id>不参与路由,始终报告本地项目的事实——正是这种"读取被路由、统计不路由"的分裂让问题难以诊断,因此 routing_read.go 在路由生效时向 stderr 打印一条 notice(受--quiet抑制),并给出对应的修复命令:
note: contributor routing (beads.role=contributor, or inferred from the origin URL) routes bd list/ready to the contributor planning store, not this project (this project has N total issue(s)). Fix: git config beads.role maintainer角色检测(Role Detection)
驱动 auto 模式的角色来自 git config——beads.role是权威来源:
bd config set beads.role contributor # 存储在 git config,而不是数据库 bd config get beads.role在源码 internal/routing/routing.go 中,DetectUserRole的检测顺序是:
- 读取 git config 中的
beads.role(首选,roleFromGitConfig调用git config --get beads.role,只认maintainer/contributor两个合法值); - jj 次级工作区特殊处理:次级工作区没有自己的
.git,会先解析主工作区(git.GetJJPrimaryWorkspaceRootFrom)再重试读取,同时把后续启发式判断锚定到主工作区的 git 仓库(GH#2950); - 回退到已废弃的远程 URL 启发式,并打印警告。
当beads.role未设置时,bd打印警告并回退到远程 URL 启发式。detectFromURL(internal/routing/routing.go)的判定规则如下:
| Git 远程情况 | 检测到的角色 |
|---|---|
origin和upstream指向不同仓库(fork 工作流) | contributor |
SSHorigin(git@...、ssh://)或带凭据的 HTTPS | maintainer |
不带凭据的纯 HTTPSorigin | contributor |
| 未配置远程(本地项目) | maintainer |
注意:SSH 并不能可靠地表示推送权限——fork 贡献者常常也通过 SSH clone。显式设置
beads.role后,启发式(及其警告)就永远不会运行。
此外,sameRemoteRepository会通过remoteRepositorySlug规范化远程地址(支持git@host:owner/repo.git与https://host/owner/repo.git两种形态、剥离.git后缀),避免因协议书写差异把同一个仓库误判为 fork。
设置(Setup)
贡献者(Contributors)
cd ~/projects/my-fork bd init --contributor这个交互式向导的实现位于 cmd/bd/init_contributor.go(runContributorWizard),完整流程如下:
- 检测 fork 关系:通过
git remote get-url upstream判断是否存在upstream远程(detectForkSetup)。若检测到 fork,向导显示 "Detected fork workflow";若没有upstream远程,会提示git remote add upstream <original-repo-url>,并询问是否继续。 - 检查 origin 推送权限(
checkPushAccess):SSH URL(git@开头)视为有推送权限,纯 HTTPS 视为只读。有推送权限时向导会再次确认"是否仍要使用独立规划仓库"。 - 创建规划仓库:默认在
~/.beads-planning(若设置了BEADS_DIR环境变量则以它为准,但会先警告BEADS_DIR优先于 contributor 路由)。该目录若不存在,会依次执行git init、创建.beads/目录、写入一份 README、并完成 initial commit,使其成为独立的 git 仓库。 - 配置路由:在数据库 store 中写入
routing.mode=auto与routing.contributor=<规划仓库路径>(init_contributor.go)。 - 启用多仓库水合:把规划仓库加入
repos.additional,使路由产生的 bead 在bd list中可见。 - fork 时配置同步源:写入
sync.remote=upstream,让bd dolt pull从源仓库而不是你自己的 fork 拉取 issue 数据。
向导结束后会输出配置摘要,并提示尝试bd create "Plan feature X" -p 2验证路由效果。
普通bd init也会自动检测 fork 模式(存在与origin不同的upstream远程)并自动套用同样的 contributor 配置(autoConfigureForkContributor,cmd/bd/init_contributor.go):它是非交互且幂等的,会创建~/.beads-planning、设置routing.mode=auto、routing.contributor、sync.remote=upstream、写入git config beads.role contributor并配置水合;若路由已配置则跳过(幂等)。传入--role maintainer可退出此自动配置。
团队(Teams)
bd init --team共享一个仓库的团队通常不需要路由:不设置路由时,每个 bead 都落在共享仓库里。团队向导配置的是其余共享工作流——团队模式,以及在受保护主干(protected-main)场景下为 issue 提交单独设置一个同步分支。想要私有 scratch 空间的团队成员可以显式路由实验内容:
bd create "Try alternative approach" --repo ~/.beads-planning-personal两种场景(以及多阶段、多人格设置)的完整逐步演练见 Multi-Repo Migration。
配置参考(Configuration Reference)
以下键用bd config set <key> <value>设置;存储位置参见 configuration reference。其中beads.role写入 git config(而非数据库,见 cmd/bd/doctor/role.go 的读取逻辑:先查 git config,再回退数据库配置);repos.primary/repos.additional写在.beads/config.yaml的repos:段(见 repo 命令文档)。
| 键 | 默认值 | 含义 |
|---|---|---|
routing.mode | (未设置) | auto按角色路由;explicit(或未设置)把一切发送到routing.default |
routing.default | . | auto 模式关闭时的目标 |
routing.maintainer | . | auto 模式下 maintainer 的目标 |
routing.contributor | ~/.beads-planning | auto 模式下 contributor 的目标 |
repos.primary | (未设置) | 多仓库水合的主仓库 |
repos.additional | (未设置) | 从中水合 bead 的仓库列表 |
beads.role | (未设置) | 显式角色:maintainer或contributor(存储在 git config) |
验证生效配置及各值的来源:
bd config show # 所有来源:config.yaml、database、git、env bd config validate # 检查 routing.mode 取值及相关设置 bd where # 当前目录实际使用哪个数据库从源码看,bd config validate(对应 cmd/bd/doctor/config_values.go 中的validRoutingModes)接受的routing.mode合法值为auto、maintainer、contributor、explicit四种;validateRoutingPaths还会检查routing.default/routing.maintainer/routing.contributor指向的路径是否存在("."除外)。配置来源的优先级链在 docs/reference/configuration.md 有说明:config.yaml按~/.beads/config.yaml→~/.config/bd/config.yaml→<repo>/.beads/config.yaml→$BEADS_DIR/config.yaml顺序查找(后者覆盖前者),config.local.yaml最后合并;当 config.yaml 或环境变量遮蔽数据库键时,bd config list会打印覆盖警告,bd config show会报告每个生效键的来源。
逐 bead 覆盖(Overriding per bead)
--repo为单个 bead 完全绕过路由:
bd create "Fix upstream bug" --repo . # 强制写入当前仓库 bd create "Private experiment" --repo ~/scratch # 强制写入另一个仓库在 cmd/bd/create.go 中该 flag 的定义是Target repository for issue (overrides auto-routing)。注意:显式--repo指向的目标如果是相对路径/裸路径且不存在 beads workspace,创建会被拒绝并给出提示(isAmbiguousRepoTarget的防呆逻辑,cmd/bd/create.go),要求传绝对路径或~/前缀的路径;而来自配置的 auto 路由路径则始终允许自动创建(auto-vivify)。--repo也支持远程 URL——此时会通过remotecache.DefaultCache()确保远程仓库同步并打开其 store(cmd/bd/create.go)。
发现的工作保持归属父仓库
带discovered-from依赖创建的 bead 会继承父任务的source_repo,因此执行任务过程中发现的后续工作始终归属到与父任务相同的仓库——无论你的角色是什么:
bd create "Found race in auth" --deps discovered-from:bd-abc # 继承 bd-abc 的 source_repo实现位于 cmd/bd/create.go:create在解析--deps后,若存在discovered-from依赖,则查询父 issue 并继承其SourceRepo字段;父 issue 查询失败或无source_repo时沿用默认。添加--repo可覆盖这一继承。
多仓库水合(Multi-Repo Hydration)
路由把 bead 写入另一个仓库——这意味着你当前的数据库里没有它们。**水合(Hydration)**把其他仓库的 bead 导入你的数据库,每个 bead 都带source_repo标记,于是bd list和bd ready呈现统一视图。
配置方式是把其他仓库列入repos.additional:
bd repo add ~/.beads-planning # 添加一个要水合的仓库 bd repo list # 显示 primary + additional 仓库 bd repo sync # 从所有 additional 仓库导入 bead bd repo remove ~/.beads-planning # 移除,并删除其已水合的 beadbd repo sync的实现细节在 cmd/bd/repo.go:
- 逐个读取每个 additional 仓库的
.beads/issues.jsonl导出文件,把 bead 连同其原始前缀一起导入,并设置source_repo; - 用mtime 缓存跳过导出未变化的仓库(
store.GetRepoMtime/SetRepoMtime比较issues.jsonl的ModTime); - 导入时使用
SkipPrefixValidation: true,以支持跨前缀水合(cross-prefix hydration); bd repo remove除了从repos.additional删除路径(路径必须与添加时完全一致,例如添加~/foo就必须移除~/foo而非/home/user/foo),还会删除数据库中来自该仓库的已水合 bead(见 repo 命令文档)。
bd init --contributor会自动接好水合链路;bd doctor在路由目标缺失于repos.additional时给出警告——cmd/bd/doctor/config_values.go 专门检查routing.mode=auto且存在路由目标时,repos.additional是否已配置并包含每个路由目标(展开~后逐一比对),否则提示Run 'bd repo add <routing-target>' to enable hydration。
水合完成后,来自其他仓库的 bead 就是你数据库里的普通行——可以按来源过滤,或用普通依赖关联:
bd list --json | jq '.[] | select(.source_repo == "~/.beads-planning")' bd dep add impl-42 plan-10 --type blocksbd dep add还支持针对另一个项目能力(而非具体 bead)的external:<project>:<capability>目标——见 bd dep 命令参考。
一个 Agent 管理多个项目(One Agent, Many Projects)
跨多个仓库工作的 AI Agent 应该运行单个beads MCP server 实例:
{ "beads": { "command": "beads-mcp", "args": [] } }server 会从每个请求的工作目录解析 beads workspace,因此一份配置即可服务所有项目,而每个项目保持自己隔离的数据库(默认 embedded Dolt 位于.beads/embeddeddolt/;server 模式使用.beads/dolt/)。每个项目各自跑一个 MCP 实例反而容易让操作落到错误的数据库。
若希望跨项目共享一个 Dolt server(而非每项目 embedded 存储),用bd init --shared-server初始化(或设置BEADS_DOLT_SHARED_SERVER=1):所有项目共享~/.beads/shared-server/上的一个 server,同时以各自的 issue 前缀命名的数据库保持隔离。安装与客户端配置见 MCP Server。
排障(Troubleshooting)
bead 落在错误的仓库
bd config get routing.mode # auto? bd config get beads.role # 设置了显式角色吗? bd config show --source git # git config 贡献了哪些值修复方式:显式设置角色(bd config set beads.role maintainer)、为单个 bead 强制目标(--repo .)、或完全禁用角色检测(bd config set routing.mode explicit)。
路由后的 bead 不出现在 bd list
路由目标没有被水合。添加并同步:
bd repo add ~/.beads-planning bd repo syncbd doctor能捕获这种错误配置(对应 config_values.go 的一致性检查)。
发现类 bead 出现在"错误"的仓库
这是有意的——带discovered-from依赖的 bead 继承父任务的source_repo。创建时用--repo覆盖即可。
规划 bead 出现在上游 PR 中
规划仓库必须是独立的 git 仓库,绝不能提交到 fork:
ls ~/.beads-planning/.git # 应该存在 bd config get routing.contributor # 应该指向规划仓库每次 bd create 都有角色警告
bd在回退到 URL 启发式时会发出警告。永久消除:
bd config set beads.role maintainer # 或 contributor相关资源
- Multi-Repo Migration —— contributor、team、multi-phase 工作流的完整设置演练(含手动配置
routing.mode、repos.additional、多阶段/多人格仓库划分与最佳实践) - Agent Coordination —— 在 agent 之间分配与认领工作
- Federation —— 跨仓库、跨组织的 bead 点对点共享
- 命令参考:
bd init、bd config、bd repo、bd create - 配置总览:configuration reference(config.yaml 查找顺序、配置来源与优先级)
- 实现依据:internal/routing/routing.go、cmd/bd/create.go、cmd/bd/init_contributor.go、cmd/bd/routing_read.go、cmd/bd/repo.go
【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考