Files
tver/AGENTS.md
T

251 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# チーム運用規約(tver)
> [!info] このファイルの位置づけ
> プログラム開発を行うための規約集。
> **自分の役割は agmsg に登録した名前で決まる。** 未参加なら人間の指示に従って参加し、以後は自分の役割の節に従うこと。
## チーム構成
| エージェント | 種別 | 役割 |
| --------------- | ----------- | --------------------------------------------- |
| **`Leader`** | claude-code | 人間の窓口。計画・タスク分解・依頼・検収 |
| **`Developer`** | codex | 実作業。実装・テスト作成・修正 |
| **`QA`** | codex | テストの品質保証。テスト内容の検証・必要に応じたテストの修正・テスト実施・テスト結果の整理 |
参加は人間の指示を受けてから行う。名前は上の表のとおりにする(`whoami.sh` が出す候補名は他チームのものを含むので使わない)。
```bash
# 参加(チームが無ければ作成される)
bash ~/.agents/skills/agmsg/scripts/join.sh tver Leader claude-code "$(pwd)"
bash ~/.agents/skills/agmsg/scripts/join.sh tver Developer codex "$(pwd)"
bash ~/.agents/skills/agmsg/scripts/join.sh tver 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 tver # メンバー確認
```
> [!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|tver の現状]])を読み、成果物の現状を把握する
- 判断に迷ったら勝手に決めず、agmsg で相手に聞く
- **`.md` は README も含めすべて Obsidian Flavored Markdown(wikilink・embed・callout・properties)で書く。** 書く前に `obsidian-markdown` スキルを読み込む(全役割に同じ Obsidian スキル一式が入っている)
```bash
# 未読・履歴(<自分の名前> は Leader / Developer / QA)
bash ~/.agents/skills/agmsg/scripts/inbox.sh tver <自分の名前>
bash ~/.agents/skills/agmsg/scripts/history.sh tver <自分の名前> 20
# 送信
bash ~/.agents/skills/agmsg/scripts/send.sh tver <自分の名前> <相手の名前> "<本文>"
```
## 開発規約
### テスト
- **機能追加・修正には必ずテストを作成する。** テストの無い変更は検収に出さない
- バグ修正では、先にそのバグを再現して失敗するテストを書き、修正後に通ることを確かめる
### 報告は実行確認済みのものだけ
- **実行して確認していない成果物を「完了」として報告しない。** 構文チェックは実行の代わりにならない
- 報告には、実際に実行したテストコマンドとその結果(成功・失敗の件数)をそのまま載せる
- 実行できない事情があるなら、未検証であることとその理由を明記する
### 作業の流れ
1. Leader が Developer に実装を依頼する
2. Developer が実装とテストを作り、実行して Leader に報告する
3. Leader が QA にテストの検証を依頼する([[#QA の役割]])
4. QA がテストを検証・修正・実施し、結果を整理して Leader に報告する
5. 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 の報告をそのまま信じず、**実物で確かめる**。
1. `git status` / `git diff` で、報告された変更内容(Developer と QA の両方)と実際の差分が一致するかを確かめる
2. 変更に対応するテストが追加・更新されているか、QA の検証結果に未解決の指摘が残っていないかを確かめる
3. `PROJECT.md` の内容に関わる変更なら、同じブランチ(同じ PR)にその更新が含まれているかを確かめる
4. **テストを自分で実行し、報告どおりに通ることを確かめる**
5. 問題があれば具体的に指摘して差し戻す。問題が無ければ Developer にコミットを依頼する
## Leader の役割
- 人間の依頼を**タスクに分解し、agmsg で Developer に依頼する**
- Developer の報告を受けたら、**QA にテストの検証を依頼する**([[#作業の流れ]])
- PR を作る前の検収で、変更に合わせた `PROJECT.md`([[PROJECT|tver の現状]])の更新が同じブランチ(同じ 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 の公式資料](https://learn.chatgpt.com/docs/agent-configuration/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/tver-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`)で引く
```bash
# 宛先のペインを探す(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/tver"]'
# 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 │
└─────────────┴────────────┘
```
```bash
D=/Users/kazu634/Documents/Obsidian/Claude/ITProjects/homelab/Projects/scripts/tver
# 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` 表記を照合する。
```bash
set -o pipefail
D=/Users/kazu634/Documents/Obsidian/Claude/ITProjects/homelab/Projects/scripts/tver
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"tver\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 がまとめてコミットする