self-review について
現在のブランチを自己レビューするスキルです。Codex によるレビュー、指摘ごとの修正とテストを、結果が収束するか停止条件に達するまで繰り返します。コードを変更しないレビュー専用モードもあります。
主な機能
- 01Codex のレビューを独立したプロセスで実行
- 02修正ごとに個別のコミットを作成
- 03修正後にテストを実行
- 04停止条件までレビューを反復
- 05レビュー専用モードを提供
活用シーン
- 01プッシュ前にコミット済み機能ブランチを確認
- 02PR 前に変更を反復して改善
- 03自動修正なしで指摘を確認
- 04人によるレビュー前に問題を検出
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ kirkchen/ cadence --skill self-reviewインストール後、Claude Code で/self-reviewを入力して読み込まれたか確認します。
詳細
セルフレビュー
現在のブランチで開発段階のセルフレビューを自動ループで実行します。codex(OpenAI GPT)を実行し、pr-review の複数ロール方式に従ってクロスモデルレビューを行い、指摘ごとに修正を適用して再レビューします。指摘が収束するか、停止条件が発動するまでループします。
オプトインで単発モード(review-only)も利用できます。自動修正は行わず、指摘のみを提示します。
ループの動作:
- 指摘ごとに個別のアトミックなコミットを作成します。修正ごとに独立した Conventional Commit を作成するため、簡単に取り消せます。
- 停止条件は交渉の余地がありません(以下の「停止条件」を参照)。いずれかが発動した場合、ループを停止し、残りの作業を必ずユーザーに提示します。
- ユーザーはいつでも ctrl-c で中断できます。メインセッションは中断を検知し、途中の状態を報告します。
コンテキスト混在の防止:
- Codex はイテレーションごとに新しいプロセスで実行され、メインセッションと会話のコンテキストを共有しません。
- Codex の出力(詳細な指摘テキスト)はチャットではなく一時ファイルに保存し、構造化された JSON の要約のみをイテレーションごとにメインセッションのメモリに取り込みます。
- 修正を実装するメインセッションは、Codex の指摘にある
Mitigation:フィールドを文字どおり、機械的に実行する必要があります。修正が正しいかどうかについて追加で推論したり、「よりよい方法」に置き換えたり、対象範囲を広げたりしてはいけません。 Mitigation:フィールドだけでは指摘を修正できない場合(曖昧である、設計上の判断が必要である、またはこの指摘の範囲外のコードに影響する場合)は、そのイテレーションでは指摘をスキップし、最後にユーザーへ提示します。
判定に関する推論の禁止:
- このスキルでは、修正不要の判断は行いません。指摘はすべて、自動修正するか、エスカレーションして提示します。
- 「この指摘は重要ではない」と判断してはいけません。上記の「Mitigation だけでは修正できない」条件に該当する場合を除き、すべての指摘を修正します。
- メインセッションのメモリから Wontfix Template の項目を記入してはいけません(
pr-babysit§ 4.6 を参照)。
品質ゲート:
- 各イテレーションの修正後にテストを実行します。
pnpm test(またはリポジトリで検出されたコマンド)を実行してください。失敗した場合は停止してエスカレーションします。 - これは、「修正によって問題が発生する」場合に備える自然な安全策です。
修正時の作成者バイアス:
- Codex(クロスモデル)が指摘を生成するため、指摘の生成段階ではバイアスが分離されています。
- メインセッションが修正を書きます。ここではバイアスは分離されていませんが、Codex の Mitigation に文字どおり従うため、バイアスの攻撃対象領域は「機械的な実行精度」であり、「判定の判断」ではありません。
- 「Codex の判断は間違っていると思う」と推論していることに気づいた場合、それは判定に関する推論であり、このスキルでは許可されません。最後にユーザーへ提示してください。
モード
loop(デフォルト)— Codex のレビュー → 指摘ごとの修正とコミット → テスト → 再レビュー → 停止するまでループreview-only— Codex のレビューを1回実行して指摘を提示し、停止します。修正、コミット、テストは行いません。自動変更なしで手動レビューを行いたい場合に使用します。
モードの選択:
- ユーザーが「セルフレビュー」または「ブランチをレビューして」と言った場合 →
loop(デフォルト) - ユーザーが「指摘だけ見せて」または「修正なしでセルフレビュー」と言った場合 →
review-only
使用する場面
- 機能ブランチでコードを書き終え、作業ツリーがクリーンでコミット済みの状態で、プッシュ前にクロスモデルレビューと修正を自動実行したい場合
- 機能の開発を繰り返しながら、すばやくクリーンな状態に収束させたい場合
- PR 前の健全性チェックとして、人に送る前に Codex が見つける明らかな問題を検出したい場合
使用しない場面
- 付箋コメントとインラインスレッドを使う公開中の PR レビュー →
/cadence:pr-review(デフォルトモード) - PR 公開後の PR 対応作業 →
/cadence:pr-babysit(スレッドへの返信、重複排除、CI ゲートに対応) - 作業ツリーに未コミットの変更がある場合 — 停止し、先にコミットするか stash するようユーザーに依頼します。ループでは開始時に作業ツリーがクリーンであることを前提とし、指摘ごとのコミットをアトミックに保ちます。
- 判定を手動で管理したい場合 →
mode=review-onlyを使用し、自分で判断します。 - 新しいブランチで初めて使用する場合 → 自動修正を許可する前に Codex の出力を確認するため、最初は
mode=review-onlyの使用を検討してください。
セットアップの確認
開始時に次のチェックを実行します。いずれかに失敗した場合は、記載されたメッセージを表示して停止してください。自動インストールを試みてはいけません。
# Codex CLI
codex --version 2>/dev/null || { echo "STOP: Install codex — npm install -g @openai/codex"; exit 1; }
codex login status >/dev/null 2>&1 || { echo "STOP: Run 'codex login' to authenticate"; exit 1; }
# `codex login status` is a subcommand, not a flag. `--status` is rejected as an unknown
# argument by codex-cli 0.150.x, which makes this check fail for an authenticated user.
# Plugin install root — needed so codex can locate the pr-review methodology prompts
[ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ -d "${CLAUDE_PLUGIN_ROOT}/skills/pr-review" ] || {
echo "STOP: CLAUDE_PLUGIN_ROOT must point at cadence's install root (so codex can read ./skills/pr-review/*-prompt.md). Set it explicitly if your harness doesn't export it (e.g. export CLAUDE_PLUGIN_ROOT=~/.claude/plugins/cache/cadence/cadence/<version>)."; exit 1;
}
# Clean working tree
git diff --quiet && git diff --cached --quiet || { echo "STOP: Working tree has uncommitted changes. Commit or stash, then re-invoke."; exit 1; }
# Detect base branch
BASE=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||')
[ -z "$BASE" ] && BASE=main
echo "BASE: origin/$BASE"
# Detect test command (best-effort — repo-specific)
if [ -f package.json ] && jq -e '.scripts.test' package.json >/dev/null 2>&1; then
TEST_CMD="pnpm test"
elif [ -f Makefile ] && grep -q '^test:' Makefile; then
TEST_CMD="make test"
else
TEST_CMD=""
echo "WARN: No test command detected — quality gate disabled"
fi
echo "TEST_CMD: ${TEST_CMD:-<none>}"
ループアルゴリズム(mode=loop)
メインセッションのメモリで、以下を維持します。
-
ITER— 現在のイテレーション番号(1から開始) -
MAX_ITERS = 3— 厳格な上限です。実測では、codex が価値の高い指摘(実際に到達可能なバグで、同じモデルのレビュアーが見落とすようなもの)を見つけるのはイテレーション1~3です。イテレーション4~5では衛生面の細かな指摘が増え、ときおり誤検出も発生します。その場合、コントローラーは判断して却下しなければなりません。実際の停止条件は後述の SC0(重大度の下限)です。MAX_ITERSは大まかな最終防衛線です。 -
FINDING_HISTORY— イテレーションごとに、そのイテレーションの指摘を{file, failure_mode, slug}のリストとして記録します。指摘の識別にはfileと失敗モードを使い、file:line:slugは使いません。行番号とスラッグは、指摘が同じかどうかとは無関係な理由でどちらも変わります。修正のたびに後続の行番号がずれ、codex はパスごとに自由に名前を変更します。文章中心のリポジトリで実施した4イテレーションの実行では、完全一致フィンガープリントのチェック(SC3)は一度も発火しませんでした。一方、ある指摘は3つの異なるスラッグと行番号で3イテレーション連続して再発しました。重複ゼロのチェック(SC4b)は2回発火しましたが、どちらも誤りでした。前のイテレーションの指摘は修正済みで、残った行番号もすべて移動していたため、重複がほぼゼロになるのは当然だったからです。その実行では、フィンガープリントに依存するシグナルは、誤検出・見逃しの両方向ですべて誤っていました。
あなたはモデルであり、
grepではありません。失敗モードを比較し、同じ欠陥を指しているかどうかを判断してください。同じファイルに対するauthor-self-accepts-security-exceptionsとspoofable-accepted-by-identityは、別々の指摘ではなく、繰り返し発生している同一の指摘です。
ステップ1:codex のレビューを実行する
mode=review-only のステップ2(後述の Codex プロンプトのセクションを参照)と同じプロンプトを構成します。出力先は $WORK_DIR/iter-$ITER.md です。冗長な codex の出力をメインセッションに直接含めないでください。JSON サマリーブロックのみを解析します。
codex のプロンプトは、メインセッションが文章を解析せずにループを進められるよう、サマリー JSON ブロック(後述の Codex プロンプトのセクションで説明)で終わらせる必要があります。
WORK_DIR=${WORK_DIR:-$(mktemp -d "${TMPDIR:-/tmp}/self-review-XXXXXX")}
PROMPT_FILE="$WORK_DIR/prompt-iter-$ITER.md"
OUTPUT_FILE="$WORK_DIR/iter-$ITER.md"
JSON_FILE="$WORK_DIR/iter-$ITER.json"
# Write prompt (see Codex Prompt section)
write_codex_prompt > "$PROMPT_FILE"
# Run codex (5-min timeout)
_REPO_ROOT=$(git rev-parse --show-toplevel)
codex exec "$(cat "$PROMPT_FILE")" \
-C "$_REPO_ROOT" \
-s read-only \
-c 'model_reasoning_effort="high"' \
--enable web_search_cached \
> "$OUTPUT_FILE" 2>/tmp/self-review-err
# Extract JSON summary block between unique sentinels
# awk, not sed: the multi-command `/range/{...}` form is a GNU extension. BSD sed (macOS)
# rejects it with `extra characters at the end of p command`, writes an empty $JSON_FILE,
# and the guard below then blames codex for output codex actually produced.
awk '//{f=1;next} //{f=0} f' \
"$OUTPUT_FILE" > "$JSON_FILE"
# Guard: codex must emit a parseable JSON block — empty or malformed is NOT zero findings
if [ ! -s "$JSON_FILE" ]; then
# Distinguish "codex emitted nothing" from "extraction failed" — they need different fixes,
# and the second one masquerading as the first sends the user to debug the wrong process.
if grep -q 'SELF-REVIEW-JSON-START' "$OUTPUT_FILE"; then
echo "STOP: the JSON block IS present in $OUTPUT_FILE but extraction produced nothing — this is a bug in this skill's extraction step, not in codex."
else
echo "STOP: codex did not emit a JSON summary block. Output saved to $OUTPUT_FILE for manual review."
fi
break
fi
if ! jq -e '.findings | type == "array"' "$JSON_FILE" >/dev/null 2>&1; then
echo "STOP: codex JSON summary malformed. Output: $OUTPUT_FILE, JSON: $JSON_FILE"
break
fi
# Sanity: confirm line_source field is "source" on every finding (catches diff-line confusion)
BAD_LINE_SOURCE=$(jq -r '[.findings[] | select(.line_source != "source")] | length' "$JSON_FILE")
if [ "$BAD_LINE_SOURCE" != "0" ]; then
echo "STOP: codex emitted findings with line_source != 'source' (likely diff-line numbers, not source-file lines). Review $OUTPUT_FILE manually."
break
fi
ステップ2:収束チェック
$JSON_FILE から指摘を読み込みます。停止条件を順番に適用します。最初に一致した条件を採用します。
FINDINGS_COUNT=$(jq '.findings | length' "$JSON_FILE")
SC1 — 成功:FINDINGS_COUNT == 0 → 停止し、成功を報告します。
SC0 — 重大度の下限(十分に収束):指摘がすべて衛生面のものだけであるイテレーション → 停止し、収束したと報告します。「衛生面の指摘のみ」とは、Blocker|Factual に該当する severity と、Reachable|Asymmetric に該当する justification の両方を満たす指摘が一つもないことです。つまり、実際に到達可能なバグは残っておらず、Suggestion/Question のみ、または Precedent/Historical に基づく推測にとどまる Factual の指摘だけが残っている状態です。
REAL_BUGS=$(jq -r '[.findings[]
| select((.severity == "Blocker" or .severity == "Factual")
and (.justification == "Reachable" or .justification == "Asymmetric"))]
| length' "$JSON_FILE")
REAL_BUGS == 0(かつ FINDINGS_COUNT > 0)→ 停止します。残っている衛生面の指摘はユーザーに提示し、自動修正は行いません。これらの指摘は、codex のレビューをもう一度実行するほどの基準を満たしていません。これは健全な実行で_意図されている_停止条件で、通常はイテレーション2~3で発火します。MAX_ITERS は、codex がそれ以上のイテレーションでも実際のバグを指摘し続ける場合にのみ検出します。その場合、変更が大きすぎるため、分割すべきだというシグナルにもなります。
SC0 を SC2 より先に、SC1 の後にチェックする理由:指摘がゼロであれば、曖昧さなく成功です。衛生面の指摘だけのイテレーションも、十分に収束した成功です。
MAX_ITERSの上限は、望ましくない場合の最終防衛線です。SC0 と名付けることで、SC2~SC6 の番号を変えずに、成功に分類される SC1 のすぐ近くに配置しています。
SC2 — 上限到達:ITER > MAX_ITERS → 停止し、現在の指摘をエスカレーションします。これ以上修正を適用しないでください。
SC3 — 同じ指摘が3回発生(再発のシグナル):
今回のイテレーションにある各指摘について、FINDING_HISTORY をさかのぼり、同じファイルで同じ欠陥が発生したイテレーション数を数えます。スラッグや行番号にかかわらず、同じ失敗モードを指しているものを数えます。3回以上なら停止し、エスカレーションします。
# Mechanical pre-filter only. It narrows the candidates; it does not decide.
jq -r '.findings[] | "\(.file)\t\(.slug)\t\(.failure_mode)"' "$JSON_FILE"
次に、候補ごとに判定します。同じ不具合が、それ以前の2回のイテレーションで報告されていますか? 文字列が一致するかではなく、失敗モードのテキストに基づいて回答してください。ファイルが履歴に含まれており、失敗モードの表現は異なっていても同等の不具合を示す指摘は、該当するものとして数えます。このチェックによって、修正を繰り返しても解消できていない指摘を検出します。パッチで穴を塞ぐのではなく場所を移したために、レビュー担当者がラウンドごとに同じ穴を別の表現で指摘し直すケースです。
同等の収束失敗パターンについては、pr-babysit § 4.5 Gate B を参照してください。
SC3.5 — ホットファイル(警告であり、停止条件ではありません):各イテレーションで指摘が発生したファイルを追跡します。1つのファイルで3回以上連続してイテレーション中に指摘が発生した場合、レポートに記載し、そのまま続行します。
jq -r '.findings[].file' "$JSON_FILE" | sort -u > "$WORK_DIR/iter-$ITER.files"
if [ "$ITER" -ge 3 ]; then
HOT=$(grep -Fxf "$WORK_DIR/iter-$((ITER-1)).files" "$WORK_DIR/iter-$ITER.files" \
| grep -Fxf "$WORK_DIR/iter-$((ITER-2)).files")
fi
以前は、SC3がスラッグの揺れを見抜けない問題を補うための停止条件でした。SC3は現在、失敗モードに基づいて照合するため、その役目は終わっています。また、停止条件としては、このシグナルは実際に有害でした。製品が1つの大きなファイルで構成されているリポジトリでは、定義上、すべての指摘がそのファイルに集まるため、3回以上続く実行のたびに発動します。実際、この変更につながった実行でもそうなり、まだ実作業が残っていたループを停止させました。
残す価値があるのは、表面化させることだけで、対処はしないシグナルです。ラウンドを重ねても同じファイルから指摘が出る場合、そのファイルの変更が大きすぎて、段階的にレビューするのが難しいことを示唆しています。その旨を伝え、判断は人に委ねます。
SC4 — 指摘の発散:2つのシグナルのどちらか一方で発動します(競合の連鎖を検出する仕組み。pr-babysit § 4.5 Gate B を参照)。
(a) 件数の増加:FINDINGS_COUNT が前のイテレーションの件数より厳密に大きい場合 → 停止し、エスカレーションします。修正手順が、問題を解決するより速く新たな問題を生み出しています。
(b) 集合の入れ替わり — 今回のイテレーションの指摘と前回の指摘がまったく重複せず、かつ新しい指摘が前回の修正バッチで変更したコード(prior_fix_range)に含まれる場合。両方の条件が必要です。
重複がないだけなら、健全なイテレーションでよくある状態です。前回のラウンドで指摘された内容をすべて修正したため、再発していないということです。それだけで発動すると、成功を失敗として報告することになり、4回のイテレーションを含む実行で2回測定した結果、どちらも誤検出でした。発散を区別するのは、新しい指摘がどこにあるかです。直近の修正で書き換えた行の中にあるなら、修正は問題を閉じるのではなく、新たな問題が生じる余地を作っています。
# Which files did the previous fix batch touch?
git diff --name-only $prior_fix_range > "$WORK_DIR/prior-fix-files.txt"
# How many of this iteration's findings are in those files?
IN_FIX=$(jq -r '.findings[].file' "$JSON_FILE" | grep -Fxf "$WORK_DIR/prior-fix-files.txt" | wc -l | tr -d ' ')
TOTAL=$(jq '.findings | length' "$JSON_FILE")
発動条件:TOTAL >= 3 かつ前回のイテレーションとの意味的な重複がゼロ かつIN_FIX が TOTAL の半分以上。そうでなければループを続けます。指摘は自ら招いた手戻りではなく、新たな作業です。
pr-review のドロップシグナル(B)では、自ら導入した範囲の指摘を破棄するため、ここでのシグナルとは非対称である点に注意してください。ここでは同じ状況がフィルターではなく停止シグナルになります。自己レビューで、自分が引き起こした問題を修正することは認められますが、それをいつまでも続けることはできず、状況を伝えずに続けることもできません。
ステップ 3:指摘事項ごとに修正を適用する
停止条件が発動していない場合、指摘事項を順に確認し、それぞれを独立したコミットとして適用します。
jq -c '.findings[]' "$JSON_FILE" | while read -r FINDING; do
ID=$(echo "$FINDING" | jq -r '.id')
PERSONA=$(echo "$FINDING" | jq -r '.persona')
CATEGORY=$(echo "$FINDING" | jq -r '.category')
SLUG=$(echo "$FINDING" | jq -r '.slug')
FILE=$(echo "$FINDING" | jq -r '.file')
LINE=$(echo "$FINDING" | jq -r '.line')
FAILURE_MODE=$(echo "$FINDING" | jq -r '.failure_mode')
MITIGATION=$(echo "$FINDING" | jq -r '.mitigation')
# Main session reads the full finding from OUTPUT_FILE for context
# then implements MITIGATION literally
apply_minimal_fix_from_mitigation "$FILE" "$LINE" "$MITIGATION"
# Verify file changed
if git diff --quiet "$FILE"; then
SKIPPED_FINDINGS+=("$ID: no diff produced — mitigation may need design judgment")
continue
fi
# Atomic commit. The body goes through a FILE, never `-m "...$MITIGATION..."`:
# $FAILURE_MODE / $MITIGATION / $SLUG are codex's output, and inside a double-quoted
# shell string both `backticks` and $(...) are command substitution. Best case a cited
# `file.py:42` silently becomes empty; worst case model output executes.
MSG_FILE="$WORK_DIR/commit-$ID.txt"
{
printf 'fix(%s): %s — self-review iter %s #%s\n\n' "$PERSONA" "$SLUG" "$ITER" "$ID"
printf 'Failure mode: %s\n' "$FAILURE_MODE"
printf 'Mitigation: %s\n\n' "$MITIGATION"
printf 'Source: codex review following pr-review methodology\nCategory: %s\n' "$CATEGORY"
} > "$MSG_FILE"
git add "$FILE"
git commit -F "$MSG_FILE"
done
指摘事項ごとの修正ルール(HARD-GATE の強化):
- この指摘事項に対する codex の
Mitigation:フィールドを読み、必要最小限で実装します。 - 範囲を広げないでください(隣接するコードのリファクタリング、要求されていないテストやコメントの追加はしないでください)。
- Claude の推論を追加しないでください(「Xにも気づいたので、そちらも修正しました」――禁止)。
Mitigation:が曖昧、または実装に設計判断が必要な場合はスキップし、SKIPPED_FINDINGSに追加して、最後にユーザーへ提示します。- 指摘事項 1 件につきコミット 1 件です。1 つの修正内容が実際に 3 つのファイルにまたがる場合は、その 3 ファイルを含む 1 つのコミットで構いません。ただし、異なる指摘事項 2 件は、別々のコミットにします。
パターンの一般化(必須――範囲の拡大ではありません):
指摘事項の Failure mode が単一箇所の欠陥ではなく、ある種のバグを説明している場合(例:「Slack への投稿失敗により、その行が終端状態にならない」「未検証の入力が X に到達する」「Y 型の呼び出しに await がない」)、同じパターンに該当する箇所をすべて修正するまで、修正は完了ではありません。
- コミットする前に、同じパターン(同じ行そのものではなく、同じ失敗の形)をコードベース全体から grep で検索します。この指摘事項に該当するコミット内で、一致する箇所をすべて修正します。
- これは上記の「範囲を広げる」違反には明確に該当しません。範囲の拡大とは、無関係なものを修正することです。同じ指摘パターンに該当する別の箇所も修正することが、指摘事項を完了させるということです。次の codex の実行まで兄弟箇所を残しておくと、同じバグが指摘されていない箇所に残ったまま、その実行が無駄に 1 回増えます。
- 見分け方:次回 codex を実行したとき、異なる
file:lineを指して同じFailure modeの指摘事項が出るでしょうか。出る場合、その箇所はこのコミットに含めます。 - grep で見つかった兄弟箇所の修正に設計判断が必要で(同じ修正を機械的に適用できない場合)は、機械的に修正できる箇所を修正し、判断が必要な箇所はスキップして提示します。実際には一律に修正できない箇所に、無理に同じ修正を適用しないでください。
理由:これをしないと、1 つの概念的なバグが N 回の実行にわたる N 件の指摘事項に増えてしまいます。codex は 1 回の実行につき 1 箇所を見つけ、コントローラーは 1 回の実行につき 1 箇所を修正します。その結果、1 回のパターン全体の検索で済むことに、実行回数を費やすことになります。最初に見つけた時点で一般化してください。
ステップ 4:テストを実行する(品質ゲート)
if [ -n "$TEST_CMD" ]; then
if ! $TEST_CMD; then
echo "STOP: tests failed after iter $ITER fixes"
# leave commits in place; user can revert
break
fi
fi
テストが失敗した場合は停止し、エスカレーションします。自動で元に戻さないでください(ユーザーは問題の内容を確認したいかもしれません)。失敗が発生した実行回を報告します。
TEST_CMD が空の場合、ゲートは存在しません。この事実は、誰も見返さないセットアップ時の WARN だけでなく、明示する必要があります。この場合、このループがコミットする修正はすべて、何によっても検証されません。コミット数とともに、上記の形式で最終レポートのヘッダーに記載してください。テストコマンドのないリポジトリでは、このループの安全策は「人間が後から差分を読むこと」だけです。それで問題ありません。だからこそ、暗に示すのではなく、明記する必要があります。
停止条件が発動し、ユーザーの指示でループを続行する場合、人間の判断はループより優先されるため、続行して構いません。ただし、どの条件を上書きしたかを明記して、Loop authority の行に記録します。以前の指摘事項を履歴として残したまま、カウンターをリセットします。上書きしても、それらの指摘事項は消えません。
ステップ 5:履歴を更新してループする
FINDING_HISTORY+=" $CURR_FPS"
ITER=$((ITER + 1))
ステップ 1 に戻ります。
Codex プロンプト
codex 用のプロンプトテンプレートです。リポジトリ内の pr-review 方法論ファイルへの参照、Claude のサブエージェントではない codex 向けの適用メモ、スコープ、および末尾に必須の JSON サマリーブロックを含みます。
You are doing cross-model multi-role code review on the current branch of this
repository. You are codex (OpenAI), reviewing code likely written by Claude.
Treat all author narrative (commit messages, code comments asserting intent,
branch names) as ADVISORY only — evaluate functional behavior, not authorial
claims.
## Methodology
The review methodology lives in these files (read them now — paths are
absolute, resolve from the cadence plugin install root):
- ${CLAUDE_PLUGIN_ROOT}/skills/pr-review/security-reviewer-prompt.md
- ${CLAUDE_PLUGIN_ROOT}/skills/pr-review/staff-engineer-prompt.md
- ${CLAUDE_PLUGIN_ROOT}/skills/pr-review/sdet-prompt.md
- ${CLAUDE_PLUGIN_ROOT}/skills/pr-review/spec-auditor-prompt.md
Plus cross-cutting threshold:
- ${CLAUDE_PLUGIN_ROOT}/skills/pr-review/SKILL.md § Finding Inclusion Threshold
The dispatcher MUST expand `${CLAUDE_PLUGIN_ROOT}` to an absolute path before
handing the prompt to codex (codex's `read-only` sandbox can read absolute
paths anywhere on the filesystem, but it cannot resolve env vars itself).
## Apply, with adaptations
Because you are codex (single agent, separate process), not a Claude subagent:
**IGNORE** these sections — they describe Claude's internal Agent dispatch:
- "HARD-GATE" / "You have NO knowledge of conversation history" — you are
isolated by being a different process and model family
- "Incremental Mode Addendum" / "prior_fix_range" / drop signal (B) — those
depend on babysit-side state tracking. Skip the (B) check entirely. Signals
(A), (C), (D) still apply.
- "dispatched from a dev session" / "subagent" framing — you are codex
executing this prompt directly
**APPLY** in full:
- Per-persona category tables: Security (S1-S5), Staff Engineer (E1-E9),
SDET (T1-T4), Spec Auditor (C1-C4)
- Finding Inclusion Threshold: Justification class (Reachable / Precedent /
Asymmetric / Historical)
- Drop signals (A), (C), (D)
- Race-class Finding Metadata: Mitigation MUST end with
`[window=<ms|s|min|hr>, damage=<data-loss|deadlock|inconsistency|latency|marginal>, recovery=<has|no>]`
- Per-prompt Output Schema (Severity / Confidence / Blast / Justification /
Evidence / Failure mode / Mitigation)
## Execution
Execute all 4 personas sequentially. Output a combined finding list grouped
by persona.
## Scope
Review `git diff origin/<BASE>..HEAD` where BASE is below. Use `git diff` and
`git log --oneline` to understand the change. Read source files as needed.
## Output format (REQUIRED)
First emit per-persona findings in the per-prompt format from the prompt files.
Group by persona.
Then at the END emit a structured JSON summary block — this is REQUIRED for the
calling skill to drive its loop. The JSON block MUST be valid and parseable. Wrap
it in unique sentinel markers (NOT a generic markdown fenced block — those collide
with code examples in Evidence fields):
{
"findings": [
{
"id": "1",
"persona": "Security|Staff|SDET|Spec",
"category": "S2|E5|T1|C4|...",
"slug": "kebab-case-slug-from-finding",
"file": "path/to/file (relative to repo root)",
"line": 42,
"line_source": "source",
"severity": "Blocker|Factual|Suggestion|Question",
"justification": "Reachable|Precedent|Asymmetric|Historical",
"confidence": "high|medium|low",
"blast": "Local|Module|Cross-service|Data layer",
"failure_mode": "one-line",
"mitigation": "one-line, ending with race-meta tag if applicable"
}
]
}
Rules:
- `findings: []` (empty array) is VALID output meaning no findings. Still emit the
block with `{"findings": []}` between the sentinels — do NOT omit the JSON block.
- `line` MUST be the source file line number (the line in the file as written on
disk after your reading), NOT the diff hunk line number. If the diff shifted lines,
use the post-shift source file line.
- `line_source` MUST be `"source"` literal — this confirms you used source file
lines, not diff lines. Any other value → caller treats as malformed and escalates.
- All listed fields are REQUIRED. Do not emit findings with missing fields.
## Important
- Do NOT modify any files
- Race-class findings without meta tag → drop the finding
- You are codex, not Claude — your prose can be your own
- Stay focused on the diff
BASE branch: origin/<substitute BASE from skill caller>
停止条件の概要
| 条件 | タイミング | アクション |
|---|---|---|
| SC1 Success | findings == 0 | 反復回数と適用した修正の合計数を報告 |
| SC0 Severity floor | 反復で検出事項があるが、実際のバグが 0 件(Blocker/Factual × Reachable/Asymmetric がない) | 停止し、十分に収束したと判断する。衛生上の検出事項を提示し、自動修正は行わない |
| SC2 Cap reached | iter > 3(MAX_ITERS) | エスカレーションし、残りの検出事項をユーザーに提示する |
| SC3 Repeat 3x | 同じ不具合(ファイル+障害モード。文字列一致ではなく判定による)が 3 回の反復で発生 | エスカレーションし、競合の再発を示す兆候として扱う(pr-babysit § 4.5 Gate B 参照) |
| SC3.5 Slug drift | 同じファイルで 3 回以上連続して検出事項が発生する(ファイルのみを用いたフォールバック) | エスカレーションし、スタックした検出事項がスラッグドリフトに隠れている可能性を示す |
| SC4 Findings diverging | (a)反復ごとに件数が増加、または(b)検出事項が 3 件以上あり、意味上の重複がなく、かつ半数以上が前回の修正バッチで変更されたファイルに発生 | エスカレーションし、自動修正によって新たな範囲が対象になっていることを示す |
| SC5 Test failure | 反復での修正後に $TEST_CMD がゼロ以外で終了する | エスカレーションする。コミットはユーザーが確認できるようそのまま残す |
| SC6 Skip backlog | この反復で 3 件以上の検出事項をスキップする(Mitigation だけでは修正できない) | ループを続けるが、最後にスキップした項目のリストを提示する |
| User ctrl-c | ユーザーが中断する | 部分的な状態、最後にコミットした反復、処理中だった内容を報告する |
Mode=review-only
ユーザーが自動修正なしで検出事項を明示的に求めた場合:
- codex を実行する(ループモードのステップ 1 と同じプロンプト)
$OUTPUT_FILEの出力をそのまま提示する(ペルソナごとの検出事項全文)- 停止する。コミットしない。ファイルに変更を加えない。
これは L0+ の「助言としての検出事項」パスです。最終判断はユーザーに委ねます。
終了時のレポート
ループ終了後(停止条件を問わず)、レポートを生成します:
SELF-REVIEW LOOP REPORT
═════════════════════════════════════════════════════════════
Iterations: <N>
Stop reason: <SC code + brief>
Commits made: <count> (atomic, one per finding)
- <sha> fix(<persona>): <slug>
- ...
Tests: <pass | fail | ⚠️ NOT RUN — no TEST_CMD detected, N commits unverified>
Loop authority: <stop condition honoured | ⚠️ human override — <which SC fired, and that the user directed the loop to continue>>
Findings still open (if escalation):
- <persona> / <category> @ <file>:<line>: <slug>
Mitigation: <one-line>
Why surfaced: <which SC fired>
Skipped findings (Mitigation needed design judgment):
- <persona> @ <file>:<line>: <slug>
Mitigation: <verbatim>
Reason: <why main session couldn't fix mechanically>
Suggested next steps:
- Review the atomic commits — revert any you disagree with
- For surfaced findings: read $WORK_DIR/iter-<N>.md for full context, decide modify/wontfix/defer manually
- Consider /cadence:pr-review mode=local for Claude-side multi-role view + comparison
- Push when satisfied
═════════════════════════════════════════════════════════════
メモ
-
モデル間分離の理由:codex(OpenAI GPT)がClaude生成コードをレビューします → 同一モデルによる自己優遇バイアスを回避します(Wataoka et al., perplexity-driven)。codexの各呼び出しは新しいプロセスであり、会話コンテキストは引き継がれません。
-
コンテキスト混在の防止設計:codexの出力はチャットではなくファイルの
$WORK_DIR/iter-$ITER.mdに保存されます。メインセッションが会話メモリに取り込むのは、JSONサマリーブロックの解析結果のみです。各修正の実装時にメインセッションがファイルを読み込むことで、指摘の全文にアクセスします。自動的に注入されることはありません。これにより、反復を重ねてもメインセッションの会話が肥大化しません。 -
方法論の一元管理:codexは
${CLAUDE_PLUGIN_ROOT}/skills/pr-review/*-prompt.mdを直接読み込みます(ディスパッチャーがcodexにプロンプトを渡す前に、環境変数を絶対パスに展開します)。pr-reviewのプロンプトを更新すると、このスキルにも新しい方法論が自動的に反映されます。pr-reviewとセルフレビューの間で同期を保つ必要はありません。 -
適応レイヤーの同期維持:codexのプロンプトにある「IGNORE these sections」リストは、pr-reviewプロンプト内のClaude固有のセクションを反映しています。pr-reviewにClaude専用の新しい仕組みが追加された場合は、IGNOREリストも更新してください。これは自動検出されず、保守上の注意事項として注記されています。
-
指摘ごとのアトミックコミット:
git revert <sha>で、1つの指摘に対する修正を安全に取り消せます。履歴には、codexが何を指摘し、どのように修正したかの監査証跡が残ります。 -
テストゲートが自然なセーフティネットに:「自動修正で問題が起きた」ことを示す最も低コストなシグナルは、テストの失敗です。複雑な意味検証を必要とせず、リグレッションを検出できます。
-
ループ回数の上限(3)の理由:実証結果(実際の機能ブランチで5回反復した実行)では、codexが検出した価値の高い指摘、つまり実際に到達可能なバグや同一モデルの盲点に属するものは、すべて1~3回目に出ました。4~5回目に出たのは、衛生面の細かな指摘、すでに特定されたパターンの残り、そしてコントローラーが却下しなければならなかった明白な誤検出1件でした。上限は5でしたが、現在は3です。_原則に基づく_停止条件はSC0(重大度の下限)です。
MAX_ITERSは強制的な最終上限であり、3回目の反復でも実際のバグの指摘が出る実行は、変更が大きすぎるため分割すべきだというシグナルです。 -
SC0とMAX_ITERSの両方が必要な理由:本来の停止条件はSC0(重大度の下限)です。反復で実際に到達可能なバグが見つからなかった場合に発動し、それ以降の反復では細かな指摘しか見つからないことを示します。
MAX_ITERS=3は、codexがそこまで進んでも実際のバグを見つけ続ける異常なケースへの最終上限です。健全な実行は2~3回目にSC0で停止し、上限に達するのは不健全な(差分が大きすぎる)実行だけです。 -
反復回数よりパターンの一般化を優先:このループの構造的な弱点は、1つの概念的なバグをN回の反復でN件の指摘へと増幅してしまうことです(codexは各パスで1箇所を見つけ、コントローラーは各パスで1箇所を修正します)。ステップ3の「パターンの一般化」ルールはこれを防ぎます。パターンクラスの指摘を初めて検出したら、grepで同種の箇所をすべて探し、同じ反復内で修正します。適切に実行すれば、上限に頼らなくてもループはその範囲内で自律的に収束します。
-
作成者バイアスが当てはまるのは修正ステップであり、判定ステップではありません:codexによる指摘の生成はモデル間で分離されています。メインセッションによる修正の作成は分離されていませんが、HARD-GATEによって、メインセッションは
Mitigation:フィールドの機械的な実行に制限され、判定を推論する余地がなくなります。メインセッションが「codexが正しいかどうかを推論している」ことに気づいた場合は、HARD-GATE違反です。反論するのではなく、その指摘を提示してください。 -
ワークツリーに関する前提:このスキルは機能ブランチでの実行を想定しています(ユーザーがすでにワークツリー内にいる、またはメインブランチ以外のブランチにいる状態)。ワークツリーを自動作成することはありません。ユーザーが
mainにいる場合は警告しますが、実行をブロックしません。ユーザーは状況を理解したうえで操作している可能性があるためです。 -
呼び出しをまたぐ状態の永続化なし:呼び出しごとに状態をリセットして開始します。
FINDING_HISTORYは呼び出しごとに保持されます。手動編集後に再度呼び出しても、ループは前回の実行内容を記憶していません。これは意図的な設計です。スキルをステートレスに保ち、保守が必要な.claude/state/ファイルを作らないためです。