Claude Code をターミナルで対話的に使うのは気持ちがいいのですが、「毎回手動で呼び出すのではなく、CI に組み込んで自動で動かしたい」という場面が出てきます。
PR が作成されたときにコードレビューを自動実行したい、テストが落ちたときに原因の仮説を AI に生成させたい、デプロイ前の最終チェックを自動化したい ── こうした用途では、Claude Code を「ヘッドレス(非対話)モード」で動かす必要があります。
その中核となるのが --print フラグと --output-format json オプションです。今回はこの2つを使って、実際に CI/CD パイプラインに組み込む方法を動くコードで解説します。
--print フラグとは何か
--print は Claude Code をヘッドレスモードで実行するためのフラグです。通常の対話 UI を起動せず、プロンプトに対する応答を標準出力に出力して終了します。
# 通常の起動(対話 UI が開く)
claude
# --print を付けるとヘッドレスで実行
claude --print "このコードをレビューしてください"
# ファイルの内容をパイプで渡す
cat src/auth.ts | claude --print "セキュリティ上の問題点を指摘してください"--print だけだと、応答がプレーンテキストとして標準出力に流れます。これで十分な用途もありますが、CI で後続の処理に使いたいときは JSON 形式で取得するほうが扱いやすくなります。
--output-format json で構造化データとして受け取る
--output-format json を組み合わせると、応答が JSON 形式で出力されます。
claude --print --output-format json "PR レビューをお願いします"出力例(整形済み):
{
"type": "result",
"subtype": "success",
"result": "レビュー内容のテキスト...",
"session_id": "sess_abc123",
"cost_usd": 0.0045,
"duration_ms": 2341,
"num_turns": 1
}result フィールドに応答テキストが入り、cost_usd でトークンコストの概算も取得できます。CI での使用量管理にも役立ちます。
GitHub Actions でコードレビューを自動化する
実際に PR が作成されたときに Claude Code が差分をレビューし、コメントを投稿する workflow を作ります。
前提準備
# リポジトリのシークレットに設定するもの
# ANTHROPIC_API_KEY: Anthropic の API キー
# GITHUB_TOKEN: Actions に自動で付与される(設定不要)workflow ファイル
# .github/workflows/claude-review.yml
name: Claude Code Review
on:
pull_request:
types: [opened, synchronize]
paths:
- "src/**"
- "lib/**"
jobs:
review:
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Claude Code
run: npm install -g @anthropic-ai/claude-code
- name: Get PR diff
id: diff
run: |
git diff origin/${{ github.base_ref }}...HEAD -- src/ lib/ > /tmp/pr_diff.txt
echo "diff_size=$(wc -c < /tmp/pr_diff.txt)" >> $GITHUB_OUTPUT
- name: Run Claude Review
id: claude
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
# 差分が大きすぎる場合は先頭 50KB に絞る
head -c 51200 /tmp/pr_diff.txt > /tmp/pr_diff_trimmed.txt
REVIEW=$(claude --print --output-format json \
--system "あなたはシニアエンジニアとしてコードレビューを行います。以下の観点で確認してください:
1. セキュリティ上の問題(SQL インジェクション、XSS、認証バイパス等)
2. パフォーマンス上の問題(N+1、不要なループ、メモリリーク等)
3. バグの可能性(エラーハンドリング漏れ、境界値の扱い等)
4. 良い実装には必ず言及する
問題がない場合は「問題なし」と明記してください。" \
"以下の PR 差分をレビューしてください:
$(cat /tmp/pr_diff_trimmed.txt)")
# JSON から result フィールドだけ取り出す
echo "$REVIEW" | python3 -c "
import json, sys
data = json.load(sys.stdin)
if data.get('subtype') == 'success':
print(data['result'])
else:
print('レビューの生成に失敗しました')
" > /tmp/review_comment.txt
echo "review_generated=true" >> $GITHUB_OUTPUT
- name: Post Review Comment
if: steps.claude.outputs.review_generated == 'true'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const reviewText = fs.readFileSync('/tmp/review_comment.txt', 'utf8');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `## 🤖 Claude Code レビュー\n\n${reviewText}\n\n---\n*このレビューは Claude Code によって自動生成されました*`
});この workflow では、PR の差分を --system で与えたロールと合わせて Claude に渡し、レビュー結果を JSON から取り出して PR コメントとして投稿します。
テスト失敗時に原因仮説を自動生成する
もうひとつの実用例として、テストが失敗したときに Claude が原因の仮説を生成する workflow です。
# .github/workflows/test-failure-analysis.yml
name: Test Failure Analysis
on:
workflow_run:
workflows: ["CI Tests"]
types: [completed]
jobs:
analyze:
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
runs-on: ubuntu-latest
permissions:
actions: read
issues: write
steps:
- uses: actions/checkout@v4
- name: Download test logs
uses: actions/download-artifact@v4
with:
name: test-results
path: /tmp/test-results/
continue-on-error: true
- name: Analyze with Claude
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
# テストログを取得(なければダミー)
LOG_FILE="/tmp/test-results/test-output.txt"
if [ ! -f "$LOG_FILE" ]; then
echo "テストログが見つかりませんでした" > "$LOG_FILE"
fi
ANALYSIS=$(claude --print --output-format json \
"以下はテストの失敗ログです。考えられる原因の仮説を3つ挙げ、
それぞれの確認方法を具体的に教えてください。
ログ:
$(head -c 10000 $LOG_FILE)")
# 解析結果を取り出して issue 作成用に保存
echo "$ANALYSIS" | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(data.get('result', '解析失敗'))
" > /tmp/analysis.txt
cat /tmp/analysis.txtローカルでの使い方:シェルスクリプトに組み込む
CI だけでなく、ローカルの開発フローにも組み込めます。
#!/bin/bash
# scripts/ai-review.sh
# 使い方: ./scripts/ai-review.sh [比較ブランチ名]
BASE="${1:-main}"
DIFF=$(git diff "$BASE"...HEAD 2>/dev/null)
if [ -z "$DIFF" ]; then
echo "差分がありません。"
exit 0
fi
echo "Claude Code でレビューを実行中..."
RESULT=$(echo "$DIFF" | claude --print --output-format json \
"この git diff をレビューしてください。特にセキュリティとパフォーマンスの観点で。")
# 終了コードを確認してエラー処理
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
echo "エラー: Claude Code の実行に失敗しました (exit: $EXIT_CODE)"
exit 1
fi
# レビュー本文を取り出して表示
echo "$RESULT" | python3 -c "
import json, sys
try:
data = json.load(sys.stdin)
print(data.get('result', '結果の取得に失敗しました'))
cost = data.get('cost_usd', 0)
print(f'\n--- コスト: \${cost:.4f} USD ---')
except json.JSONDecodeError:
print('JSON の解析に失敗しました')
sys.exit(1)
"このスクリプトを git commit の前に手動で実行する習慣を作るだけでも、見落としを減らす効果があります。
使用量とコストを管理する
--output-format json では cost_usd が返ってくるため、CI での使用量を記録しておくと月次のコスト把握に役立ちます。
# scripts/track_claude_cost.py
import json
import sys
from datetime import datetime
def track_cost(json_output: str, run_name: str) -> None:
"""Claude Code の JSON 出力からコストを記録する"""
try:
data = json.loads(json_output)
cost = data.get("cost_usd", 0)
tokens = data.get("usage", {})
log_entry = {
"timestamp": datetime.utcnow().isoformat(),
"run": run_name,
"cost_usd": cost,
"usage": tokens,
}
# ログファイルに追記
with open("claude_usage.jsonl", "a") as f:
f.write(json.dumps(log_entry) + "\n")
print(f"[{run_name}] cost: ${cost:.4f} USD")
except (json.JSONDecodeError, KeyError) as e:
print(f"コスト記録に失敗: {e}", file=sys.stderr)
if __name__ == "__main__":
run_name = sys.argv[1] if len(sys.argv) > 1 else "unknown"
json_input = sys.stdin.read()
track_cost(json_input, run_name)つまずきやすいポイント
① --print なしで --output-format json を使うと動かない
--output-format は --print と合わせて使う必要があります。単独では機能しません。
# ❌ これは動かない
claude --output-format json "質問"
# ✅ 正しい使い方
claude --print --output-format json "質問"② 長い差分は必ずトリムする
コンテキストウィンドウの上限を超えると、Claude がエラーを返したり応答が途切れたりします。50KB を目安にトリムするか、ファイルを分割して処理してください。
③ API キーの権限確認
ANTHROPIC_API_KEY が Organization レベルで使用量制限を受けている場合、CI での並列実行でレート制限に引っかかることがあります。CI 専用のキーを発行し、使用量上限を設定しておくと安全です。
試しに今日から使えるコマンド
まずはローカルで試してみたい方は、以下のコマンドから始めてみてください。
# 現在の変更内容を Claude にレビューさせる(そのまま使えます)
git diff HEAD | claude --print --output-format json \
"このコード変更で気になる点を教えてください" | \
python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('result',''))"一度 --print と --output-format json の感覚をつかんだら、GitHub Actions への組み込みはそれほど難しくありません。まずは差分レビューの自動化から試して、徐々に用途を広げていくのがお勧めです。
検証時に確認すべきこと
- 本番相当の負荷をかけた状態で再現できるか
- ログだけでなくメトリクスにエラー率を出しているか
- 失敗時の人間への通知が遅延なく届くか