前言
dev-orchestra 1.2.0 可以把计划拆分成工作单元。互不依赖的工作单元各自在专用的 git worktree 中并行运行,完成一个就合并回工作树一个。从 v1.1.0 到 v1.2.1 的全部变更,整理在发布文章(英文)中。
上一篇试了为每个角色传递固定的指示。
平时,这些步骤都由编排器(Claude Code 等)自动完成。这次为了看清楚到底发生了什么,我手动把同样的命令一条一条地执行了一遍。
试用的环境如下。
- Windows 11
- dev-orchestra 1.2.1
- Claude Code 2.1.309(implementer 用的是 Claude 的 sonnet)
- Python 3.14.7
测试时,我把 DEV_ORCHESTRA_HOME 指向了与日常配置分开的文件夹,并在专门为此建的小仓库(textkit)中运行。
dev-orchestra 已在 GitHub 上开源(MIT 许可证)。如果你觉得有用,给个 Star 我会很高兴。
步骤
1. 在计划中写 ## Units
题材是一个计划:给名为 textkit 的小 Python 包添加 slugify(text) 和 word_count(text) 两个函数。两者在不同的文件里,所以可以并行实现。README 和 CHANGELOG 要写两者的结果,所以放到最后一起改。
在计划(plan.md)中写上 ## Units 标题和一个 yaml 代码块。
## Units
```yaml
units:
- name: slug
kind: feature
files: [textkit/slug.py, tests/test_slug.py]
depends_on: []
- name: count
kind: feature
files: [textkit/count.py, tests/test_count.py]
depends_on: []
- name: docs
kind: integration
files: [README.md, CHANGELOG.md]
depends_on: [slug, count]
```
### Unit: slug
1. Add `slugify(text)` in textkit/slug.py: lowercase, runs of non-alphanumerics become one `-`, strip `-` at both ends.
2. Add tests/test_slug.py.
- 写上
name、kind(feature、fix、refactor、docs、test、ci、integration)、files(要改的文件)和depends_on(必须先完成的工作单元) - 每个工作单元建一个
### Unit: <name>小节,写下该工作单元的步骤 - 像 CHANGELOG 这样大家都要改的文件,归到一个依赖其他所有工作单元的
integration工作单元里
实际上,architect 写计划时也会写这个代码块(当工作分布在不同文件,或计划超过 4 个步骤时)。这次是我手写的。
在
## Files to Modify下,路径要像`textkit/slug.py`这样用反引号括起来。我不加反引号时,units check输出了warning:,说这些文件不在 Files to Modify 中(不会被拒绝)。
2. 用 units check 确认能否运行
一开始,我把 README 同时放进了 slug 和 count 的 files。这种状态下执行 units check,会被拒绝。
$ dev-orchestra units check
.ai/workflows/demo/plan.md: the units cannot be run:
- slug and count may run in parallel but both list README.md
退出码是 2。可能并行运行的两个工作单元列出了同一个文件,合并时就会冲突,所以它在运行之前就拦下来。把 README 只放到 docs 工作单元后,就通过了。
$ dev-orchestra units check
3 units in 2 waves (implementation.max_parallel: 2):
wave 1: slug, count
wave 2: docs
计划是 slug 和 count 在第 1 波并行运行,docs 在第 2 波运行。同时运行的数量由 implementation.max_parallel(默认 2,最多 8)决定。
3. 设置为合并后再运行工作单元的测试
在这次的环境中,implementer 的 Claude 一要执行 shell 命令就会等待批准,所以跑不了测试(dev-orchestra 用 --permission-mode acceptEdits 启动 Claude 的 implementer,文件编辑可以通过,但 shell 命令需要批准)。
于是,我在仓库的 .dev-orchestra.yaml 中写上了 1.2.1 新增的 implementation.unit_tests: after_merge。
version: 1
implementation:
unit_tests: after_merge
这样,各工作单元只负责写代码和测试,测试在全部合并之后只运行一次。这是为测试共用数据库或端口、并行运行就会冲突的项目准备的设置。
第一次我没加这个设置就运行了。结果其中一个工作单元的工具记录里一次
Write都没有,并没有写文件,报告里却写着“已创建文件”。units merge输出了merged slug: 0 file(s),所以看合并的文件数就能发现。
4. 批准计划,并行运行两个工作单元
implementer 只在已批准的计划上运行。用 design approve 记录批准(平时是编排器把计划给你看,只有你说“是”时才执行)。
$ dev-orchestra design approve
approved .ai/workflows/units/plan.md (sha256 f108913500da) for workflow units
用 run implementer --unit <name> --detach 在后台逐个启动工作单元。请求文件(implement-request.md)所有工作单元共用一个,工作单元的名称、文件和计划中的小节由 CLI 加在前面。
$ dev-orchestra run implementer --unit slug --prompt-file .ai/workflows/units/execution/implement-request.md --detach
started implementer as job implementer-20261025-165514-ee46f2
$ dev-orchestra run implementer --unit count --prompt-file .ai/workflows/units/execution/implement-request.md --detach
started implementer as job implementer-20261025-165515-d7c62b
看 units status,两个都是 running,各自在不同的 worktree 中。worktree 建在仓库旁边的 textkit.units 文件夹里(路径部分省略)。
$ dev-orchestra units status
slug feature running job implementer-20261025-165514-ee46f2 base d736c6342cc7 ...\textkit.units\d736c634-slug
count feature running job implementer-20261025-165515-d7c62b base daf7aed8edd8 ...\textkit.units\daf7aed8-count
docs integration pending job - base - -
Ready to start: none
Unit tests: after_merge (units skip their tests; run them once on the merged tree)
传给工作单元的提示词开头,带有这样的头部(第一次尝试时的内容)。
# Work unit: slug (feature)
This run implements one unit of the plan, and only that unit.
Its files: textkit/slug.py, tests/test_slug.py
5. 用 jobs wait --any 先收下完成的那个
从 1.2.0 起,jobs wait 可以接收多个任务 id。加上 --any,只要有任意一个完成就会返回(输出为节选)。
$ dev-orchestra jobs wait implementer-20261025-165514-ee46f2 implementer-20261025-165515-d7c62b --any
implementer-20261025-165514-ee46f2 RUNNING
unit: slug (...\textkit.units\d736c634-slug)
elapsed: 0m30s
activity: 9 tool uses, context 51,040 tokens
+00:15 Write textkit/slug.py
+00:17 Write tests/test_slug.py
...
implementer-20261025-165515-d7c62b SUCCEEDED
unit: count (...\textkit.units\daf7aed8-count)
activity: 8 tool uses, context 49,706 tokens
+00:15 Write textkit/count.py
+00:17 Write tests/test_count.py
...
count 先完成,slug 还在运行。两个都是 30 秒左右就完成的小任务。
6. 用 units merge 合并回工作树
完成的工作单元用 units merge 合并回工作树。它按文件合并,不会动 index、HEAD 和分支。
$ dev-orchestra units merge count
merged count: 2 file(s)
等 slug 也完成后,同样合并。
$ dev-orchestra units merge slug
merged slug: 2 file(s)
$ dev-orchestra units status
slug feature merged job implementer-20261025-165514-ee46f2 base d736c6342cc7 -
count feature merged job implementer-20261025-165515-d7c62b base daf7aed8edd8 -
docs integration pending job - base - -
Ready to start: docs
已合并的工作单元的 worktree 被清理掉了。工作树中新增了 4 个文件。
$ git status --short
?? tests/test_count.py
?? tests/test_slug.py
?? textkit/count.py
?? textkit/slug.py
7. 整合的工作单元在原地运行
剩下的 docs 没有可以与之并行的工作单元。这种情况下不建 worktree,而是直接在工作树中运行(我没加 --detach)。
$ dev-orchestra run implementer --unit docs --prompt-file .ai/workflows/units/execution/implement-request.md
docs ユニットを実装しました。変更したのは README.md と CHANGELOG.md だけです。
...
$ dev-orchestra units status
slug feature merged ...
count feature merged ...
docs integration merged job - base - in place
Ready to start: none
(implementer 的报告是日语,因为我的环境要求用日语回复。内容是“只修改了 README.md 和 CHANGELOG.md”。)在原地运行的工作单元,完成时就算已合并。README 中加上了两个函数的说明,CHANGELOG 中加上了 ### Added。
8. 在合并后的工作树上运行测试
因为是 after_merge,最后只运行一次测试。
$ python -m unittest
.........
----------------------------------------------------------------------
Ran 9 tests in 0.000s
OK
看 budget show,即使运行了 3 个工作单元,implementer 的尝试次数也只用了 1 次(输出为节选)。
$ dev-orchestra budget show
implementer 1/5 used
delegated runs 3/40 used
implementer pass open: slug, count, docs run (plan f108913500da)
同一个计划的工作单元共用 1 次尝试。只有重新运行同一个工作单元时,才会再用 1 次。运行次数本身(delegated runs)则算作 3 次。
9. 发生冲突时(这次没有发生)
这次合并没有冲突。根据参考文档,例如在工作单元运行期间工作树中的同一文件发生了变化,就会冲突,然后:
units merge以退出码 7 结束,并在.ai/execution/units/<name>-conflicts.md留下说明- 编排器让 review_fixer 根据这份说明解决冲突
- 用
units merge <name> --resolved记录为已解决
我没有试过冲突,所以这里只介绍它的机制。
总结
- 在计划中写下
## Units的yaml,就能把实现拆分成工作单元 units check会在运行之前拒绝文件重叠的工作单元,并显示各波次- 互不依赖的工作单元在各自独立的 git worktree 中并行运行,再用
units merge按文件合并回工作树,不会动 index 和分支 - 没有可以并行的工作单元(这次是
integration)会在原地运行 - 用
jobs wait --any,可以先收下完成的那个 - 同一个计划的工作单元共用 1 次 implementer 的尝试
- 如果测试不能并行运行,就用
implementation.unit_tests: after_merge。也要留意units merge输出的文件数
下一篇测一测 dev-orchestra 的耗时,以及不同评审人数下的指摘数。
GitHub: istb16/dev-orchestra(给个 Star 就是对我最大的鼓励)
想一次看全本系列,请看“dev-orchestra”文章列表。
相关文章
我测了一下 dev-orchestra:每个请求的耗时,以及不同审查者人数下的问题数
我用 dev-orchestra 1.2.1 提了一个小功能的请求,测了耗时(不算等待我批准的时间,约 6 分钟),以及审查者为 1 人、2 人、4 人时提出和采纳的问题数。审查者越多,可采纳的问题也越多,但多出来的都是关于测试的问题。
试着给 dev-orchestra 的每个角色交代固定的指示
我试用了 dev-orchestra 1.2.1 加入的 instructions。把给 implementer 和审查者的固定指示写在仓库里,它们就会进入每一次的提示词。本文用实际的输出确认它们如何显示、放在哪里,以及修改指示的变更会被如何对待。
试着更新 dev-orchestra(Claude Code / Codex / Antigravity)
我在 Claude Code、Codex 和 Antigravity 中,分别实际把 dev-orchestra 从 1.0.0 更新到了 1.1.1。在 Claude Code 中,只执行 claude plugin update 并不会更新,需要先更新 marketplace。本文整理了各 CLI 的更新步骤、更新之后要确认的事,以及卸载方法。