github / git / ai-agent
GitHub Projects・Issues・PRと独自.teamで複数AIエージェントを調整する
GitHub標準機能で作業ライフサイクルを管理しながら、実装中のleaseとパス競合だけを独自の.teamで補う、複数AIエージェント向けのタスク運用を整理します。
- 起票日
- 2026-08-22
- 更新日
- 2026-09-05
- 対象
- GitHub Projects / GitHub Issues / GitHub Pull Requests
概要
運用変更(2026-09-05): CompanyではIssueを任意とし、共有レジストリ・lease・
task:*による管理を廃止しました。この記事は旧方式の設計記録です。以下の手順やコード例は現行Companyの作業手順ではありません。
複数のAIエージェントへ開発作業を任せると、通常のタスク管理だけでは扱いにくい競合が発生します。二つのエージェントが同じファイルを編集したり、期限切れの作業を別のエージェントが無断で引き継いだり、異なるブランチのPRを同じIssueへ関連付けたりする問題です。
一方、この問題を解決するために独自のタスク管理システムを作り込みすぎると、GitHub Projects、Issues、Pull Requestsと同じ進捗を二重に管理することになります。
この記事では、GitHub標準機能を人間向けの作業ライフサイクルの正本として使いながら、GitHubが直接提供しない実装中のleaseと作業範囲の排他制御だけを、専用ブランチ上の.teamで補う設計を説明します。
結論
- GitHub Projectは、優先度と
Open、In Review、Doneの作業ライフサイクルを一覧する場所にします。 - Issueは、背景、目的、完了条件、対象外、変更可能なパスを記載する作業契約にします。
- Pull Requestは、実装差分、レビュー、CI、マージ状態の正本にします。
- 独自の
.teamは、owner、session、lease、branch、占有パス、PRの同一性確認に必要な情報だけを保持します。 - 実装中かどうかは
.teamのactive leaseで判定し、ProjectのStatusやdraft-pr、ready-prを複製しません。 - GitHub Projectsの組み込みworkflowで扱える遷移はGitHubへ任せ、
task:startではProjectを操作しません。
一つのシステムにすべてを持たせない
Project、Issue、PR、独自レジストリには、それぞれ異なる強みがあります。
| 情報 | 正本 | 理由 |
|---|---|---|
| 優先度、担当予定、作業工程 | GitHub Project | ボードやテーブルで人間が確認しやすい |
| 背景、目的、完了条件、対象外 | GitHub Issue | 会話と意思決定を作業単位で残せる |
| 実装差分、レビュー、CI、マージ | Pull Request | Gitのrevisionとレビュー状態に直接結び付く |
| owner、session、lease | .team | 複数エージェントの一時的な所有権を機械判定できる |
| allowed paths、共有資源 | .team | 作業開始前とcommit前に競合を拒否できる |
この分担では、ProjectのStatusが人間向けの作業ライフサイクルの正本です。実装中のownerとleaseは.team、PRがDraftかReadyか、merge済みかはPR自身が正本です。.teamは開発作業の安全装置であり、もう一つのProjectにはしません。
推奨する状態遷移
Projectには、次の三つのStatusを用意します。
| Status | 意味 |
|---|---|
Open | Issueがopenで、レビュー待ちのPRがまだリンクされていない |
In Review | PRがIssueへリンクされ、レビュー可能 |
Done | Issueがcloseされた、またはPRがmergeされた |
標準フローは次のようになります。
Issue created
-> Project: Open
-> task:start: leaseとpathsをclaim
ProjectはOpenのまま、実装中は.teamで確認
-> PR created with "Closes #123"
-> Project: In Review
-> PR merged / Issue closed
-> Project: Done
-> task:finish: main同期とlease解放
Openは未着手と実装中を意図的に区別しません。実装中かどうかは.teamのactive recordまたはtask:statusで確認します。また、task:finishでProjectをDoneへするのではなく、PRのmergeとIssueのcloseをGitHubが扱い、ProjectのworkflowがDoneへ反映します。task:finishはローカルのmain同期と一時的なclaimの解放に集中します。
Issueを作業契約にする
Issue本文には、少なくとも背景、目的、完了条件、対象外を記載します。エージェントが変更できる範囲も、機械が読める形式で埋め込みます。
## タスク契約
<!-- task-contract
allowed_paths:
- apps/web/content/knowledge/**
- tools/task-workflow/**
shared_resources:
- apps/web/pnpm-lock.yaml
required_checks:
- format:check
- typecheck
branch_slug: project-team-hybrid
-->
allowed_pathsは通常の変更範囲、shared_resourcesはlockfileのように複数領域から触れる可能性がある資源です。別のactive taskと重なる場合、実装を始める前にIssueを分割するか、占有範囲を調整します。
.teamはleaseと競合防止に限定する
GitHub Projectは進捗の可視化には向いていますが、「このsessionが4時間だけこのディレクトリを占有する」といったCAS付きのleaseや、パス単位の競合拒否を標準では提供しません。
そこで、専用ブランチに.team/index.ymlとactive recordを置きます。拡張子はYAMLでも、処理を単純にするため内容をJSON互換にして構いません。
{
"schema_version": 1,
"issue": 123,
"owner": {
"kind": "agent",
"name": "implementation-agent",
"session_id": "session-uuid"
},
"branch": "codex/issue-123-project-team-hybrid",
"base_branch": "main",
"base_sha": "commit-sha",
"allowed_paths": ["tools/task-workflow/**"],
"shared_resources": [],
"started_at": "2026-08-22T00:00:00.000Z",
"heartbeat_at": "2026-08-22T01:00:00.000Z",
"lease_expires_at": "2026-08-22T05:00:00.000Z",
"pr": 456,
"pr_head_sha": "commit-sha"
}
このrecordにProject StatusやPRのDraft・Ready状態は保存しません。prとpr_head_shaは進捗表示ではなく、登録されたPRが本当に対象ブランチのrevisionかを完了時まで検証するために使います。
共有ブランチの更新にはfast-forwardだけを許可し、読み取ったhead SHAを期待値としてrefを更新します。別のエージェントが先に更新した場合はforceせず、最新状態を読み直して競合判定をやり直します。
GitHub Projectsのworkflowへ任せる範囲
GitHub Projectsの組み込みworkflowを使うと、次の遷移を独自コードなしで扱えます。
| Trigger | Action |
|---|---|
| repositoryのopen Issueが作成・更新された | Projectへ自動追加 |
| itemがProjectへ追加された | Openへ設定 |
| PRがIssueへリンクされた | In Reviewへ設定 |
| itemがcloseされた | Doneへ設定 |
| PRがmergeされた | Doneへ設定 |
| itemがreopenされた | Openへ設定 |
PR本文にはCloses #123のようなclosing keywordを記載します。これによりPRとIssueの関係が明示され、既定ブランチへmergeされたときにIssueが自動でcloseされます。
task:startとOpenの役割分担
task:startは、作業ツリーのclean確認、Issue契約の解析、他のactive taskとの競合確認、leaseの取得、タスクブランチの準備を行います。成功してもProjectは操作せず、PRがIssueへリンクされるまでStatusはOpenのままです。
作業開始をProjectへ重複記録しないため、ブラウザー操作やProject API用のtoken、Project ID、field ID、option IDは必要ありません。Projectはレビュー開始と完了の境界を人間へ示し、.teamは実装中のowner、session、leaseを機械へ示します。この粒度の違いを意図的に保つことで、表示とclaimの不整合を避けます。
task:link-prは検証に集中する
PR作成後のコマンドは、次の一致だけを確認します。
- PRのhead repositoryが対象repositoryであること。
- PRのhead branchがactive recordのbranchであること。
- PRのbase branchが予定したbase branchであること。
- PRのhead SHAがlocalとremoteのタスクブランチに一致すること。
一致したPR番号とhead SHAをrecordへ保存します。DraftかReadyかはGitHub PRから確認できるため、独自レジストリへ保存しません。PRへcommitを追加した場合は再度検証し、保存したhead SHAを更新します。
失敗と再開を先に設計する
複数エージェント運用では、正常系より中断時の扱いが重要です。
- lease期限切れを自動取得せず、Issue、branch、PR、最終heartbeatを確認してから明示的にtakeoverします。
- 共有ブランチのref更新が競合したら、force pushせず最新状態から再試行します。
- PR merge後にhead branchが削除されても、保存したPR head SHAとローカルrevisionが一致するときだけ完了を許可します。
- abort時は理由をIssueへ記録してからclaimを解放します。
- ProjectのStatusだけを見てファイル所有権を判断しません。
.teamだけを見て製品の進捗を報告しません。
段階的に導入する
既存のIssue・PR運用へ追加する場合は、一度にすべてを自動化しない方が安全です。
- Projectへ
Open、In Review、Doneを用意します。 - 対象repositoryのopen IssueをProjectへ自動追加し、追加時とreopen時は
Openにします。 - PRリンク時は
In Review、closeまたはmerge時はDoneへ遷移させます。 .teamへleaseと作業範囲の排他制御を追加し、task:startでclaimします。- 独自レジストリからProject StatusやDraft・Readyなどの重複状態を削除します。
task:link-prをPRとbranch revisionの検証へ縮小します。task:finishをmerge確認、main同期、lease解放へ縮小します。
この順序なら、各段階でGitHub上の表示と実際の作業を比較でき、問題があれば小さく戻せます。
注意点
.teamはGitHubの標準機能ではなく、複数エージェント向けの補助レジストリです。単独開発や競合の少ないチームでは不要な場合があります。Openだけでは未着手と実装中を区別できません。現在のclaimは.teamまたはtask:statusで確認します。- leaseがあるだけで、OS上のファイルロックやGitの競合がなくなるわけではありません。commit前にも変更パスを検査します。
- Projectの自動追加は、workflowを有効にした後の新規・更新itemが対象です。既存itemは別途追加が必要になる場合があります。
- closing keywordは、対象PRがrepositoryの既定ブランチへmergeされたときにIssueをcloseします。
- Projectのfieldやworkflowは変更できるため、運用文書と実際の設定を定期的に照合します。