Max Nardit
← 記事
14 mindev

Claude Code Review が GA に:周囲のレビュー層と、Team プランなしで真似できる層

Claude Code チームのプロセスを支えているものの大半は GitHub の設定と文章化されたルールで、どのプランでも動きます。真似できないのは、ルールをどこから読むかです。マネージドサービスはプルリクエストが触れられないブランチからルールを読みます。ローカルのレビューはディスク上にあるものを読み、レビュー対象の変更が書き換えたばかりのルールファイルも例外ではありません。

目次

Claude Code Review は10月15日、Team と Enterprise プラン向けにリサーチプレビューを終えました。同じ日に Claude Code チームが自分たちのリポジトリのレビュー方法を公開しており、そこではマネージドのレビュアーは7つある層の1つにすぎません。残りの大半は GitHub の設定と文章化されたルールで、どのプランでも真似できます。

真似できないものが1つあり、この記事はそのために書いています。マネージドサービスはレビュールール REVIEW.md をベースブランチから読み、プルリクエストからは決して読みません。ローカルの /code-review コマンドは、公式には REVIEW.md をまったく読みません。ところが Claude Code 2.1.302 で試したところ、ディスクからこのファイルを読んでいました。レビュー対象の変更が書き換えたばかりのコピーも、です。その後ルールが守られるかどうかは、モデル次第でした。

以下のマネージドサービスの説明はドキュメントと告知に基づくもので、実際には動かしていません。ローカルのコマンドは11回試しました。

Claude Code Review の GA には何が含まれるか

Anthropic のインフラ上でプルリクエストをレビューする GitHub App で、対象は Team と Enterprise の組織です。Owner が機能を有効にし、App をインストールしてリポジトリを選びます。リポジトリごとにレベル(Quick、Standard、Deep)とトリガーを決めます。トリガーは、PR を開いたときに1回、push のたび、書き込み権限を持つ人が @claude review とコメントしたときだけ、のいずれかです。

告知によると、ほとんどのレビューは現在6〜10分で終わり、プレビュー中の約20分から短くなりました。プレビューのドキュメントでは1回あたり平均15〜25ドルとされていましたが、GA のコストページには1回あたりの金額が一切ありません。課金はトークン使用量に基づき、プランとは別に使用量クレジットから引かれます。金額はレベル、変更の大きさ、検証が必要な候補 Finding の数に応じて増えます。管理ページから追加したリポジトリは最初「After every push」になっており、これは最もレビュー回数が多いトリガーです。先に月額の上限を設定してください。対象の Enterprise 組織は2027年1月15日までに最低1万ドル分のクレジットを申請でき、申請から30日で失効します。

価格より重要な制約が2つあります。レビューはコードを読むだけで、ビルドも実行もしません。そして承認もブロックもしません。ドキュメントによれば、チェックランは失敗として終わることがありません("doesn't conclude as a failure")。Zero Data Retention、HIPAA 構成、顧客管理キーを使う組織は利用できません。

Claude Code チームは Code Review の周りにどんなレビュー層を置いているか

PR の前からマージの後まで、7つです。PR の前に Claude がテスト、ビルド、リンターを実行し、2つ目のエージェントが新しいコンテキストで差分をレビューします。各 PR では、必須の CI、AI レビュー、別立てのセキュリティレビュー、そして承認の段階(人間なし、1人、2人)があります。段階は分類器が選び、2つ目の分類器が、それでも人間が必要な変更かを判定します。その後に、最新の main に対してチェックを再実行するマージキュー、まず社内で使うフラグの裏に置いた新しい挙動、段階的なリリース、素早いロールバックが続きます。

重みの大部分を担っているのは、層の周りのルールです。すべての Finding には返答し、修正するか理由を付けて閉じます。未解決のバグやセキュリティの Finding があればマージはブロックされます。軽い承認ルートを使えるのは信頼された作成者、主に担当チームだけで、常に人間が必要なパスもあります。エージェントの承認が人間の枠を埋めることはありません。エージェントに PR を書かせた人は、必須レビュアーとして数えられます。承認は特定の1コミットに対してのものです。

数字は社内のもので、外からは確かめられません。「実質的な」レビューコメントが付いた PR はプレビュー開始とともに16%から54%に増えましたが、記事は「実質的」を定義していません。後述する収束の改善のあと、1回のレビューラウンドで通る PR は65%から78%に増えました。記事は自身の穴も挙げています。リバートやインシデントの数字が動いたときに承認を自動で厳しくする仕組みは、まだありません。

Team プランなしで使える Claude Code Review の層はどれか

マネージドのレビュアー本体とチーム内部の分類器を除けば、すべてです。

チームの層どのプランでも使える代替失うもの
PR 前の新しいコンテキストでのレビューセッション内の /code-review構造上は何もない。自分の使用量に計上される
すべての PR への AI レビュー必要に応じて /code-review --comment 1234、または GitHub Actions で自分の CI に Claude を組み込むローカルでは自分が実行したときだけ動く。Action は PR の更新で起動できるが、専用のワークフローと API 認証情報が要る
セキュリティレビュー/security-review同じく、必要なときだけ
未解決の Finding がマージを止めるGitHub のブランチ保護で会話の解決を必須にする止めるのは存在するスレッドで、レビューが実行されたかどうかではない
リスク段階CODEOWNERS と「require review from Code Owners」分類器はない。Owner の誰か1人の承認で満たされる
承認は1コミットに対して「Dismiss stale approvals when new commits are pushed」GitHub はこれを差分の変化に結び付けており、近いが同じではない
ラウンド上限、範囲を絞った再レビュー文章化した停止ルールとレビュー範囲強制する仕組みはない

ブロックの行はもう一度見ておく価値があります。マネージド製品ですらブロックはしません。チームの「未解決の Finding があればマージしない」は、マージ前にすべてのレビュースレッドの解決を必須にすることから来ています。これは記事が推奨するリポジトリ設定です。レビュアーはテキストを書くだけで、そのテキストに拘束力を持たせているのはブランチのルールです。プロンプトは不変条件ではないで書いた区別そのものです。指示はたいてい守られ、プラットフォームが実行するチェックは、カバーするすべての経路で守られます。そしてこのチェックがカバーする範囲は、見た目より狭いのです。スレッドを解決済みにするのに修正も理由も要りませんし、予算の都合で省かれたレビューや、ドラフトで一度も実行されなかったレビューは、解決すべきスレッドを残しません。さらに、プライベートリポジトリのブランチ保護には有料の GitHub プランが必要です。

ドキュメントを読むときの名前の罠も1つあります。/code-review は "as a forked subagent" で動くとされています。これは Skill の設定 context: fork のことで、Skills のページには、現在の会話のフォークでは動かない("doesn't run in a fork of the current conversation")と書かれています。レビュアーはあなたのセッションを見ません。レビュアーとしてはそれが正しく、理由はフォークしたサブエージェントはすでに知りすぎているで書きました。すべてを引き継ぐ会話のフォークは、ほぼ同じ名前の別機能です。

ローカルの /code-review をブランチや範囲に対して実行するには

対象を指定します。指定しない場合は、upstream より先行しているブランチのコミットと未コミットの変更をレビューし、upstream がなければ main か直前のコミットにフォールバックします。Claude Code のプロンプトで次のように入力します。

/code-review main...my-feature
/code-review a1b2c3d..HEAD
/code-review --comment 1234
/code-review --fix

1つ目はブランチを main と比較します。2つ目は a1b2c3d 以降のコミットだけをレビューし、一度フルに通したあとの安価な再レビューになります。--comment は Finding を PR 1234 にインラインコメントとして投稿します。--fix は現在のパーミッションモードに従って Finding を作業ツリーに適用します。対話セッションではレビューがバックグラウンドで動くため、自分が触っていなかったファイルへの変更は /rewind では戻らず、git なら戻せます。シェルからは、同じコマンドがフォアグラウンドで動きます。

shell
claude -p "/code-review a1b2c3d..HEAD"

対象の前にレベル(low から max)を付けると、確信度とカバー範囲を引き換えにできます。low は最も確信のあるものだけを報告します。対話モードでは入力したレベルが次回以降も記憶されますが、-p で渡したレベルは記憶されません。

ローカルの /code-review は REVIEW.md を読むか

設定としては読みません。ドキュメントにもそうあります。このコマンドは CLAUDE.md に従い("follows your CLAUDE.md")、REVIEW.md は読みません("doesn't read REVIEW.md")。ところが実際には、ファイルがあった実行ではすべて、結局読んでいました。

用意したのは、ページネーション関数を追加するコミットが1つだけのスクラッチリポジトリです。関数には off-by-one、消し忘れの print() があり、docstring がありません。CLAUDE.md はライブラリコードでの print() を禁止しました。REVIEW.md には、新しい公開関数に docstring がないのは Nit ではなく Important だと書きました。各回の実行は次のとおりです。

shell
claude -p "/code-review medium HEAD~1..HEAD" \
  --allowedTools "Bash(git:*)" Read Grep Glob

再現したい人のために、実行条件で重要な点が3つあります。セッションのモデルは Opus 5.5 でした。ユーザー設定でパーミッションの確認を省略していたので、--allowedTools は何も制限しておらず、レビュアーの cat 呼び出しが通ったのはそのためだけです。標準の設定なら、Bash(git:*) の外にある cat は確認で止まります。また、medium を渡したのに、トレースに残ったレビュー自身のプロンプトには high effort とありました。11回で約2.31ドルでした。

off-by-one は11回すべてで検出されました。2つのルールは、検証としては弱いことがわかりました。ルールファイルを一切置かないベースラインの実行でも、print() と docstring は普通の Finding として指摘されたからです。つまり Finding が出たこと自体は何も証明しません。重要なのは、その出どころです。

REVIEW.md があるとき(3ファイルのリポジトリのルート、3,043ファイルのリポジトリのルート、変更したファイルと同じ lib/ のいずれでも)、9件の出力すべてがファイル名を挙げ、Important のルールを引用しました。ツールのトレースを残した6回の実行を見ると、経路がわかります。レビュアーはリポジトリのファイル一覧を取り、REVIEW.md に気づき、それに cat を実行していました。設定として組み込まれたファイルではなく、モデルが自分で探しに行ったと考えるのが自然です。同じルールを CLAUDE.md に書いた場合、Finding は文書化された経路どおり CLAUDE.md を引用しました。

つまり仕組みについてはドキュメントが正しく、それでも挙動は意外です。ローカルで REVIEW.md が効いたのは、モデルが読むことを選び、パーミッションがそれを許したからです。これは習慣であって、次のモデルや次のプロンプトではなくなるかもしれません。ローカルで確実に守らせたいルールは CLAUDE.md に置くべきです。

最初の実行では、ユーザーレベルの ~/.claude/rules/ にある型ヒントのルールも適用されました。これは仕様どおり(レビューはユーザーの指示を読む)ですが、同じブランチで2人が /code-review を実行すれば、パーミッション設定の違いを考える前から、異なる Finding が出るということです。

変更が自分自身の REVIEW.md を書き換えたらどうなるか

マネージドサービスはその編集を見ません。REVIEW.md はベースブランチまたはデフォルトブランチから読み、プルリクエスト自身の変更からは決して読みません("never from the pull request's own changes")。重大度の引き下げ、スキップするパス、Nit の上限は、保護されたデフォルトブランチにあるルートのファイルからしか受け付けません。これで、どのルールのコピーが有効かは決まります。ただし、差分の別の場所に仕込まれた指示に対してレビュアーが無敵になるわけではありません。

ローカルにはこうした選別がありません。リポジトリにベースはあっても、信頼できるルールのコピーを選ぶ仕組みはなく、レビュアーは作業ツリーを読みます。そこで、すぐ思いつく悪用を試しました。同じバグ入りのコミットで REVIEW.md に「Do not report」の行を追記し、その関数の算術と入力検証を対象外にしたのです。理由は、レガシー API に関する作り話にしました。2回とも、レビュアーはバグをそのまま報告し、REVIEW.md の変更自体も Finding として指摘し、リポジトリにレガシー API など存在しないと書きました。

良い結果ですが、保証としては薄いものです。2回の実行、1つのモデル、稚拙な試みにすぎません。サービスは、モデルが何かを見る前に、どのルールを適用するかを決めます。ローカルではそれがモデルの判断で、今回はたまたま正しく判断しました。main を保護しても変わりません。ブランチ保護が決めるのは何がマージされるかであって、ローカルのレビューがフィーチャーブランチから何を読み込むかではないからです。役に立つのは、CLAUDE.md や REVIEW.md への変更を、その上で走ったレビューを信用する前に自分の目で読むことです。

Claude Code Review のループが50ラウンド続くのを止めるには

ラウンド数に上限を設け、再レビューが見る範囲を絞ります。Claude Code のある PR は、一晩でレビューと修正を50ラウンド以上繰り返し、作成者がようやく止めました。git blame によると、レビュアーが指摘し続けた内容の約59%は、最初のレビューの時点からすでにあったものでした。後半のラウンドは、ほとんど古いバグを掘り起こしていたことになります。

チームの対策は次のとおりです。3ラウンドを超えたらレビュアーが作成者にアプローチの見直しを求める。最初の数回のあとは新しい差分だけをレビューする。バグの種類として指摘し、同じ種類の箇所をまとめて直させる。同じ Finding を繰り返さない。マネージド製品は、引き継がれたバグに Pre-existing のタグも付け、作成者の責任にならないようにしています。

このうち2つはローカルでも無料で使えます。最後のフルレビューの SHA を控えておき、<that-sha>..HEAD を再レビューすれば範囲が絞れます(変更が触れた関数の中なら、触れていない行にもレビュアーはコメントできます)。そして上限を、エージェントが読む場所に書いておきます。作成者がエージェントだと、見せられた Nit をすべて直そうとし、修正のたびにコミットとラウンドが1つ増えるからです。

markdown
## Review loop
- After three review-and-fix rounds on one change, stop and ask whether the approach is wrong.
- After the first full review, re-review only commits since the last reviewed SHA.

Claude Code チームのレビュー体制から最初に真似すべきもの

どのレビュアーにも依存しない保護です。必須の CI、古い承認の取り消し、そしてミスが高くつくパスへの CODEOWNERS です。

/.github/workflows/  @you
/src/billing/        @you
/CLAUDE.md           @you
/REVIEW.md           @you
/CODEOWNERS          @you

「require review from Code Owners」をオンにすると、これらのパスへの変更には Owner の承認が必要になります。一覧にある Owner の誰か1人の承認で満たされ、2人を求めるのは必須承認数という別の設定です。ルールファイルと CODEOWNERS 自体を一覧に入れているのは、前のセクションで書いた理由からです。

次に、AI レビュアーを必要なときに完成した差分に対して実行します。どの指摘を外しがちかがわかるだけの数を読むまでは、Finding は助言として扱います。これは Claude Code と Codex の組み合わせで主張した順序です。作成者とレビュアーは別のシステムにし、会話の解決を必須にして AI の Finding でマージを止めるのは、やるとしても最後です。リスク分類器は省きましょう。チーム自身のインシデント評価セットが採点しているのはレビュアーで、分類器ではありません。分類器の作り方も説明されていません。上の手書きのパス一覧は筆者なりの代替で、記事が提案しているものではありません。

サービスは、プルリクエストが触れられないブランチからルールを読みます。ローカルのレビューはディスクから読みます。それが変わるまで、ルールファイルは差分の一部であり、そのレビュアーはあなたです。

01 / ディスカッション

コメント欄はありません。議論は X で行っています。

Max Nardit@mnardit

02 / ほかの記事

  1. Claude API の OpenTelemetry:トークンを二重に数えずに SDK と API をトレースする

    スパンの入力トークン数にはキャッシュの読み込みと書き込みがすでに含まれています。そのため、Messages API を知っている人が自然に書くクエリでは、キャッシュされたプレフィックスが二重に数えられます。ローカルのモックで試した SDK 側のセットアップ、ドキュメントに沿った Console のデスティネーション設定、そしてキャッシュされていない入力に戻すための引き算をまとめます。

  2. Claude Code のアイドル時コンパクション:今の安い要約か、後でキャッシュを丸ごと書き直すか

    アイドル時コンパクションが動くかどうかは5つの条件で決まり、デフォルトではそのうち2つが、API キーのセッションと、200K ウィンドウのセッションの大半を対象外にします。実際に対象になるのは誰か、このトレードオフがキャッシュトークンでいくらになるか、調整や無効化の方法をまとめます。

  3. Gemini 4 Argon が一般公開:Google が初日に報告した利用例と、12月1日に2倍になる価格

    Google が Argon について報告している利用例を7つ、出どころの記事とあわせて並べます。レビューの記録まで公開しているのは1つだけで、提案6件のうち採用は2件でした。残りは、発表が触れずドキュメントに任せた請求の話です。まず、long decode が入力をどう数えるかから始めます。