1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

dev-orchestra の作業単位で、計画を分けて並べて実装してみた

1
Last updated at Posted at 2026-10-27

はじめに

dev-orchestra 1.2.0 で、計画を作業単位に分けて実装できるようになりました。互いに関係しない作業単位は、それぞれ専用の git worktree で並べて走り、終わったものから作業ツリーへマージされます。v1.1.0 から v1.2.1 までの変更全体は、リリースの記事にまとめています。

前回は、役割ごとに決まった指示を渡す機能を試しました。

ふだんは、オーケストレーター(Claude Code など)がこの手順をすべて自動で進めます。今回は何が起きているのかを見るために、同じコマンドを手で 1 つずつ実行しました。

試した環境です。

  • 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 ライセンス)。役に立ちそうと思ったら、スターを付けてもらえるとうれしいです。

→ github.com/istb16/dev-orchestra

手順

1. 計画に ## Units を書く

題材は、textkit という小さな Python のパッケージに、slugify(text) と word_count(text) の 2 つの関数を足す計画です。2 つは別々のファイルなので並べて作れます。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 の作業単位 1 つにまとめる

実際には architect が計画を書くときに、このブロックも書きます(ファイルが分かれる作業か、手順が 4 つを超える計画のとき)。今回は手で書きました。

## Files to Modify には、パスを `textkit/slug.py` のようにバッククォートで囲んで並べます。囲まずに書いたら、units check が「Files to Modify にない」という warning: を出しました(拒否はされません)。

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 です。並んで走りうる 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 がシェルのコマンドを実行しようとすると承認待ちになり、テストを流せませんでした(dev-orchestra は Claude の implementer を --permission-mode acceptEdits で起動するので、ファイルの編集は通りますが、シェルのコマンドは承認が要ります)。

そこで、1.2.1 で入った implementation.unit_tests: after_merge をリポジトリの .dev-orchestra.yaml に書きました。

version: 1
implementation:
  unit_tests: after_merge

こうすると、各作業単位はコードとテストを書くだけにし、テストはすべてをマージしたあとに 1 回だけ流します。テスト用のデータベースやポートを共有していて、並べて流すとぶつかるプロジェクト向けの設定です。

最初はこの設定なしで走らせました。すると片方の作業単位は、ツールの記録に Write が 1 度もなく、ファイルを書いていなかったのに、報告では「ファイルを作った」と書いていました。units merge は merged slug: 0 file(s) と出したので、マージしたファイルの数を見れば気づけます。

4. 計画を承認して、2 つの作業単位を並べて走らせる

implementer は、承認された計画でないと走りません。design approve で承認を記録します(ふだんはオーケストレーターがあなたに計画を見せ、あなたが「はい」と言ったときだけ実行します)。

$ dev-orchestra design approve
approved .ai/workflows/units/plan.md (sha256 f108913500da) for workflow units

run implementer --unit <name> --detach で、作業単位を 1 つずつ裏で走らせます。依頼のファイル(implement-request.md)は全作業単位で 1 つで、作業単位の名前・ファイル・計画の節は 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 を見ると、2 つが 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 を付けると、どれか 1 つが終わった時点で戻ります(出力は抜粋)。

$ 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 はまだ走っています。2 つとも 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

その場で走った作業単位は、終わった時点でマージ済みです。README には 2 つの関数の説明が、CHANGELOG には ### Added が足されていました。

8. マージしたツリーでテストを流す

after_merge なので、最後にテストを 1 回だけ流します。

$ 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 回分け合います。同じ作業単位をやり直したときだけ、もう 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 の試行を 1 回分け合う
  • テストを並べて流せないなら implementation.unit_tests: after_merge。units merge が出すファイルの数も見ておく

次回は、dev-orchestra の所要時間と、レビュアーの人数ごとの指摘数を測ります。

GitHub: istb16/dev-orchestra(スターを付けてもらえると励みになります)

連載の回をまとめて見る場合は「dev-orchestra」の一覧からどうぞ。

この記事は tk3.biz のブログ からの転載です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?