Beads 的bd swarm:基于 Epic 依赖 DAG 编排编码 Agent 并行工作流
【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads
导读
bd swarm是 Beads(bdCLI)中用于协调 Epic 并行工作的集群(swarm)管理命令组。它把一个 Epic 及其子任务、以及子任务之间的依赖关系抽象成一张有向无环图(DAG),据此创建可被任意协调 Agent(coordinator)拾取的 swarm 分子(swarm molecule)、实时计算集群进度、并校验 Epic 结构是否具备并行执行条件。读完本文,你将掌握bd swarm create / list / status / validate四个子命令的完整用法、全部 Flags 与 JSON 输出,并从源码层面理解 Ready Front(就绪波次)、依赖方向检查与环检测的底层实现原理。
什么是 Swarm:Epic + 依赖 DAG + 分子
从官方文档与源码定义看,swarm 是一个由 Epic 及其子任务构成的结构化工作体,子任务之间的依赖关系形成一张 DAG(directed acyclic graph)。其入口定义位于 cmd/bd/swarm.go:
"A swarm is a structured body of work defined by an epic and its children, with dependencies forming a DAG (directed acyclic graph) of work."
swarm 并不是一张独立存储的表,而是一个**"分子"(molecule)**——Beads 中mol_type为swarm的特殊 Issue。在 internal/types/types.go 中可以看到三种分子类型:
| mol_type | 含义 |
|---|---|
swarm | 协调多 worker 并行工作的分子 |
patrol | 周期性运维工作的分子 |
work | 常规指派工作分子(默认) |
swarm 分子通过一条relates-to类型的依赖边指向它编排的 Epic,从而建立"分子 ↔ Epic"的关联;Epic 再通过parent-child依赖边挂载全部子任务。整个体系围绕依赖图工作:状态由底层 beads(Issue 及其依赖关系)实时计算得出,而非单独存储,因此任何一条 Issue 状态或依赖关系的变化都会立即反映到 swarm 的进度与就绪情况中。
通用行为与前提
bd swarm [flags]作为命令组,其下挂载create、list、status、validate四个子命令(注册见 cmd/bd/swarm.go)。- 所有子命令都支持全局
--json标志输出机器可读结果;部分子命令还有自己的专属 Flags。 - 命令需要已打开的数据库连接(
no database connection报错),Issue ID 支持部分 ID 解析(utils.ResolvePartialID),即输入前缀即可匹配完整 ID。 - 在 proxied-server(代理服务)模式下,
create与list会直接报"not supported in proxied-server mode",而status与validate可通过代理服务器执行(见 swarm_proxied_server.go)。
bd swarm create:创建 swarm 分子
create用于为一个 Epic 创建编排并行工作的 swarm 分子。
bd swarm create [epic-id] [flags]Flags
| Flag | 类型 | 默认值 | 说明 |
|---|---|---|---|
--coordinator string | string | 空 | 协调者地址,例如my-project/witness;指定后该分子可被任何协调 Agent 拾取 |
--force | bool | false | 即使已存在 swarm 分子也强制新建 |
典型用法
bd swarm create bd-epic-123 # 为 epic 创建 swarm bd swarm create bd-epic-123 --coordinator=observer/ # 指定协调者 bd swarm create bd-task-456 # 自动包裹单个 issue行为细节
输入为 Epic(或 molecule)时,直接以该 Epic 为目标创建分子。输入为普通 Issue(非 Epic)时自动包裹(auto-wrap):先创建一个标题形如Swarm Epic: <原标题>的 Epic,把该 Issue 作为其唯一子任务(通过parent-child依赖挂载),再为这个新 Epic 创建 swarm 分子。源码路径见 cmd/bd/swarm.go。
创建过程包含以下关键步骤:
- 解析输入 ID:通过
utils.ResolvePartialID定位 Issue,类型不是 Epic/molecule 则走自动包裹逻辑。 - 查重:调用
findExistingSwarm(cmd/bd/swarm.go)遍历 Epic 的所有依赖者,找出mol_type=swarm且通过relates-to边指向该 Epic 的既有分子;若已存在且未传--force,则报错提示Use --force to create another.。 - 结构预检:对 Epic 调用
analyzeEpicForSwarm做可 swarm 性分析;若存在环等结构性错误(Swarmable=false),拒绝创建并列出错误清单。 - 创建分子:生成一个
mol_type=swarm、IssueType=molecule的新 Issue,标题为Swarm: <Epic标题>,Assignee设为 coordinator(可空),再添加一条指向 Epic 的relates-to依赖边,形成"分子 → Epic"的关联。
--json模式下成功输出包含swarm_id、epic_id、coordinator、analysis(完整 SwarmAnalysis)四个字段;已有分子时输出error、existing_id、existing_title。
bd swarm list:列出全部 swarm 及进度
list列出仓库中所有 swarm 分子,并附带各自进度信息。
bd swarm list [flags]bd swarm list # 列表人类可读输出 bd swarm list --json # 机器可读输出列表项(SwarmListItem,见 cmd/bd/swarm.go)包含:
id/title:分子 ID 与标题epic_id/epic_title:通过relates-to依赖追溯到的目标 Epicstatus、coordinator:分子状态与协调者(来自Assignee)total_issues、completed_issues、active_issues、progress_percent:由getSwarmStatus实时计算
实现上,list以MolType=swarm为过滤条件调用SearchIssues(cmd/bd/swarm.go),随后对每个分子逐条解析relates-to边找到 Epic 并计算进度。人类可读输出形如:
🐝 Active Swarms (2) gt-swarm-456 Swarm: Release 2.0 Epic: gt-epic-123 (Release 2.0) Progress: 3/8, 2 active (38%) Coordinator: observer/bd swarm status:从 beads 实时计算集群状态
status展示某个 swarm 的当前状态。它的输入有两种:Epic ID(展示该 Epic 子任务的状态)或swarm 分子 ID(沿relates-to边回溯找到 Epic)。
bd swarm status [epic-or-swarm-id] [flags]bd swarm status gt-epic-123 # 按 epic 查状态 bd swarm status gt-swarm-456 # 经分子回溯 epic bd swarm status gt-epic-123 --json四类状态分组
输出将全部子任务按状态分为四组(计算逻辑见getSwarmStatus,cmd/bd/swarm.go):
| 分组 | 判定规则 |
|---|---|
| Completed(已完成) | 状态为 Closed,附closed_at时间 |
| Active(进行中) | 状态为 in_progress,附assignee |
| Ready(就绪) | 处于 Open 且所有依赖都已满足(无未关闭的前置依赖) |
| Blocked(阻塞) | 处于 Open 且存在未关闭的前置依赖,附blocked_by列表 |
关键设计:状态是"计算"出来的,不是"存储"出来的。正如文档所述 "The status is COMPUTED from beads, not stored separately. If beads changes, status changes."——只要任一 Issue 关闭或依赖解除,下次执行status就会得到新结果。进度百分比为completed / total * 100;--json输出完整的SwarmStatus(含epic_id、epic_title、四组明细、progress_percent、各计数)。人类可读输出还贴心地在 Ready 为空时汇总"正在等待哪些前置任务"((none - waiting for ...))。
bd swarm validate:校验 Epic 是否适合并行执行
validate对 Epic 的结构做静态分析,判断其是否满足 swarm 执行条件。
bd swarm validate [epic-id] [flags]bd swarm validate gt-epic-123 # 校验 epic 结构 bd swarm validate gt-epic-123 --verbose # 输出详细 issue 图Flag
| Flag | 类型 | 默认值 | 说明 |
|---|---|---|---|
--verbose | bool | false | 在输出中附上详细 issue 依赖图(issues字段) |
五类结构检查
根据文档与detectStructuralIssues实现(cmd/bd/swarm.go),校验覆盖:
- 依赖方向检查:依赖应基于"需求"(requirement)而非"时间先后"(temporal)。实现采用标题启发式——若标题含
foundation/setup/base/core的基础性任务没有后继者,或含integration/final/test的收尾型任务没有前置依赖,则给出"依赖方向可能反转"的警告。 - 孤儿问题(roots with no dependents):找出没有前置依赖的根节点,多个根是正常的(它们构成并行起点)。
- 缺失依赖(leaves that should depend on something):找出没有后继的叶子节点,多个叶子可能意味着任务间缺少连接。
- 环检测(cycles):通过三色 DFS 检测依赖环,一旦发现即在
Errors中记录Dependency cycle detected involving: ...,并置Swarmable=false。 - 断连子图(disconnected subgraphs):从所有根节点出发 DFS 遍历,无法到达的节点判为断连,给出警告。
此外,若子任务依赖了 Epic 之外的 Issue 或external:外部引用,也会产生警告。
报告输出
validate报告以下指标(SwarmAnalysis,见 cmd/bd/swarm.go):
ready_fronts:就绪波次(可并行的任务浪潮),每波含wave编号、issues、titlesestimated_sessions:预估 worker 会话数(≈ 剩余未关闭任务数)max_parallelism:最大并行度(各波次任务数的最大值)warnings/errors:结构问题清单swarmable:是否存在错误(有环则不可 swarm)
人类可读输出按Wave 1 / Wave 2 ...逐波列出任务,并给出Estimated worker-sessions、Max parallelism、Total waves与最终结论Swarmable: YES/NO (fix errors first)。
Ready Front 的底层算法
computeReadyFronts(cmd/bd/swarm.go)采用Kahn 算法计算拓扑波次:先统计每个未关闭任务"未关闭前置依赖"的数量作为入度,入度为 0 的任务构成 Wave 0;处理完当前波后,将其后继的入度递减,减到 0 的任务进入下一波,直到全部排完。每波即一个可并行执行的"就绪前沿"。
一个值得注意的实现细节(对应 issue GH#4564):已关闭(Closed)的任务被排除在波次之外,也不再阻塞其后继——一个已关闭的依赖被视为已满足。由 swarm_ready_fronts_test.go 中的TestComputeReadyFrontsExcludesClosed与TestAnalyzeEpicForSwarmClosedCycleDoesNotSuppressOpenFronts可以验证:即使存在"closed-a ↔ open-b"这样的闭合-开启互环,只要环中一侧已关闭,环就不会被报告为结构性错误,也不会抑制其他开放子任务的就绪波次。
数据模型:依赖类型如何影响就绪计算
swarm 的就绪/阻塞判定完全建立在 Beads 依赖类型体系之上。DependencyType定义于 internal/types/types.go,其中与 swarm 相关的核心类型包括:
| 依赖类型 | 语义 |
|---|---|
blocks | 硬阻塞:前置不完成,后继不能开工 |
parent-child | 父子结构关系(Epic → 子任务) |
conditional-blocks | 条件阻塞 |
waits-for | 扇出门(等待动态子任务) |
relates-to | 松散知识图谱边(swarm 分子 → Epic 即用此类型) |
判定哪些依赖影响就绪计算的方法AffectsReadyWork(internal/types/types.go)只认可blocks、parent-child、conditional-blocks、waits-for四种;relates-to、related、replies-to等非阻塞边一律不计入就绪判定。因此 swarm 的波次计算只会被真正的阻塞依赖驱动,松散关联不会拖慢进度。在分析 Epic 时,源码还特别跳过子任务指向 Epic 自身的parent-child边(避免把父子结构误当阻塞),并且只统计 Epic 内部的依赖、对跨 Epic 依赖给出警告(cmd/bd/swarm.go)。
测试与验证
该功能具备完整的测试覆盖,可作为理解行为的补充证据:
- 单元测试cmd/bd/swarm_ready_fronts_test.go:用内存版
fakeSwarmStorage验证已关闭任务不进波次、闭环不抑制开放波次、MaxParallelism与EstimatedSessions的数值口径。 - 嵌入式集成测试cmd/bd/swarm_embedded_test.go:通过
bd graph create(一个 JSON plan 文件:1 个 epic + 3 个 task + 1 条blocks边)构造可 swarm 的 DAG,随后覆盖validate(含--verbose/--json)、create(含--coordinator、--force、重复创建报错、单任务自动包裹、JSON 字段)、status、list等全部路径;create_force与create_error_existing用例印证了"已有分子时未加--force会失败"的行为。 - 代理服务集成测试swarm_proxied_integration_test.go:覆盖 proxied-server 模式下
status/validate的代理执行路径。
端到端使用流程示例
结合上述命令,一个典型的 swarm 工作流如下:
- 规划:用
bd graph create(或bd epic)建立 Epic 及子任务,并通过bd dep添加blocks依赖,形成 DAG。 - 预检:
bd swarm validate gt-epic-123—— 查看波次划分与警告,修复环、断连等结构问题,直到Swarmable: YES。 - 创建:
bd swarm create gt-epic-123 --coordinator observer/witness—— 生成 swarm 分子,得到gt-swarm-xxx。 - 监控:
bd swarm list总览所有集群进度;bd swarm status gt-epic-123或bd swarm status gt-swarm-xxx查看四类状态明细。 - 迭代:协调 Agent 从 Ready 组领取任务、置为 in_progress 开工;任务关闭后
status自动反映新进度,后继任务转入 Ready。全程无需手工维护任何集群状态表——swarm 的一切状态都实时派生自底层 beads。
更完整的命令参考见 docs/cli-reference/swarm.md(由bd help --doc swarm自动生成)。
【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考