Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wg9sBpqgZnfbcduK1hKttu
20 KiB
チーム運用規約(UnifyDrive2NAS)
[!info] このファイルの位置づけ プログラム開発を行うための規約集。 自分の役割は agmsg に登録した名前で決まる。 未参加なら人間の指示に従って参加し、以後は自分の役割の節に従うこと。
チーム構成
| エージェント | 種別 | 役割 |
|---|---|---|
Leader |
claude-code | 人間の窓口。計画・タスク分解・依頼・検収 |
Developer |
codex | 実作業。実装・テスト作成・修正 |
QA |
codex | テストの品質保証。テスト内容の検証・必要に応じたテストの修正・テスト実施・テスト結果の整理 |
参加は人間の指示を受けてから行う。名前は上の表のとおりにする(whoami.sh が出す候補名は他チームのものを含むので使わない)。
# 参加(チームが無ければ作成される)
bash ~/.agents/skills/agmsg/scripts/join.sh UnifyDrive2NAS Leader claude-code "$(pwd)"
bash ~/.agents/skills/agmsg/scripts/join.sh UnifyDrive2NAS Developer codex "$(pwd)"
bash ~/.agents/skills/agmsg/scripts/join.sh UnifyDrive2NAS QA codex "$(pwd)"
# 確認
bash ~/.agents/skills/agmsg/scripts/whoami.sh "$(pwd)" claude-code # → Leader
bash ~/.agents/skills/agmsg/scripts/whoami.sh "$(pwd)" codex # → multiple=true agents=Developer,QA
bash ~/.agents/skills/agmsg/scripts/team.sh UnifyDrive2NAS # メンバー確認
[!note] 参加直後は人間が Leader に一声かける
monitorモードは、そのセッションで最初のターンを踏むまで 1 通目の受信に反応しない(agmsg の仕様)。
[!important] codex は同じディレクトリに 2 つ(
DeveloperとQA)いるwhoami.shは codex についてmultiple=trueを返し、どちらの役割かを自動では決められない。各 Codex セッションの起動時に、$agmsg actas Developerまたは$agmsg actas QAで役割を指定する(#Codex を herdr のペインで起動する の手順に含まれる)。actasはそのセッションを役割の席として記録し、monitorモードでは各役割宛のメッセージがその役割の Codex セッションだけに届く(agmsg のSKILL.mdのactas節)。
共通ルール
- 役割間の連絡はすべて agmsg で行う。人間を伝書鳩にしない
- セッション開始時は自分宛の未読と
historyを確認し、途中からでも文脈を引き継ぐ - 作業を始める前に
PROJECT.md(PROJECT)を読み、成果物の現状を把握する - 判断に迷ったら勝手に決めず、agmsg で相手に聞く
.mdは README も含めすべて Obsidian Flavored Markdown(wikilink・embed・callout・properties)で書く。 書く前にobsidian-markdownスキルを読み込む(全役割に同じ Obsidian スキル一式が入っている)
# 未読・履歴(<自分の名前> は Leader / Developer / QA)
bash ~/.agents/skills/agmsg/scripts/inbox.sh UnifyDrive2NAS <自分の名前>
bash ~/.agents/skills/agmsg/scripts/history.sh UnifyDrive2NAS <自分の名前> 20
# 送信
bash ~/.agents/skills/agmsg/scripts/send.sh UnifyDrive2NAS <自分の名前> <相手の名前> "<本文>"
開発規約
テスト
- 機能追加・修正には必ずテストを作成する。 テストの無い変更は検収に出さない
- バグ修正では、先にそのバグを再現して失敗するテストを書き、修正後に通ることを確かめる
報告は実行確認済みのものだけ
- 実行して確認していない成果物を「完了」として報告しない。 構文チェックは実行の代わりにならない
- 報告には、実際に実行したテストコマンドとその結果(成功・失敗の件数)をそのまま載せる
- 実行できない事情があるなら、未検証であることとその理由を明記する
作業の流れ
- Leader が Developer に実装を依頼する
- Developer が実装とテストを作り、実行して Leader に報告する
- Leader が QA にテストの検証を依頼する(#QA の役割)
- QA がテストを検証・修正・実施し、結果を整理して Leader に報告する
- Leader が検収し(#検収)、合格なら Developer にコミットを依頼する
- Developer と QA は同じ作業ツリーを使う。同時に編集しないよう、QA への依頼は Developer の報告の後に出し、その間 Developer は待機する
- QA が実装の不具合を見つけたら、Leader が Developer に差し戻す。差し戻しの修正後は、もう一度 QA に検証を依頼する
git
- このディレクトリは git で管理する。変更はすべて git 上の差分として確認できる状態にする
- 新しい作業ブランチは、必ず
git switch mainとgit pull --ff-onlyで最新にした main から切る。未マージの PR のブランチから重ねて切らない - 未マージの PR と同じファイルを変更する場合も main から切る。衝突はマージ時に解消し、判断に迷ったら Leader に聞く
- コミットは検収を通ってから行う。検収前の変更は未コミットのまま報告する
検収
Leader は Developer と QA の報告をそのまま信じず、実物で確かめる。
git status/git diffで、報告された変更内容(Developer と QA の両方)と実際の差分が一致するかを確かめる- 変更に対応するテストが追加・更新されているか、QA の検証結果に未解決の指摘が残っていないかを確かめる
PROJECT.mdの内容に関わる変更なら、同じブランチ(同じ PR)にその更新が含まれているかを確かめる- テストを自分で実行し、報告どおりに通ることを確かめる
- 問題があれば具体的に指摘して差し戻す。問題が無ければ Developer にコミットを依頼する
Leader の役割
- 人間の依頼をタスクに分解し、agmsg で Developer に依頼する
- Developer の報告を受けたら、QA にテストの検証を依頼する(#作業の流れ)
- PR を作る前の検収で、変更に合わせた
PROJECT.md(PROJECT)の更新が同じブランチ(同じ PR)に含まれているかを確かめる - 成果物をレビュー・検収し、修正が必要なら具体的に指摘して差し戻す(手順は #検収)
- 実装はしない。 コード・テストの作成と修正は、規模にかかわらずすべて Developer または QA に依頼する。Leader が行うのは調査・レビュー・検収のための読み取りとテスト実行まで
起こす係は Leader が持つ
Codex も Claude Code も配信モードは monitor。Developer と QA の bridge(codex-bridge.js)は受信箱を監視し、Codex が idle なら新しいターンを始めて新着を渡す。bridge が動くのは、Codex を agmsg 経由で起動したときだけ:
~/.agents/skills/agmsg/scripts/drivers/types/codex/codex-monitor.shで起動する(またはdelivery.sh set monitor codexが表示するcodex()シェル関数をシェルの設定に入れてcodexで起動する)- bridge は新しいセッションの最初のターンで起動する。起動しただけでは動かないので、起動後に 1 通話しかける
Developer と QA はどちらも codex-monitor.sh で起動し、bridge から新着を受け取る。送信後に反応しないときだけ Leader が herdr で起こす。
bridge は TUI と同じ app-server スレッドのコマンド実行・ファイル変更・権限昇格・MCP の確認要求をすべて拒否する(codex-bridge.js の 879〜885 行目、#299 対策)。TUI から入力したターンでも同じ。このため、ユーザー共通の ~/.codex/rules/git.rules に Codex の rules を置く。allow に一致するコマンドはサンドボックス外で確認なしに実行され、bridge の拒否を受けない。Codex rules の公式資料(2026-10-03 参照)。
この rules は Git の参照系・ローカル操作・fetch・pull --ff-only と ps を許可し、git push を禁止する(push は Leader が行う)。git -C <path> ... は先頭が違うため一致しない。変数・リダイレクト・置換を含むシェルコマンドは全体で判定される。rules は Codex の起動時に読み込まれるので、変更後は Codex を起動し直す。
rules に無く昇格が必要な操作は拒否される。テストやビルドのツールがキャッシュを書き込む場合は、サンドボックス内で書き込める場所を指定する(例: Go なら env GOCACHE=/private/tmp/UnifyDrive2NAS-go-cache GOPROXY=off go test -count=1 ./...)。拒否されたら Leader に報告する。
- agmsg で送っても宛先(Developer または QA)が反応しないときは herdr で起こす
- 相手が
working(作業中)やblocked(入力待ち)のときは何もせず待つherdr agent promptは相手がblockedのときagent_blockedを返して送信前に拒否するので、承認画面に文字を流し込む事故は起きない
- ペイン名を agmsg のエージェント名に揃える(必須)。 Developer と QA はどちらも同じ
cwdの codex なので、cwd+agentでは見分けられない。herdr pane rename <pane> Developer/herdr pane rename <pane> QAで名前を付け、ペイン名(herdr pane listのlabel)で引く
# 宛先のペインを探す(pane_id は再起動で変わるので毎回引く。<名前> は Developer または QA)
herdr pane list | python3 -c 'import json,sys; [print(p["pane_id"], p.get("agent_status")) for p in json.load(sys.stdin)["result"]["panes"] if p.get("agent")=="codex" and p.get("label")=="<名前>" and p["cwd"]=="/Users/kazu634/Documents/Obsidian/Claude/ITProjects/homelab/Projects/scripts/UnifyDrive2NAS"]'
# idle なら起こす(<pane> は上で得た pane_id)
herdr agent prompt <pane> "agmsg の受信箱を確認して" --wait --until working --timeout 30000
Codex を herdr のペインで起動する
Developer・QA の Codex は、herdr で新しいペインを作り、agmsg の起動スクリプト codex-monitor.sh で起動する。これで bridge が付き、idle の間も新着を受け取れる。起動は人間が行っても Leader が行ってもよい(どちらも Claude Code のペインの中から実行する。--current はコマンドを実行したペインを指す)。
ペインの配置は、上段に Claude Code(Leader)、下段の左に Developer、右に QA とする。
┌──────────────────────────┐
│ Claude Code(Leader) │
├─────────────┬────────────┤
│ Developer │ QA │
└─────────────┴────────────┘
D=/Users/kazu634/Documents/Obsidian/Claude/ITProjects/homelab/Projects/scripts/UnifyDrive2NAS
# split の出力から新しいペインの pane_id を取り出す
pane_id() { python3 -c 'import json,sys; print(json.load(sys.stdin)["result"]["pane"]["pane_id"])'; }
# ペイン $2 で Codex を起動し、役割 $1 を指定する
launch() {
local NAME=$1 P=$2
# ペイン名を役割名にする(Developer と QA を見分けるのに必須)
herdr pane rename "$P" "$NAME" >/dev/null
# agmsg の起動スクリプトで Codex を起動する
herdr pane run "$P" "cd $D && bash ~/.agents/skills/agmsg/scripts/drivers/types/codex/codex-monitor.sh --codex-command codex" >/dev/null
# herdr が Codex を検出し、idle になるまで待つ(最大 60 秒)
for i in $(seq 1 60); do
herdr agent wait "$P" --until idle --timeout 30000 >/dev/null 2>&1 && break
sleep 1
done
herdr agent get "$P" # agent_status が idle であることを確かめる
# 役割を指定する。これが最初のターンになり、bridge が起動する
herdr agent prompt "$P" "\$agmsg actas $NAME" --wait --timeout 180000
}
# 1. Claude Code のペインを上下に分け、下段を Developer にする
DEV=$(herdr pane split --current --direction down --cwd "$D" --no-focus | pane_id)
# 2. 下段を左右に分け、右を QA にする
QA=$(herdr pane split "$DEV" --direction right --cwd "$D" --no-focus | pane_id)
# 3. それぞれで Codex を起動する
launch Developer "$DEV"
launch QA "$QA"
- 片方だけ起動し直すときは、上の
pane_idとlaunchを定義し、残っているほうのペインを分割してlaunchを 1 回呼ぶ。例: QA だけならP=$(herdr pane split <Developer の pane_id> --direction right --cwd "$D" --no-focus | pane_id); launch QA "$P" herdr pane moveは同じタブの中では配置を変えない(changed:false、reason:"same_tab")。配置を直すときは、いったん--new-tabで別のタブに出してから--tab <元のタブ> --target-pane <隣のペイン> --split right|downで戻すlaunchの中の待ち合わせ(繰り返し)は省かない。起動直後は、Codex の画面が出た後でも herdr がまだ Codex を検出しておらず、herdr agent waitが即座にagent_not_foundで失敗する- Developer と QA を起動できたら、Leader から agmsg でそれぞれ疎通確認を送り、herdr で起こさずに返信が来ることを確かめる(来なければ bridge が付いていない)
codex-monitor.shは bridge を用意できないと、素の Codex に切り替えて起動する(画面にagmsg: Codex monitor bridge unavailableと出る)。この場合は idle の間に新着を受け取れない- 同じ役割の古いセッションが残っている場合は、先にそのセッションを終了してから起動する。生きているセッションが役割を握っていると
actasがheldで失敗する
Codex やペインを終了しても、app-server が生きている間は古い役割の bridge が残ることがある。さらに親 launcher は、一度 bridge を起動した役割を覚えており、役割の子 launcher と node だけを止めても再起動しないことがある。history で、宛先が動く前にメッセージが既読(○)になっていたら古い bridge を疑う。
起動し直すときは、まず Developer と QA の両方を /quit で終了する。次に、Leader のシェルで、このプロジェクトの app-server・親 launcher・両役割の子 launcher と node を以下で一覧表示する。pidfile 名はプロジェクトの絶対パスの SHA-1 から求める。ps が表示するタブ文字の \011 表記を照合する。
set -o pipefail
D=/Users/kazu634/Documents/Obsidian/Claude/ITProjects/homelab/Projects/scripts/UnifyDrive2NAS
PROJECT_HASH=$(printf '%s' "$D" | shasum | awk '{print $1}')
APP_PID=$(cat "$HOME/.agents/skills/agmsg/run/codex-app-server.$PROJECT_HASH.pid")
ps -axo pid=,command= | python3 -c '
import sys
project, app_pid = sys.argv[1:]
launcher = "/codex-bridge-launcher.sh codex " + project + " "
pairs = {role: r"UnifyDrive2NAS\011" + role for role in ("Developer", "QA")}
for line in sys.stdin:
pid, _, command = line.strip().partition(" ")
if pid == app_pid and command.startswith("codex app-server "):
print(f"app-server\t{pid}\t{command}")
elif launcher in command:
args = command.split(launcher, 1)[1].split()
if len(args) == 2:
print(f"parent launcher\t{pid}\t{command}")
elif len(args) == 3:
for role, pair in pairs.items():
if args[2] == pair:
print(f"{role} launcher\t{pid}\t{command}")
elif "/codex-bridge.js " in command and " --project " + project + " " in command:
for role, pair in pairs.items():
if " --pair " + pair + " " in command:
print(f"{role} node\t{pid}\t{command}")
' "$D" "$APP_PID"
表示された PID とプロジェクト・役割を確かめてから、表示されたこのプロジェクトの app-server・親 launcher・両役割の子 launcher と node を kill <確認した PID ...> で止める。他のプロジェクトの bridge は止めない。停止後、#Codex を herdr のペインで起動する の launch で両役割を起動し、疎通を確認する。
止まったときの見分け方
| 状態 | 意味 | 対処 |
|---|---|---|
idle なのに仕事が残っている |
bridge が動いていない(素の codex で起動した等)か、起こし損ね。メッセージは保管庫に残っている |
上記コマンドで起こす。続くようなら #Codex を herdr のペインで起動する の手順で起動し直す |
宛先が動く前にメッセージが既読(history で ○) |
古い役割の bridge が受け取った可能性がある | 上の起動し直す手順でこのプロジェクトの bridge 関連プロセスを止め、両役割を起動してから送り直す |
blocked |
故障ではなく、承認・権限確認などの入力待ち(正常) | 人間の承認待ちなら人間に取り次ぐ。声はかけない |
| ペインが落ちている | プロセス断 | #Codex を herdr のペインで起動する の手順で起動し直し、未読・history の確認と作業再開を指示する |
エージェントの内部状態は復元できないので、実際の作業状態はファイルの実物で確かめさせること(差分・テスト結果・実行ログ)。
Developer の役割
- Leader からの依頼に従って作業する
- 不明点は勝手に判断せず、agmsg で Leader に質問する。推測で突っ走らない
- 実装には必ずテストを付け、実行して確認してから報告する(#開発規約)
- 変更が
PROJECT.mdの内容(今の状態・構成・外部とのつながり・壊してはいけないこと・確かめ方・経緯・課題)に関わるときは、同じブランチでPROJECT.mdも更新する PROJECT.mdには、マージ前には分からない PR 番号やマージコミットのハッシュを書かない。経緯には変更内容とコミット(またはブランチ名)を書き、「この PR は未マージ」のような古くなる自己言及を避ける- 完了したら変更内容の要約(対象パス・変更概要・追加したテスト・実行したテストコマンドと結果)を Leader に報告し、次の指示を待つ
- 検収を通ったら、Leader の依頼を受けてコミットする
QA の役割
- Leader からの依頼に従って、Developer が作ったテストを検証する
- テスト内容の検証: 依頼された要件・修正内容に対してテストが足りているかを確かめる(正常系・異常系・境界値、バグ修正なら修正前に失敗するテストがあるか)
- 必要に応じた修正: テストの不足・誤りは QA が直す。修正してよいのはテストコードとテスト用データだけで、実装コードの不具合を見つけたら直さずに Leader に報告する
- テスト実施: テストを実際に実行する。直したテストは、修正前の実装に対して意図どおり失敗することも、可能な範囲で確かめる
- テスト結果の整理: 次の内容を Leader に報告し、次の指示を待つ
- 実行したテストコマンドとその結果(成功・失敗の件数)
- 検証の観点と、見つけた不足・誤り
- QA が修正・追加したテスト(対象パスと変更概要)
- 未解決の指摘(実装の不具合の疑いなど)
- 不明点は勝手に判断せず、agmsg で Leader に質問する
- コミットはしない。QA の変更も検収を通った後に Developer がまとめてコミットする