[AGENTS.md] 並列AI開発に耐えるリポジトリの作り方

2026/07/19

AGENTS.md
生成AI
Git

こんにちは。

worktree・Orcaと続いた話の、3本目にして本命です。

前々回で git worktree を、前回でその管理ツールであるOrcaを紹介しました。道具は揃いました。これでAIを並列に走らせ放題……かと思いきや、普通に崩れます。

私が実際に踏んだやつを1つ挙げます。2つのworktreeで別々の機能をAIに書かせていて、両方がDBにカラムを足しました。それぞれのブランチでは何の問題もなくテストが通ります。で、片方をマージして、もう片方をrebaseした瞬間に schema.rb がコンフリクトします。マイグレーションのタイムスタンプもズレています。AIは2体とも正しく仕事をしたのに、統合したら壊れました。

これ、worktreeのせいでもOrcaのせいでもありません。リポジトリ側が並列に耐える作りになっていなかっただけです。

今回は、私たちがAGENTS.mdとリポジトリ構成でどう対処しているかを書きます。

結論から言うと

並列AI開発で一番効くのは、モデルでもツールでもなく「コンフリクトしない設計」と「AIが自己完結できるルール」です。

私たちのAGENTS.mdは、元々は普通の開発ルールとして書き始めたものでした。でも、worktreeで並列に走らせるようになってから読み返すと、効いているルールと効いていないルールがはっきり分かれていることに気づきました。今回はその「効いている方」を紹介します。

なお、この記事に出てくるAGENTS.mdの引用は業務で使っている実物ですが、案件が特定できる部分は伏せています。うちのリポジトリはRails系とNext.jsのpnpmモノレポ系が混在していて、スタックはバラバラです。それでもAGENTS.mdの骨格はほぼ同じになりました。技術スタックが違ってもルールは共通化できる、というのが個人的な発見でした。


1. 宣言的スキーマにする(これが最重要)

冒頭の事故の答えがこれです。私たちのRailsリポジトリでは、マイグレーションを使っていません。

AGENTS.md
## 3. DB スキーマ変更は ridgepole で行う

このリポジトリはマイグレーションファイルではなく **ridgepole** でスキーマ管理している。

- スキーマ定義は `db/schema/{primary,cache,queue}/Schemafile`
- 差分確認: `bin/rails ridgepole:dry-run DATABASE=primary`
- 適用: `bin/rails ridgepole:apply DATABASE=primary`
- `rails g migration` / `rails db:migrate` 前提の変更は行わない。

実際、うちのRailsリポジトリには db/migrate ディレクトリが存在しません。あるのは db/schema/primary/Schemafile と、テーブルごとの .schema ファイルだけです。

なぜこれが並列に効くのか。

マイグレーション方式だと、スキーマ変更は「20260718123456_add_foo_to_bars.rb という時刻の名前が付いたファイル」+「schema.rb という全テーブルが1ファイルに詰まった生成物」の組み合わせになります。並列でやると、

  • タイムスタンプが実行順に依存する(後からマージした方が先の時刻、みたいな状態が起きる)
  • schema.rb は全テーブルが1ファイルなので、無関係なテーブルの変更同士でもコンフリクトする
  • しかも生成物なので、手でコンフリクト解決すると壊れる

Ridgepoleの宣言的スキーマだと、「あるべき姿」をテーブル単位のファイルに書くだけです。時刻の概念がないので順序で揉めません。ファイルがテーブルごとに分かれているので、別テーブルを触っている限りコンフリクトしません。同じテーブルの別カラムなら、普通のコード同様に素直に3-wayマージできます。

正直、Ridgepoleを入れた当初は並列AIのことなんて1ミリも考えていませんでした(単にスキーマ管理が楽だから、でした)。それが今になって一番効いているので、人生分からないものです。

ポイントは Ridgepole そのものではなく 「順序に依存する生成物を、宣言的な定義に置き換える」 という発想です。Prismaのschema.prismaでも同じ話ですし、Railsじゃなくても考え方は使い回せると思います。


2. ブランチ名を issue-<番号> に固定する

地味ですが、めちゃくちゃ効いています。

AGENTS.md
- Issue 対応のブランチ名は `issue-<番号>` に固定する(例: `issue-183`)。個人名などの prefix は付けない。

なぜ効くか。worktree名 = ブランチ名 = issue番号 = Orcaのメタデータが、全部1対1で揃うからです。

GitHub issue #357
  → ブランチ issue-357
    → worktree ~/orca/workspaces/product-a/issue-357
      → Orca の linkedIssue: 357

前回の記事で「orca worktree ps で全体が見える」と書きましたが、あれが機能するのはそもそも名前が揃っているからです。ここが kenji/fix-status とか feature/new-ui みたいにバラバラだと、一覧を見ても結局issueを探しに行くことになります。

面白いのは、**「既存ブランチに個人名prefixが残っていても、それを前例にするな」**とわざわざ書いてあるところです。これは完全にAI向けの記述で、放っておくとAIは既存ブランチを見て「あ、この命名でいいのね」と真似するんですよね。AIは規約ドキュメントより実物のコードを信じるので、移行期には明示的に否定しておく必要がありました。


3. 「git stashを使うな、worktreeを使え」と明記する

これはもう、そのまんまです。

AGENTS.md
## 6. worktreeで複数の修正を並行して進める場合、git stashは使わない

複数の修正を同時並行で進める際は git worktree を使い、作業ツリーを分離すること。
`git stash` は同一の作業ツリーで一時退避する手段であり、並行作業と相性が悪く、
退避漏れ・取り違えの原因になるため使用しない。

前々回の記事で「AIが読んでいるファイルが知らないうちに書き換わるのは事故」と書きましたが、その事故をAI自身が起こすことがあります。「別のことを試したいので一旦stashしますね」と気を利かせてくれるんです。悪気はないんですが、隣のworktreeで動いている別のAIからしたら、共有の .git にstashが積まれることになります。

なので禁止と書いてあります。AIに「やるな」を伝える唯一の方法は、書いておくことです。 当たり前ですが、書いていないことは守られません。


4. テストは「リポジトリ全体で」回させる

AGENTS.md
一部のパッケージ/アプリだけを変更した場合でも、リポジトリ全体で実行する
`pnpm --filter <name> test` 等での部分実行だけで済ませない)。
他のアプリ・パッケージへの意図しない影響(型エラー、共有パッケージの
破壊的変更など)を見逃さないため。

一見、並列と関係なさそうに見えますよね。むしろ全体テストは遅いので、並列でガンガン回したいなら部分実行の方が良さそうに思えます。

でも逆でした。並列AIは、自分のworktreeの外を一切知りません。 worktree Aのエージェントは、worktree Bで共有パッケージのインターフェースが変わったことを知る術がありません。各エージェントが自分の担当範囲だけテストして「通りました!」と報告してくると、統合した瞬間に全部落ちます。

全体テストは、その最後の砦です。時間はかかりますが、待っているのはAIであって私ではないので、正直あまり困りません。ここは並列AI開発ならではの発想の転換だったなと思います。


5. 影響範囲の「横展開」を執拗に書く

これはAGENTS.mdの中でも一番文量を割いているルールです。

AGENTS.md
## 2. テスト・修正の追加漏れを作らない(横展開の徹底)

- 新しい値(例: enum 値・ステータス)を追加したら、`grep -rl "<既存の類似の値>" app/`
  でその値を参照している全ファイル(ViewComponent、Haml ビュー、Worker、Mailer、
  ransack 検索条件、seed 等)を洗い出し、それぞれ更新・テスト追加されているか確認する。
- 「同じチェックロジック(権限判定、公開/非公開の出し分け等)が複数ファイルに
  重複実装されている」ケースに注意する。1箇所を直しても、コピーされた別の実装が
  古いままだと機能しない。

grep -rl で洗い出せ、という具体的な手順まで書いているのがポイントです。「影響範囲を確認すること」だけだと、AIは確認したつもりで終わります。

なぜ並列で効くかというと、コンテキストが分断されているAIほど「片方だけ直す」をやりがちだからです。人間なら「あ、admin側にも同じのあったな」と記憶で気づけますが、worktreeに閉じたAIにはその記憶がありません。だから手順として外部化する。AIの記憶力に期待せず、grepさせる。 これに尽きます。


6. 大きい変更は、先に docs/ へ計画を書かせる

AGENTS.md
## 3. 大きめの変更は、まずドキュメント(差分分析・フェーズ計画)を作ってから着手する

1. 現状と目指す姿の差分を整理したドキュメントを `docs/` に作成する。
2. ドキュメントの中で、フェーズ分割と各フェーズの依存関係を明示する。
3. 設計判断が必要な箇所(要判断ポイント)は実装前にユーザーに確認し、
   決定した内容と理由をドキュメントに書き戻す。
4. 各フェーズは個別のブランチ・PRに分割して着手し、完了したフェーズは
   ドキュメントのチェックリストを更新する。

これ、実は並列化の前工程そのものです。

「フェーズ分割と依存関係を明示する」「各フェーズを個別のブランチ・PRに分割する」——これをやった時点で、どこを並列に走らせられるかが確定します。 依存のないフェーズ同士は、そのまま別worktreeに割り当てられます。

私は以前これを「丁寧な進め方のためのルール」だと思っていました。実際は「並列実行計画を作らせるルール」だったんですね。気づいたときは、ちょっと感動しました。


7. PRの自動レビューを、AIに回し切らせる

前回の記事の最後に「結局、人間がボトルネックになる」と書きました。並列度を上げるほどレビュー待ちが溜まる、と。

そこへの現時点の回答がこれです。

AGENTS.md
## 7. PR作成後は自動レビューの結果を待って対応する

このリポジトリには、PR作成・更新時に自動でコードレビューを行う
GitHub Action(`.github/workflows/claude-pr-review.yml`)が設定されている。
PRを作成(またはpush)したら、以下のループを完了するまで対応を続けること。

1. PRを作成・updateしたら、自動レビューのワークフローが完了し
   レビューコメントが投稿されるまで待機する。
2. 投稿されたレビューコメントを1件ずつ確認し、対応方針を決める。
3. 修正が必要な指摘は実装してpushする。
4. push後、再度レビューが投稿されるので、コメントが解消されるか
   新たな指摘が無くなるまで1〜3を繰り返す。

ポイントは「ループを完了するまで対応を続けること」です。PRを出して終わりではなく、レビューが静かになるまでAIが自分で回す。私のところにPRが来る頃には、機械的な指摘は一通り潰れています。

これで人間のボトルネックが解消したかというと、完全にはしていません。 設計判断や「そもそもこの仕様でいいんだっけ」は結局私が見ます。ただ、レビューの1周目をAI同士でやってくれるだけで、私が見る量はかなり減りました。詳しくは以前Claude Code × GitHub Actionsの記事にも書いています。


8. コマンドを bin/ に寄せる

細かいですが、地味に効きます。あるRailsリポジトリの bin/ はこうなっています。

bin/brakeman  bin/bundle  bin/codex-setup  bin/dev  bin/rails
bin/rake  bin/rspec  bin/rubocop  ...

AGENTS.mdには bin/rspec と書いてあるだけです。bundle exec rspec でも docker compose exec app bundle exec rspec でもなく、bin/rspec

worktreeを増やすと、ディレクトリの絶対パスは全部変わります。でも bin/ 相対なら、どのworktreeでも同じコマンドが通ります。 AGENTS.mdに書いたコマンドが、コピペで全worktreeで動く。これだけです。これだけですが、書き換えが要らないというのは並列だと効きます。

ちなみに bin/codex-setup があるあたり、エージェント用のセットアップも同じ場所に寄せているのが分かると思います。前回書いたOrcaのセットアップフックとも、素直に噛み合います。


まとめ:効いているルールの共通点

改めて並べると、効いているルールには2つの軸しかありませんでした。

軸1: コンフリクトしない設計にする

やったこと 効く理由
Ridgepoleで宣言的スキーマ 順序依存の生成物を消す。テーブル単位でファイルが分かれる
ブランチ名を issue-<番号> に固定 worktree/issue/ブランチが1対1で揃い、迷子が消える
ViewComponentなど1機能1ディレクトリ 別機能を触る限りファイルが衝突しない
名前空間の分離 疎結合なほど並列で踏み合わない

軸2: AIが自己完結できるようにする

やったこと 効く理由
git stash 禁止を明記 書いていないことは守られない
リポジトリ全体でテスト worktreeの外を知らないAIの最後の砦
grep -rl で横展開しろと手順で書く AIの記憶力に期待しない
docs/ にフェーズ計画 それがそのまま並列実行計画になる
PR自動レビューをループさせる 人間のレビュー負荷を1周ぶん減らす
コマンドを bin/ に寄せる どのworktreeでも同じコマンドが通る

3本続けて書いてきて、結局これが言いたかったことなのですが——AI駆動開発の話題は「どのモデルが賢いか」「どのツールが速いか」に寄りがちです。でも、実際に効いてくるのは足回りでした。 worktreeという地味なGit機能、Orcaという地味な管理ツール、そしてAGENTS.mdという地味なテキストファイル。派手さはゼロですが、ここが整っていないと、どんなに賢いモデルを持ってきても統合時に崩れます。

そして正直に言うと、うちのAGENTS.mdも、最初から並列を狙って書いたものではありません。 普通の開発ルールとして書いたものが、たまたま並列に効いていた。だから、いま手元のAGENTS.mdを「並列に耐えるか?」という目で読み返してみるのが、一番安上がりな第一歩だと思います。

まずは1つだけ。grep -rl で横展開しろ、を追記してみてください。 うちで一番費用対効果が高かったのはこれです。

3回にわたる長い話にお付き合いいただき、ありがとうございました。同じように並列AI開発でハマっている方の参考になれば幸いです!それではまた!

Related Posts

[Git] AI駆動開発で必須の git worktree、使えてますか?

[Git] AI駆動開発で必須の git worktree、使えてますか?

[Orca] worktreeを増やしすぎて破綻した私を救ったツール

[Orca] worktreeを増やしすぎて破綻した私を救ったツール

[生成AI] 2025/10 中旬時点での Spec Driven バイブコーディングフローを整理してみた

[生成AI] 2025/10 中旬時点での Spec Driven バイブコーディングフローを整理してみた