チームに 15 人のエンジニアがいるとします。そのうち 3 人は Claude Code を毎日使っている。残りの 12 人は、会社の IT 部門に管理された Windows ラップトップを使っていたり、ターミナルの設定など一度も触ったことのないフロントエンド担当者だったりする。PR が来るたびに、変更をすべてレビューしてほしい — Claude ユーザーがたまたまオンラインにいるときだけ、ではなく。
そのために存在するのがヘッドレスモードです。
claude -p(--print フラグ)は、Claude Code を非対話形式で実行します。プロンプトとコンテキストを渡すと、出力を生成して終了する。TTY 不要。承認プロンプトなし。人間の介入なし。GitHub Actions に組み込んで PR の diff を渡せば、チームの誰一人 Claude Code をインストールしていなくても、レビューコメントが自動的に投稿されます。
そのパイプラインの作り方を紹介します。
基本的な考え方:diff を Claude に渡す
根本のパターンはシンプルです:
- GitHub Actions のジョブで PR の diff を取得する
- レビュープロンプトと一緒に
claude -pに渡す - 出力をキャプチャする
- PR コメントとして投稿する
diff には Claude が変更内容を理解するために必要な情報がすべて含まれています。Claude にブランチをチェックアウトさせたりコードを実行させたりする必要はない — diff と、プロンプトと、明確なレビュー基準があれば十分です。
# もっともシンプルな形
git diff origin/main...HEAD | claude -p "Review this diff for bugs and security issues" \
--output-format text \
--max-turns 3
これが出発点です。以下はすべてこれをベースに発展させたものです。
GitHub Actions ワークフローを作る
PR のオープンと同期イベントをトリガーとして、Claude レビューを実行し、結果をコメントとして投稿する完全なワークフローを示します:
# .github/workflows/claude-pr-review.yml
name: Claude PR Review
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # 正確な diff のためにフル履歴が必要
- name: Install Claude Code
run: npm install -g @anthropic-ai/claude-code
- name: Get PR diff
id: diff
run: |
git fetch origin ${{ github.base_ref }}
DIFF=$(git diff origin/${{ github.base_ref }}...HEAD -- . \
':(exclude)*.lock' \
':(exclude)*.min.js' \
':(exclude)dist/**' \
':(exclude)*.snap')
echo "DIFF<<EOF" >> $GITHUB_OUTPUT
echo "$DIFF" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Run Claude review
id: review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
REVIEW=$(echo "${{ steps.diff.outputs.DIFF }}" | claude -p \
"You are a code reviewer. Review the following git diff carefully.
Focus on:
1. Correctness bugs — logic errors, off-by-one errors, null pointer risks
2. Security issues — injection risks, auth bypasses, unsafe data handling
3. Performance problems — N+1 queries, unnecessary allocations, blocking calls
4. Coding standards — naming, error handling, missing tests for new behavior
Be direct. Skip praise. For each issue, state:
- The file and approximate line
- What the problem is
- Why it matters
- A concrete fix suggestion
If the diff looks clean, say so briefly and mention one thing that's done particularly well.
Diff to review:
$(cat)" \
--output-format text \
--max-turns 5)
echo "REVIEW<<EOF" >> $GITHUB_OUTPUT
echo "$REVIEW" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Post review comment
uses: actions/github-script@v7
with:
script: |
const review = `## Claude Code Review\n\n${{ steps.review.outputs.REVIEW }}\n\n---\n*Automated review by Claude Code headless mode*`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: review
});
いくつか注意点があります:
fetch-depth: 0 は必須です。 フル履歴がないと、git diff origin/main...HEAD が失敗するか、誤った出力を返します。デフォルトのシャロークローンは、現在のコミットしか取得しません。
diff はロックファイルとビルド成果物を除外しています。 ロックファイルの変更をレビューしても意味がない。:(exclude) のパス指定で、Claude に届く前にフィルタリングしています。
--output-format text はインタラクティブモードを無効にします。 このフラグがないと、Claude Code は TTY がないことを検出してエラーになる場合があります。CI 環境では必須です。
大きな diff への対処
数百ファイルに触れる PR はトークンの上限に達します。Claude にはコンテキストウィンドウがあり、10,000 行の diff はそれを超えます。対処法をいくつか紹介します:
方法 1:ファイルタイプ別に分割する
コードベースの異なる部分を別々にレビューする:
# バックエンドの変更のみレビュー
git diff origin/main...HEAD -- 'src/api/**' 'src/services/**' | \
claude -p "Review this backend diff for security and correctness" \
--output-format text --max-turns 3
# フロントエンドの変更のみレビュー
git diff origin/main...HEAD -- 'src/components/**' 'src/pages/**' | \
claude -p "Review this frontend diff for accessibility and UX issues" \
--output-format text --max-turns 3
方法 2:stat でまずトリアージする
最初に diff の統計を取り、リスクが高そうなファイルだけ詳細展開する:
# 統計サマリーを取得
STAT=$(git diff origin/main...HEAD --stat)
# 変更が最も多いファイル(リスクが高い可能性)の完全な diff を取得
TOP_FILES=$(git diff origin/main...HEAD --stat | \
grep -v "changed" | sort -t'|' -k2 -rn | head -5 | \
awk '{print $1}')
for file in $TOP_FILES; do
git diff origin/main...HEAD -- "$file" | \
claude -p "Review this file's changes: $file" \
--output-format text --max-turns 2
done
方法 3:行数の上限を設けて警告する
diff が閾値を超えたら、フルレビューをスキップしてノートを投稿する:
DIFF_LINES=$(git diff origin/main...HEAD | wc -l)
if [ "$DIFF_LINES" -gt 2000 ]; then
echo "PR diff is too large for automated review ($DIFF_LINES lines). Manual review required."
else
# Claude レビューを実行
fi
大きな PR はそもそもコードの匂いであることが多い。ボットが「この PR は大きすぎて自動レビューできません」とコメントするのは、それ自体有用なシグナルです。
Claude に何をレビューさせるか
レビューの質は、ほぼすべてプロンプトにかかっています。漠然としたプロンプトは漠然としたレビューを生む。具体的な基準が具体的な指摘を生む。
セキュリティ重視のレビュー
Review this diff for security vulnerabilities.
Check specifically:
- SQL injection: any string interpolation in database queries
- XSS: user input rendered without sanitization
- Authentication: endpoints missing auth middleware
- Secrets: any hardcoded credentials, API keys, or tokens
- SSRF: any URL construction from user input
- Path traversal: file operations using user-supplied paths
- Dependency risks: new npm/pip packages with known CVEs
For each finding, rate severity: Critical / High / Medium / Low.
Skip Low severity unless there are no higher ones.
パフォーマンス重視のレビュー
Review this diff for performance issues.
Check specifically:
- N+1 queries: loops that trigger database calls
- Missing indexes: new queries filtering on non-indexed columns
- Synchronous blocking: I/O operations on the main thread (Node.js) or event loop
- Memory leaks: event listeners or intervals not cleaned up
- Unnecessary re-renders: React state changes that cause full subtree renders
- Large bundle additions: any new imports that significantly increase bundle size
If you can't tell without runtime data, say so — don't guess.
コーディング規約のレビュー
Review this diff against our team's standards.
Our conventions:
- Functions over 30 lines should be broken up
- All async functions must have try-catch or propagate errors explicitly
- No console.log in production code (use our logger)
- React components must have prop types or TypeScript interfaces
- New utility functions need unit tests in the adjacent __tests__ folder
- Database queries must go through the repository layer, not called directly from controllers
Flag violations with the specific rule they break.
これらを組み合わせることもできます。トレードオフはコスト — 基準が増えるほど、トークンとターン数が増えます。
--max-turns によるコスト管理
レビューを実行するたびに API トークンを消費します。大規模なチームで PR が頻繁に来ると、コストはすぐに積み上がります。最も重要なコントロールは --max-turns です。
Claude Code は反復的なマルチステップのワークフロー向けに設計されています。PR レビューの場合、多くのターンは必要ない — diff を読んで、レスポンスを生成して、終わり。実際、ほぼすべてのレビュータスクで 3〜5 ターンで十分です。
# タイトな予算 — 最大 3 ターン
run: |
claude -p "$REVIEW_PROMPT" \
--output-format text \
--max-turns 3
# 中程度の予算 — 複雑な diff のフォローアップ分析に有用
run: |
claude -p "$REVIEW_PROMPT" \
--output-format text \
--max-turns 8
その他のコスト管理:
特定のラベルのみ実行する。 些細な PR まで毎回レビューしない。ラベルを付けた PR だけ Claude をトリガーする:
on:
pull_request:
types: [labeled]
jobs:
review:
if: github.event.label.name == 'needs-review'
並行実行制限を設ける。 5 つの PR が同時にオープンされても、全部並行して Claude を動かす必要はないでしょう:
concurrency:
group: claude-review-${{ github.repository }}
cancel-in-progress: false
# 注意: レビューは cancel-in-progress しない — すべての PR をレビューしたい、
# ただし同時に実行しないというだけ
Anthropic コンソールで月次支出アラートを設定する。 予算上限を設けておけば、ワークフローが暴走しても一晩でアカウントが空になる事態を防げます。
レビュー疲れを防ぐ:ノイズのフィルタリング
放置すれば、Claude はすべての diff に問題を見つけます。既存の技術的負債を抱えるコードベースでは、PR ごとに 20 件のコメントが付くかもしれない。それはノイズであり、エンジニアはボットを無視し始めます。
効果的なアプローチが 2 つあります:
変更行のみにスコープを絞る。 プロンプトでこれを明示する:
Only flag issues in the lines that were changed in this diff (marked with +).
Do not comment on pre-existing code that wasn't modified.
実行可能な指摘のみ要求する:
Only include findings where you can suggest a specific fix.
If you see a potential issue but aren't sure, skip it rather than adding speculation.
重大度の閾値を設定する:
Report Critical and High severity issues only.
Skip Medium and Low unless the PR has no higher-severity findings.
目標は、エンジニアが実際に読むレビューを作ること。鋭い 5 件の指摘は、曖昧な 20 件に勝ります。
構造化コメントの投稿
1 つの大きなコメントの代わりに、GitHub の PR レビュー API を使って構造化されたフィードバックを投稿できます:
- name: Post structured review
uses: actions/github-script@v7
with:
script: |
// サマリー付きのレビューを作成
await github.rest.pulls.createReview({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
body: `## Automated Review Summary\n\n${reviewSummary}`,
event: 'COMMENT' // 重大な問題でマージをブロックするには 'REQUEST_CHANGES' を使用
});
event パラメータは検討の余地があります:
'COMMENT'— 情報提供のフィードバックを投稿する。マージをブロックしない'APPROVE'— PR を承認する(自動承認はおそらくしないほうがいい)'REQUEST_CHANGES'— 却下されるまでマージをブロックする
ほとんどのチームには 'COMMENT' がデフォルトとして適切です。Claude の出力に基づいてマージを自動ブロックするには、プロンプトへの高い信頼性と低い誤検知率が必要 — それを達成するには反復が必要です。
関連記事
PR レビューの自動化が動き始めたら、次のステップは通常、CI 環境内で Claude ができることを絞り込むことです:
- Claude Code in GitHub Actions: How to Fix Permission Errors (3 Battle-Tested Patterns) — CI ジョブで Claude ができることをロックダウンする
.claude/settings.jsonの許可リストアプローチは、ここでも直接適用できます - Claude Code Hooks: 12 Real-World Automation Patterns 2026 — diff を分析するだけでなく、レビュー中にフック(リンティング、セキュリティスキャン)を実行させたい場合
ヘッドレスレビューのパターンはうまくスケールします。一度動き始めれば、より高度な分析 — アーキテクチャフィードバック、テストカバレッジのギャップ、API コントラクトのドリフト — をレイヤーとして追加できます。レビュアーの負担を増やすことなく。