--- name: delegate-review license: MIT description: > main の context 消費の削減(context isolation)を第一目標として、 コード/ドキュメントレビュー(差分の指摘出し)を判断比重の高いモデルの subagent に委譲するスキル。 大きめの diff、複数ファイルにまたがる変更、main が差分全体を読むと重い一次レビューに使う。 数行の diff、main が既に読んだ差分、style / typo 程度の軽微レビューには使わない。 review の作業を委譲する場合は、この skill を使う。generic な subagent で代替しない。 コード変更を伴う場合は delegate-implement を使うこと。 allowed-tools: Bash(bash .claude/skills/delegate-review/scripts/run.sh:*), Bash(bash .claude/skills/delegate-review/scripts/prepare.sh:*), Bash(bash .claude/skills/delegate-review/scripts/dispatch.sh:*), Bash(bash .claude/skills/delegate-review/scripts/read-request.sh:*), Bash(bash .claude/skills/delegate-review/scripts/read-response.sh:*), Bash(bash .claude/skills/delegate-review/scripts/read-json.sh:*), Bash(git diff:*), Bash(git log:*), Bash(git show:*), Bash(git status:*), Read --- # delegate-review 差分のコード/ドキュメントレビューを委譲する。task_type=`review`、既定モデル `opus`(指摘品質が成果物に直結し判断比重が高いため)。実行系分岐(Codex / Devin / Cursor / Claude / OpenCode)は `dispatch.sh` が行う。`opencode//` を使う場合は `opencode` CLI(ログイン済み)が必要。 ## スクリプトパス - Claude Code: `skill_dir=.claude/skills/delegate-review` - Codex: `skill_dir=.agents/skills/delegate-review` 以降のコマンド例は Claude Code の `.claude/skills/delegate-review` を使う。Codex で使う場合は、同じ相対構造の `.agents/skills/delegate-review` に読み替える。 ## モデル価格参照 コスト分析・単価比較が必要な場合のみ、`/model-token-prices.json` を読む。このデータは参照用であり、delegate の起動可否判定には使わない。 ## 委譲する前に(コストゲート) review は、main が差分全体を読むと context を膨らませる一次レビューに使う。大きめの diff、複数ファイルにまたがる変更、広い影響範囲の確認が必要な差分を発火条件にする。一方、数行の diff、main が既に読んだ差分、style / typo 程度の軽微レビューは委譲せず main が直接処理する。 レビュー対象はコード差分に限らず、README / spec / design docs / changelog などのドキュメント差分も含める。 review の作業を委譲する場合は、この skill を使う。generic な subagent へ流す運用はしない。 ## 実行フロー(one-shot) 1. **リクエスト作成**: Objective / Scope / Context / Constraints の Markdown を stdin で渡す。レビュー対象の差分範囲(base/head・対象パス等)を Scope に明記する。request は terse に書く: diff 本体やファイル内容は貼らず、範囲指定とパス参照で渡す(main の出力=課金トークンを増やさないため)。 - ユーザーが会話でモデルや effort を指定した場合は、run 呼び出しにインライン env を前置する(例: `DELEGATE_REVIEW_MODEL=gpt-5.5@high bash .../run.sh ...`)。exit 6 の場合は、許容値列挙を含む stderr の 1 行をそのままユーザーへの説明に使う。 2. **実行**: `out="$(printf '%s' "$req_md" | bash .claude/skills/delegate-review/scripts/run.sh review DELEGATE_REVIEW_MODEL opus "$PARENT_TASK_TYPE_CHAIN" "$REQUESTER_SESSION_ID")"`(top-level 起動なら `$PARENT_TASK_TYPE_CHAIN` は空でよい)。 - run は内部で prepare → dispatch → read-response を順に実行し、stdout は成功・失敗とも単一 JSON(`exit_code` / `status` / `content` / `content_truncated` / `response_file` / `observe_file` / `run_dir`)を返す。 - selector 省略時の既定は `decision`。`decision` は大規模 response でも Summary と Findings / Blockers の要点を 1 回で返す。第 6 位置引数は read-response の selector であり、prepare.sh の第 6 位置引数 session_mode とは意味が異なる。 - exit code は内部スクリプトを透過する。exit 3=前提不足 / exit 4=委譲サイクルなら中止する。 - `run.sh` は dispatch 前に `observe_file: ` を stderr へ先出しする。`run.sh` が Bash timeout で background へ退避しただけの場合は**再実行しない**(再実行は worker の二重起動になり、implement / chore では同一 worktree の同時書き換えになる)。復旧は `bash .claude/skills/delegate-review/scripts/read-json.sh .state.phase "$observe_file"` を見て分岐する。`ended` / `stalled` / `interrupted` なら終端なので、いずれでも `bash .claude/skills/delegate-review/scripts/read-json.sh .run.response_file "$observe_file"` で応答パスを取得して `bash .claude/skills/delegate-review/scripts/read-response.sh` で読む(`stalled` では failed response が書かれる。`interrupted` は dispatcher が終端を書けずに落ちた run を wrapper が代わりに記録したもので、`.state.response_present` が `true` なら完走した response がある)。`running` の間は `.heartbeat.ts` が進んでいれば待つ。`running` のまま `.heartbeat.ts` が `DELEGATE_OBSERVE_HEARTBEAT_INTERVAL`(既定 10 秒)を大きく超えて進まない場合は dispatcher が終端を書けずに落ちている。wrapper も同時に落ちていれば phase は終端へ遷移しないので、待っても応答は来ない。**新しい run を出す前に**順に確認する。(1) `read-json.sh .run.response_file "$observe_file"` を読む。dispatcher だけが死んだ場合、wrapper が完全な response を書き終えていることがある。(2) response が `Child CLI failed or did not write a response.` の stub なら、`read-json.sh .run.run_dir "$observe_file"` の `/worker-stdout.capture` に子 CLI の生 stream が残っている。wrapper が finalize まで到達していれば observe の `.streams.stdout.content` にも `DELEGATE_OBSERVE_STREAM_MAX_BYTES`(既定 65536 バイト)まで入る。構造化された response ではないが、長い run では再実行より安く回収できる。(3) `read-json.sh .heartbeat.child_pid "$observe_file"` の pid の生存を確認する。wrapper は dispatcher と別プロセスなので孤児化して動き続けることがあり、生きている間に implement / chore で新しい run を出すと同一 worktree の二重書き換えになる。確認後に新しい run を出す。background 退避した出力ファイルは stdout と stderr が合流するが、`read-json.sh` は既知の harness 行(空行 / `observe_file: ` 行 / `[exited with ...]` 行)に囲まれた JSON object を切り出して読める。 - 非対話モードの親(`claude -p` 等)では run を必ずフォアグラウンドで実行し、委譲所要時間より長い Bash timeout(Claude Code なら `BASH_DEFAULT_TIMEOUT_MS` / `BASH_MAX_TIMEOUT_MS` または Bash tool の timeout 引数)を設定する。 3. **レスポンス消費と裏取り**: `status="$(printf '%s' "$out" | bash .claude/skills/delegate-review/scripts/read-json.sh .status)"` / `content="$(printf '%s' "$out" | bash .claude/skills/delegate-review/scripts/read-json.sh .content)"` を読む。`content_truncated` が `true` なら `response_file="$(printf '%s' "$out" | bash .claude/skills/delegate-review/scripts/read-json.sh .response_file)"` を取り出し、`bash .claude/skills/delegate-review/scripts/read-response.sh "$response_file" ` で必要 section だけ段階読みする。読了後、worker の本文を **要約し直さない(echo しない)**。`status` が `failed` なら Error section をユーザーへ伝える。`completed` でも Summary 先頭に警告行があればその旨を伝える(警告は response 本体に載るので selector に関わらず Summary とともに返る)。重要 findings は該当する `file:line` 周辺または該当 diff だけを main が確認する。問題なしの報告や軽微 findings は差分全体を再読せず、Scope と Summary の整合を確認する。 ## 高度なフロー(個別スクリプト) dispatch 中の observe 監視、background 実行など、途中で親の判断を挟むフローでは従来の個別スクリプトを使う。 1. **準備(集約)**: 前提チェック→モデル解決→チェーン確認→リクエスト生成を `prepare.sh` 1 本に畳む。Objective / Scope / Context / Constraints の Markdown を stdin で渡す。レビュー対象の差分範囲(base/head・対象パス等)を Scope に明記する。request は terse に書く: diff 本体やファイル内容は貼らず、範囲指定とパス参照で渡す(main の出力=課金トークンを増やさないため)。exit 3=前提不足 / exit 4=委譲サイクルなら中止。 - ユーザーが会話でモデルや effort を指定した場合は、prepare 呼び出しにインライン env を前置する(例: `DELEGATE_REVIEW_MODEL=gpt-5.5@high bash .../prepare.sh ...`)。prepare が exit 6 の場合は、許容値列挙を含む stderr の 1 行をそのままユーザーへの説明に使う。 - `out="$(printf '%s' "$req_md" | bash .claude/skills/delegate-review/scripts/prepare.sh review DELEGATE_REVIEW_MODEL opus "$PARENT_TASK_TYPE_CHAIN" "$REQUESTER_SESSION_ID")"`(top-level 起動なら `$PARENT_TASK_TYPE_CHAIN` は空でよい) - `model="$(printf '%s' "$out" | bash .claude/skills/delegate-review/scripts/read-json.sh .model)"` / `request_file="$(printf '%s' "$out" | bash .claude/skills/delegate-review/scripts/read-json.sh .request_file)"` / `response_file="$(printf '%s' "$out" | bash .claude/skills/delegate-review/scripts/read-json.sh .response_file)"` / `run_dir="$(printf '%s' "$out" | bash .claude/skills/delegate-review/scripts/read-json.sh .run_dir)"` / `observe_file="$(printf '%s' "$out" | bash .claude/skills/delegate-review/scripts/read-json.sh .observe_file)"` 2. **実行**: `bash .claude/skills/delegate-review/scripts/dispatch.sh "$model" review "$request_file" "$response_file" "$run_dir" "$observe_file"`。モデル名プレフィックスによる実行系分岐(Codex / Devin / Cursor / Claude / OpenCode)は dispatch.sh が行う。stdout は response_file のパスのみ。非対話モードの親(`claude -p` 等)では dispatch を必ずフォアグラウンドで実行し、委譲所要時間より長い Bash timeout(Claude Code なら `BASH_DEFAULT_TIMEOUT_MS` / `BASH_MAX_TIMEOUT_MS` または Bash tool の timeout 引数)を設定する。実行中の通常監視は `observe_file` から `state.phase` / `state.started_at` / `heartbeat.ts` / `heartbeat.stdout_bytes` / `heartbeat.stderr_bytes` / `heartbeat.last_stream_change_at` だけを read-json.sh で読む。`state.phase` は `prepared | running | superseded | stalled | interrupted | ended`。`prepared` / `superseded` は dispatch されなかった observe(`state.started_at == null`、`usage` は未設定で read-json.sh では null 相当)なので、usage を集計する場合は分母から除外する。 3. **レスポンス読み取り**: `bash .claude/skills/delegate-review/scripts/read-response.sh "$response_file" decision`。`decision` は大規模 response でも Summary と Findings / Blockers の要点を 1 回で返す。さらに必要な詳細があれば `... "$response_file" ` で追加取得する。読了後、worker の本文を **要約し直さない(echo しない)**。`status` が `failed` なら Error section をユーザーへ伝える。`completed` でも Summary 先頭に警告行があればその旨を伝える(警告は response 本体に載るので selector に関わらず Summary とともに返る)。main のユーザー向け応答は Summary を指す 1 行に留める(main の出力=課金トークンを増やさないため。spec.md §6)。 4. **裏取りフェーズ(必須)**: `status` を先に確認し、必要時のみ Findings section を引く。重要 findings は該当する `file:line` 周辺または該当 diff だけを main が確認する。問題なしの報告や軽微 findings は差分全体を再読せず、Scope と Summary の整合を確認する。 ## 待ち時間の隠蔽(対話親向け) 対話親では体感待ち時間を隠蔽できる。経路は起動スクリプトで異なる。`dispatch.sh` 経由は `prepare.sh` で `response_file` を事前取得済みなので、`dispatch.sh` を background で実行し、`observe_file` の `state.phase` / `heartbeat` を確認して `ended` / `stalled` / `interrupted` になった後に `read-response.sh` する。`run.sh` 経由は `response_file` を事前に取得できないので、`run.sh` を background で実行した場合は `read-json.sh .run.response_file "$observe_file"` で応答パスを取るか、合流した出力 JSON をそのまま `read-json.sh` で読む。総所要時間(wall time)は変わらない体感改善であり、非対話モードの親では従来どおりフォアグラウンド実行必須。 ## 制約 - read-only。ファイル編集・git の書き込み操作・push はしない(差分を読んで指摘を報告するだけ) - read-only 種別のため session reuse(resumable / follow-up)は使わない - 指摘は報告 Markdown の Findings section に収め、各 finding に severity / file:line / 根拠 / 影響 / 推奨対応を含める - task_type_chain 内種別への再委譲はしない(別種別 delegate は可) - main は worker 出力を echo / 再要約しない。ユーザー向けは Summary を指す 1 行に留める(出力=課金トークンを増やさないため。spec.md §6) - OpenCode: cwd 外への出力は保証されない(direct な edit / write と明示パスの読み取りは拒否され、bash のリダイレクトは通る)。request が `DELEGATE_REQUEST_INLINE_MAX` を超えると child 起動前に fail-closed する - OpenCode の read-only 抑止は管理者設定のない環境を前提とする(管理者設定は注入した permission を override し得る) - この種別は常に `--pure` で起動し、OpenCode の project plugin を読み込まない(plugin は任意コード実行で prompt 制約を迂回し得るため)。`DELEGATE_OPENCODE_PURE` が `1` / `true` / `yes` なら implement / chore を含む全 task type へ広げる。`DELEGATE_OPENCODE_MCP_SOURCE`(`claude` / `cursor` / `codex`)で MCP 入力元を明示し、未指定なら注入しない