review-loop
レビュー→検証→修正の自動ループ。問題 0 件まで繰り返す。「/vibecorp:review-loop」「レビューして直して」と言った時に使用。
SKILL.mdskills/review-loop/SKILL.md
GitHub🔁 review-loop: レビュー→検証→修正の自動ループ
[!IMPORTANT] 変更差分に対してレビュー→検証→計画→修正のループを 問題 0 件になるまで 繰り返す。 最大 5 回でループを打ち切る(無限ループ防止)。上限到達時はコミットせず未解決の指摘一覧を報告する。 合議制は full プリセット かつ 差分キーワードヒット 時のみ起動する(standard 以下では起動しない)。
ultrathink
変更差分に対してレビュー→検証→計画→修正のループを実行する。
🌿 worktree モード
--worktree <path> が指定された場合、全操作を指定パス内で実行する。
- Bash: 全コマンドを
cd <path> && commandで実行する。 - Read/Write/Edit:
<path>/を基準とした絶対パスを使用する。 - サブスキル呼び出し:
--worktree <path>を引き継ぐ。 - 未指定時は従来通り CWD で実行する(後方互換)。
🔄 ループフロー
以下を問題が 0 件になるまで繰り返す。最大 5 回でループを打ち切る。上限到達時はコミットせず、未解決の指摘一覧を報告してユーザーに判断を委ねる。
1. レビュー実行
/vibecorp:review を実行してレビュー結果を取得する(worktree モードでは --worktree <path> を引き継ぐ)。
1b. 合議制レビュー(full プリセット限定)
.claude/vibecorp.yml の preset: full の場合、コード差分が特定領域に触れていれば、平社員合議制(×3 独立実行)+ C*O メタレビュー を追加で実行する。
/vibecorp:review(CodeRabbit CLI を含む)の 置き換えではなく追加レイヤーとして動作する。
/vibecorp:review: 汎用バグ検出・コード品質・ベストプラクティス- 合議制: プロジェクト固有ポリシー遵守(
SECURITY.md/POLICY.md/cost-analysis.mdの MUST / MUST NOT)
両者が同じ観点を指摘した場合、次ステップ「2. 妥当性検証」で .claude/rules/review-handling.md(捌き基準)と .claude/rules/severity/claude-action.md(severity 定義)に基づき重複排除する。
起動条件
# preset 取得
preset=$(awk '/^preset:/ { sub(/^preset:[[:space:]]*/, ""); print; exit }' .claude/vibecorp.yml)
presetがfull以外(minimal / standard / 未定義)の場合、このステップ全体をスキップする(既存挙動を維持)。preset: fullの場合、以下の差分検出に進む。
差分ベーストリガー表
git diff main...HEAD -U0 の出力に対して以下のキーワードを case-insensitive で検索し、ヒットした領域のみ起動する(複数該当時は該当全 C*O を並列起動)。
| 領域 | diff 内キーワード | 起動 C*O | 平社員合議 |
|---|---|---|---|
| 課金影響 | API call, model:, claude -p, ANTHROPIC_API_KEY, rate limit, 従量, トークン消費, npx, bunx |
CFO | accounting-analyst×3 |
| セキュリティ | auth, token, secret, encrypt, permission, credential, curl, wget, eval, exec |
CISO | security-analyst×3 |
| 法務 | dependency, LICENSE, third-party, 規約, プライバシー, 第三者, package.json, requirements.txt, go.mod |
CLO | legal-analyst×3 |
検出例:
git diff main...HEAD -U0 | grep -iE 'auth|token|secret|encrypt|permission|credential|curl|wget|eval|exec'
ヒットなしなら合議制はスキップする(既存挙動を維持)。
平社員 ×3 起動
該当領域の analyst を Agent tool で 同一プロンプト・独立に 3 回 同時並列で起動する(必須)。
複数領域が該当した場合、各領域の analyst×3 と対応する C*O を同時並列で起動する(例: 課金 + セキュリティなら accounting-analyst×3 + CFO と security-analyst×3 + CISO を並列実行)。
- 課金影響 →
.claude/agents/accounting-analyst.mdを ×3 - セキュリティ →
.claude/agents/security-analyst.mdを ×3 - 法務 →
.claude/agents/legal-analyst.mdを ×3
各 analyst に渡すプロンプトは skills/review-loop/prompts/agent-call-review-analyst.md を参照する。
C*O メタレビュー
3 件の独立結果を対応 C*O がメタレビューする(1 回)。
- 課金 →
.claude/agents/cfo.md - セキュリティ →
.claude/agents/ciso.md - 法務 →
.claude/agents/clo.md
メタレビュー観点:
- 3 件の独立結果で 共通する指摘 を抽出する(重要)。
- 1 件だけの指摘は「偽陽性の可能性」として慎重に扱う。
- 全会一致ルール(CISO / CLO): 1 人でも Major 以上を検出したら止める。
- 多数決ルール(CFO): 2/3 以上の指摘を採用する。
PR コメント投稿(Major 以上のみ)
CO メタレビューの結論が Major 以上 のとき、対応 CO が PR にコメント投稿する。
- PR が未作成(push 前)なら stdout に出力のみとする。
- Major 未満(Info / Trivial)はスキップする。
- 判定基準は
.claude/rules/review-handling.md(捌き基準)と.claude/rules/severity/claude-action.md(severity 定義)に準拠する。
重複防止のため、マーカー [<C*O>-consensus-review](例: [CFO-consensus-review])で既存コメントを検索して upsert する。
# owner/repo を取得
repo=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')
pr_num=$(gh pr view --json number --jq '.number')
marker="[CFO-consensus-review]" # C*O に応じて変える
existing_id=$(gh api "repos/${repo}/issues/${pr_num}/comments" --paginate \
--jq '.[] | select(.body | startswith("'"$marker"'")) | .id' | head -1)
if [ -n "$existing_id" ]; then
gh api --method PATCH "repos/${repo}/issues/comments/${existing_id}" \
-f body="${marker}"$'\n\n'"${summary}"
else
gh pr comment "${pr_num}" --body "${marker}"$'\n\n'"${summary}"
fi
1c. intent ラベルの取得(Issue 側から直接参照)
レビュー判定(intent × severity)の SoT は Issue ラベル。PR には intent ラベルを付与しないため(Issue #575)、Issue 番号を解決して gh issue view --json labels で intent を取得する。
4 段フォールバック:
| 優先 | 取得経路 | コマンド例 |
|---|---|---|
| 1 | closingIssuesReferences(PR 作成後のみ) |
gh pr view --json closingIssuesReferences --jq '.closingIssuesReferences[0].number // empty' |
| 2 | PR 本文 grep(PR 作成後のみ) | pr-issue-link-check.yml 互換正規表現 (close[sd]?|fix(es|ed)?|resolve[sd]?|refs?)[[:space:]]+#([0-9]+) で PR 本文を解析。最初のマッチを採用 |
| 3 | ブランチ名(PR 未作成時はここから開始) | git branch --show-current から dev/<num>_* パターンの <num> 抽出 |
| 4 | 空(severity-only fallback) | warning ログ + severity-only 判定モードに切替 |
# PR 作成後: closingIssuesReferences → PR 本文 → ブランチ名
# PR 未作成(push 前): ブランチ名から直接
# PR 番号取得(無ければ空、stderr ノイズは無害)
PR_NUM=$(gh pr view --json number --jq '.number // empty')
ISSUE_NUM=""
if [ -n "$PR_NUM" ]; then
ISSUE_NUM=$(gh pr view "$PR_NUM" --json closingIssuesReferences --jq '.closingIssuesReferences[0].number // empty')
if [ -z "$ISSUE_NUM" ]; then
PR_BODY=$(gh pr view "$PR_NUM" --json body --jq '.body')
# #N 形式 + GitHub URL 形式の両対応(pr-issue-link-check.yml と互換)
ISSUE_NUM=$(printf '%s' "$PR_BODY" \
| grep -oiE '(close[sd]?|fix(es|ed)?|resolve[sd]?|refs?)[[:space:]]+(#[0-9]+|https?://[^[:space:]]+/issues/[0-9]+)' \
| head -1 \
| grep -oE '[0-9]+$')
fi
fi
if [ -z "$ISSUE_NUM" ]; then
BRANCH=$(git branch --show-current)
ISSUE_NUM=$(printf '%s' "$BRANCH" | grep -oE '^dev/([0-9]+)_' | grep -oE '[0-9]+')
fi
# 数値検証を経た上でのみ gh に渡す
PR_INTENT=""
if [ -n "$ISSUE_NUM" ]; then
if [[ "$ISSUE_NUM" =~ ^[0-9]+$ ]]; then
PR_INTENT=$(gh issue view "$ISSUE_NUM" --json labels --jq '[.labels[].name | select(startswith("intent/"))][0] // empty')
else
echo "[WARN] ISSUE_NUM が数値以外('$ISSUE_NUM')。intent 取得をスキップして severity-only fallback に切替" >&2
fi
fi
severity-only fallback の挙動:
Issue 番号 / intent ラベルが解決できない場合、PR_INTENT が空となる。この場合は intent 重視軸判定が不可能となるため、.claude/rules/review-handling.md の判定基準を severity のみで 適用する。
- Critical / Major: 通常通り修正対象(intent 問わず必ず対応)。
- Minor / Trivial / Info: 全スキップ(intent 重視軸該当判定が不能のため保守的に倒す)。
warning ログ [WARN] Issue 番号 / intent ラベルが解決できませんでした。severity-only fallback で Critical / Major のみ修正対象とします を出力する。
2. 妥当性検証
.claude/rules/review-handling.md(intent × severity の捌き基準)と .claude/rules/severity/claude-action.md / .claude/rules/severity/coderabbit.md(severity 定義)に従い、/vibecorp:review と合議制(full プリセット時)の両方の指摘を統合して分類する。判定の入力としては 1c で取得した PR_INTENT を使う(PR ラベルではなく Issue ラベル直接参照)。
- 同一観点の重複は 1 件にまとめる(出典は両方を残す)。
- Critical / Major は intent 問わず必ず対応、Minor / Trivial / Info は intent の重視軸該当時のみ対応する。
PR_INTENTが空(severity-only fallback)の場合は Minor 以下を全スキップする。
出力形式
## 修正すべき指摘
1. [ファイルパス:行番号] 指摘内容の要約(出典: /vibecorp:review, CFO-consensus)
2. ...
## 却下した指摘
1. [指摘内容の要約] — 却下理由
2. ...
要修正 0 件ならループ終了。
3. 修正計画
要修正リストに対して、各指摘の具体的な修正計画を策定する。このステップではコードの変更は行わない。
手順:
- 指摘箇所の実コードと周辺コードを読む。
- 既存の類似実装パターンを確認する。
- 修正による影響範囲を特定する。
- 具体的な修正手順を策定する。
出力形式
## 修正計画
### 1. [ファイルパス:行番号] 指摘内容の要約
- **修正内容**: 何をどう変更するか
- **影響範囲**: 変更が影響する他のファイル・テスト
- **注意点**: 修正時に気をつけるべきこと
4. 修正実行
修正計画に従ってコードを修正する。
- 計画に記載された範囲のみを変更する(計画外の変更は行わない)。
- 修正後、関連するテスト・lint を実行して通過を確認する。
出力形式
## 修正内容
1. [ファイルパス] 修正内容の要約
2. ...
## テスト結果
- {テスト名}: PASS/FAIL
5. レビュー完了スタンプの生成
ループが問題 0 件で正常終了した場合、PR 作成を許可するスタンプを生成する。スタンプは ~/.cache/vibecorp/state/<repo-id>/ 配下に作成される(.claude/ 配下への書込確認プロンプトを回避)。
. "$CLAUDE_PROJECT_DIR/.claude/lib/common.sh"
STAMP_DIR="$(vibecorp_stamp_mkdir)"
touch "${STAMP_DIR}/review-ok"
worktree モードの場合:
. "<path>/.claude/lib/common.sh"
STAMP_DIR="$(vibecorp_stamp_mkdir)"
touch "${STAMP_DIR}/review-ok"
上限到達で打ち切った場合はスタンプを生成しない。
6. 結果報告(ループ終了後)
全イテレーションの結果をまとめて報告する。
## review-loop 結果
### レビューモード
- preset: {minimal/standard/full}
- 合議制: {起動/スキップ} (full プリセット時のみ判定)
- 起動 C*O: {CFO / CISO / CLO}(起動時のみ)
### 修正した指摘
- {ファイル:行番号}: {指摘内容} → {修正内容}(出典: /vibecorp:review / {C*O}-consensus)
### 却下した指摘
- {指摘内容} — 理由: {却下理由}
### サマリ
- ループ回数: {n}回
- 修正: {n}件
- 却下: {n}件
- 最終レビュー: 問題0件
🚧 制約
--force、--hard、--no-verifyは使用しない。git add/git commit/git pushは実行しない(呼び出し元に委ねる)。- 最大 5 回でループを打ち切る(無限ループ防止)。
- 修正前に必ず関連ファイルを読み込む。
- 合議制は full プリセット かつ 差分キーワードヒット 時のみ起動する(standard 以下では起動しない)。