多くの開発者はClaude Codeをインタラクティブに使っている。しかし同じツールが完全なヘッドレスモードでも動作し、パイプライン・スクリプト・CIシステムに適した構造化された出力を生成できる。
-pフラグ(printモード)は、Claude Codeを独自のUIの外にあるすべてのものと統合する方法だ。このガイドでは、ヘッドレスClaude Codeのすべての側面を解説する。出力フォーマット、JSONスキーマを使った構造化出力、ストリーミングパターン、高速自動化のための--bareモード、そしてCI/CD統合の実践的なパターンまで。
-pフラグ:ヘッドレス実行
# 基本的なヘッドレスクエリ
claude -p "src/api/には何個のエクスポートされた関数があるか?"
# 標準入力から
echo "$(cat package.json)" | claude -p "古くなっている依存関係は?"
# ファイル内容から
claude -p "このファイルを要約して: $(cat ARCHITECTURE.md)"
-pで実行すると、Claude Codeは:
- インタラクティブUIを開かずに実行
- 単一のプロンプトを読み込んで処理し、終了
- 標準出力にレスポンスを出力
- エラーを標準エラーに書き込む
- 成功時は終了コード0、失敗時は非ゼロを返す
プロンプトは--allowedToolsや--disallowedToolsで制限されない限り、インタラクティブモードとまったく同じようにすべてのツール(ファイル読み取り、bash実行など)にアクセスできる。
出力フォーマット
text(デフォルト)
claude -p "このコードベースで最も複雑な関数を3つ挙げて"
# 出力: プレーンなmarkdownテキスト
読みやすいが、プログラムでパースするのは難しい。
json
claude -p "最も複雑な関数を3つ挙げて" --output-format json
以下のJSONオブジェクトを返す:
{
"result": "1. processPaymentTransaction...\n2. handleOAuthCallback...",
"session_id": "7f3a9c2b-4e81-4c3d-a9f2-3b8c1d7e0a65",
"total_cost_usd": 0.0043,
"cost_breakdown": [
{
"model": "claude-sonnet-4-6",
"input_tokens": 4821,
"output_tokens": 312,
"cost_usd": 0.0043
}
]
}
以下が必要なときに有用:
- 後で再開するためのセッションID
- クエリごとのコスト追跡
- より大きなJSONパイプラインの一部としての結果
stream-json
claude -p "再帰を説明して" --output-format stream-json --verbose
到着したイベントを改行区切りのJSONで発行する。各行は完全なJSONオブジェクト。
--verboseフラグはツール呼び出しとシステムイベントを含む。付けない場合は最終結果のみストリーミングされる。
到着時に部分的なテキストトークンを受け取るには--include-partial-messagesを追加する(プログレッシブ表示に有用):
claude -p "詳細な分析を書いて" \
--output-format stream-json \
--verbose \
--include-partial-messages
stream-jsonのイベントタイプ
system/init
セッション開始時に発行される。セッションのメタデータを含む:
{
"type": "system/init",
"session_id": "7f3a9c2b-...",
"model": "claude-sonnet-4-6",
"tools": ["Read", "Write", "Bash", "Edit"],
"mcp_servers": ["filesystem", "github"],
"plugins": [],
"timestamp": "2026-06-17T08:14:22Z"
}
ストリーム開始時にセッションIDをキャプチャして後で再開するために使う。
stream_event
主要なイベントタイプ。インクリメンタルなテキスト出力を含む:
{
"type": "stream_event",
"event": {
"delta": {
"type": "text_delta",
"text": "最も複雑な"
}
}
}
ツール呼び出しの場合、delta.typeは"input_json_delta"または"tool_use"になる。
system/api_retry
APIエラーのリトライ前に発行される:
{
"type": "system/api_retry",
"attempt": 2,
"retry_delay_ms": 2000,
"error": "overloaded_error"
}
最終resultイベント
完了時:
{
"type": "result",
"result": "完全な最終テキストレスポンス",
"session_id": "7f3a9c2b-...",
"total_cost_usd": 0.0043
}
jqでstream-jsonをパース
テキストトークンを到着時に抽出:
claude -p "デプロイについての詩を書いて" \
--output-format stream-json \
--verbose \
--include-partial-messages | \
jq -rj 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | .event.delta.text'
開始時にセッションIDをキャプチャし、終了時にテキストをキャプチャ:
OUTPUT=$(claude -p "authモジュールを分析して" --output-format stream-json --verbose)
SESSION_ID=$(echo "$OUTPUT" | jq -r 'select(.type == "system/init") | .session_id' | head -1)
RESULT=$(echo "$OUTPUT" | jq -r 'select(.type == "result") | .result' | head -1)
COST=$(echo "$OUTPUT" | jq -r 'select(.type == "result") | .total_cost_usd' | head -1)
echo "セッション: $SESSION_ID"
echo "コスト: \$$COST"
echo "結果: $RESULT"
--json-schemaによる構造化出力
markdownっぽいJSONではなく、保証された構造が必要なとき:
claude -p "このコードベースのすべてのAPIエンドポイントを抽出して" \
--output-format json \
--json-schema '{
"type": "object",
"properties": {
"endpoints": {
"type": "array",
"items": {
"type": "object",
"properties": {
"method": {"type": "string"},
"path": {"type": "string"},
"handler": {"type": "string"},
"auth_required": {"type": "boolean"}
},
"required": ["method", "path", "handler"]
}
}
}
}'
JSON出力のresultフィールドはスキーマに準拠した有効なJSONを含む文字列になる。パース方法:
RESULT=$(claude -p "APIエンドポイントを抽出して" --output-format json --json-schema "$SCHEMA")
echo "$RESULT" | jq '.result | fromjson | .endpoints[] | "\(.method) \(.path)"'
一般的な自動化タスク向けの実用的なスキーマ:
# バグ検出
BUGS_SCHEMA='{
"type": "object",
"properties": {
"bugs": {
"type": "array",
"items": {
"type": "object",
"properties": {
"file": {"type": "string"},
"line": {"type": "integer"},
"severity": {"type": "string", "enum": ["critical", "high", "medium", "low"]},
"description": {"type": "string"},
"suggested_fix": {"type": "string"}
},
"required": ["file", "severity", "description"]
}
},
"summary": {"type": "string"}
}
}'
# テストカバレッジのギャップ
COVERAGE_SCHEMA='{
"type": "object",
"properties": {
"uncovered_functions": {"type": "array", "items": {"type": "string"}},
"risk_areas": {"type": "array", "items": {"type": "string"}},
"recommended_tests": {"type": "array", "items": {"type": "string"}}
}
}'
高速自動化のための--bareモード
--bareフラグは自動化に必要ない起動オーバーヘッドをスキップする:
claude --bare -p "CHANGELOG.mdを要約して" --allowedTools "Read"
--bareがスキップするもの:
- CLAUDE.mdの読み込み
- Hooks(PreToolUse、PostToolUseなど)
- プラグインの読み込み
- MCPサーバーの接続
- 自動メモリ
プロジェクト固有の設定が不要なときに起動時間を大幅に削減する。何千回も実行する自動化スクリプトでは、累積効果が大きい。
注:--bareは将来のリリースで-pのデフォルトになる予定。
ヘッドレスモードでのツール制御
使えるツールを制限してスコープを限定し、意図しない副作用を防ぐ:
# 読み取り専用分析(書き込みなし、bashなし)
claude -p "セキュリティモデルを分析して" --allowedTools "Read"
# 特定のツールのみ
claude -p "構文エラーをチェックして" --allowedTools "Read,Bash"
# 特定のツールだけ無効化
claude -p "この関数をリファクタリングして" --disallowedTools "Bash"
完全な自動化(ツール確認プロンプトなし):
claude -p "すべてのTypeScriptエラーを修正して" \
--dangerously-skip-permissions \
--allowedTools "Read,Edit,Write,Bash"
--dangerously-skip-permissionsはClaude が何をするか検証済みのサンドボックス化されたCI環境でのみ使う。
実践的なCI/CDパターン
パターン1:コミット前分析
#!/bin/bash
# .git/hooks/pre-commit
CHANGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.ts$' | head -20)
if [ -z "$CHANGED_FILES" ]; then
exit 0
fi
FILES_CONTENT=$(echo "$CHANGED_FILES" | xargs -I {} sh -c 'echo "=== {} ===" && cat {}')
RESULT=$(claude --bare -p "変更されたこれらのTypeScriptファイルで重大なバグのみをレビューして。簡潔に。ファイル:\n$FILES_CONTENT" \
--output-format json \
--allowedTools "" \
--json-schema '{
"type": "object",
"properties": {
"critical_bugs": {"type": "array", "items": {"type": "string"}},
"blocking": {"type": "boolean"}
}
}')
BLOCKING=$(echo "$RESULT" | jq '.result | fromjson | .blocking')
BUGS=$(echo "$RESULT" | jq -r '.result | fromjson | .critical_bugs[]' 2>/dev/null)
if [ "$BLOCKING" = "true" ]; then
echo "❌ Claude Codeが重大なバグを発見:"
echo "$BUGS"
exit 1
fi
exit 0
パターン2:PRレビューコメント
#!/bin/bash
# PRオープン時にGitHub Actionsから呼ばれる
PR_DIFF=$(git diff origin/main...HEAD)
PR_NUMBER=$1
REVIEW=$(claude --bare -p "このPR diffをレビューして、具体的で実行可能なフィードバックを提供して。バグ・セキュリティ問題・パフォーマンス問題に集中して。スタイルのコメントはスキップ。\n\nDiff:\n$PR_DIFF" \
--output-format json \
--allowedTools "Read" \
--json-schema '{
"type": "object",
"properties": {
"summary": {"type": "string"},
"issues": {
"type": "array",
"items": {
"type": "object",
"properties": {
"severity": {"type": "string", "enum": ["critical", "major", "minor"]},
"file": {"type": "string"},
"description": {"type": "string"}
}
}
},
"recommendation": {"type": "string", "enum": ["approve", "request_changes", "comment"]}
}
}')
COMMENT=$(echo "$REVIEW" | jq -r '.result | fromjson | "## Claude Codeレビュー\n\n**推奨アクション:** \(.recommendation)\n\n**概要:** \(.summary)\n\n### 問題点\n\(.issues[] | "- **\(.severity)** (`\(.file)`): \(.description)")"')
gh pr comment "$PR_NUMBER" --body "$COMMENT"
パターン3:マルチステップ分析パイプライン
#!/bin/bash
# ステップ1: 候補を見つける
STEP1=$(claude -p "メモリリークがありそうな関数を見つけて" \
--output-format json \
--json-schema '{"type":"object","properties":{"suspects":{"type":"array","items":{"type":"string"}}}}')
SESSION_ID=$(echo "$STEP1" | jq -r '.session_id')
SUSPECTS=$(echo "$STEP1" | jq -r '.result | fromjson | .suspects[]')
# ステップ2: 各候補を詳細分析(ステップ1のコンテキストを引き継いで)
for func in $SUSPECTS; do
claude -p "この関数をメモリリークについて詳細に分析して: $func" \
--session-id "$SESSION_ID" \
--output-format json | \
jq -r '.result' >> leak_report.md
done
echo "レポートをleak_report.mdに書き込みました"
パターン4:定期的なコードベース健全性チェック
#!/bin/bash
# cronで毎日実行
HEALTH=$(claude --bare \
-p "このコードベースの健全性チェックを実施して。確認項目: 1) 1000行超で分割すべきファイル, 2) 循環依存, 3) ハードコードされた認証情報のパターン, 4) 30日以上経過したTODOコメント" \
--output-format json \
--allowedTools "Read,Bash" \
--json-schema '{
"type": "object",
"properties": {
"score": {"type": "integer", "minimum": 0, "maximum": 100},
"issues": {"type": "array", "items": {"type": "string"}},
"urgent": {"type": "array", "items": {"type": "string"}}
}
}')
SCORE=$(echo "$HEALTH" | jq '.result | fromjson | .score')
URGENT=$(echo "$HEALTH" | jq -r '.result | fromjson | .urgent[]' 2>/dev/null)
if [ "$SCORE" -lt 70 ]; then
echo "⚠️ コードベース健全性スコア: $SCORE/100"
echo "緊急の問題:"
echo "$URGENT"
# Slack、PagerDutyなどにアラートを送信
fi
コンテキストを効率的に渡す
大規模なコードベースでは、Claudeが読むべきファイルを明示する:
# プロンプトにファイルリストを渡す
RELEVANT_FILES=$(grep -rl "authentication" src/ | head -10 | tr '\n' ' ')
claude -p "認証フローを分析して。関連ファイル: $RELEVANT_FILES" \
--allowedTools "Read"
# 構造化されたコンテキストをパイプで渡す
{
echo "これらの特定の関数を分析して:"
grep -n "function process\|async function handle" src/api/*.ts
} | claude -p "$(cat)" --allowedTools "Read"
複数ファイルの分析では、Claudeが自分で見つけるのではなく、プロンプトで明示的にファイルを事前に渡す:
CONTEXT=$(for f in src/auth.ts src/session.ts src/middleware.ts; do
echo "=== $f ==="
cat "$f"
done)
claude -p "この認証スタックを踏まえて:\n$CONTEXT\n\nセッション固定の脆弱性を見つけて" \
--bare \
--allowedTools ""
コストとレート制限の考慮事項
--output-format jsonのレスポンスにはコストデータが含まれる。追跡方法:
RESULT=$(claude -p "コードベース全体を分析して" --output-format json)
COST=$(echo "$RESULT" | jq '.total_cost_usd')
echo "クエリコスト: \$$COST"
大量の自動化では、タスクの複雑さが低いときに安価なモデルを選択するために--modelを使う:
# 単純な分類タスクにはHaikuを使う
claude -p "これはバグレポートか機能リクエストか: $ISSUE_BODY" \
--model claude-haiku-4-5-20251001 \
--output-format json \
--json-schema '{"type":"object","properties":{"type":{"type":"string","enum":["bug","feature","other"]}}}'
# 複雑な分析にはSonnet/Opusを使う
claude -p "authモジュールのセキュリティ監査を実施して" \
--model claude-sonnet-4-6 \
--allowedTools "Read"
まとめ
| 目標 | パターン |
|---|---|
| 単純なヘッドレスクエリ | claude -p "クエリ" |
| 構造化された結果を得る | claude -p "..." --output-format json |
| JSONスキーマを強制 | --json-schema '...'を追加 |
| リアルタイムでトークンをストリーミング | --output-format stream-json --include-partial-messages |
| 高速自動化(設定オーバーヘッドなし) | --bareを追加 |
| 読み取り専用分析 | --allowedTools "Read"を追加 |
| 確認プロンプトなし(CI) | --dangerously-skip-permissionsを追加 |
| コンテキストを引き継いだマルチステップパイプライン | session_idをキャプチャして--session-idで渡す |
| コスト追跡 | --output-format json → .total_cost_usd |
Print modeは、Claude Codeが開発者ツールからプラットフォームへとスケールする場所だ。出力フォーマットとツール制御を理解すれば、Claudeをあらゆるパイプラインに統合するのは簡単になる。