Claude Agent SDK
Anthropic 公式の Agent SDK(TypeScript / Python)。ターミナルの対話ではなく、コードから Claude をエージェントとして呼び出し、ツール実行ループを組み込む。
Claude Code が『対話 UI』なら、Agent SDK は『同じエンジンをプログラムから呼ぶ API』。`query()` に prompt と options を渡すと、Claude が Read/Edit/Bash/Glob などのツールを自律的に選び、結果を async イテレータでストリーミングする。CI・バックグラウンドジョブ・自作エージェント・ヘッドレス運用のときはこちら。
30秒サマリ
- パッケージ:`@anthropic-ai/claude-agent-sdk`(TS) / `claude-agent-sdk`(Python)
- TS 版はネイティブ Claude Code バイナリを optionalDependency として同梱。別途 CLI インストール不要
- 認証:`ANTHROPIC_API_KEY` を実行シェルの環境変数に設定(`.env` は自動読み込みしない)
- Bedrock / AWS / Vertex / Foundry も環境変数で切替可(`CLAUDE_CODE_USE_BEDROCK=1` など)
- claude.ai ログイン / レート制限を第三者アプリで使うのは規約で禁止。必ず API キー経由
向き / 不向き
- ○ CI / cron / Slack bot / GitHub Actions でエージェントを走らせたい
- ○ 独自の権限フロー・承認 UI を自作したい(`canUseTool` コールバック)
- ○ MCP サーバー経由で DB・ブラウザ・独自 API を触らせたい
- △ 対話しながらリポを育てたい → 普通の `claude` CLI のほうが速い
- × ChatGPT ライクな Web UI が欲しい → SDK にはない。UI は自作
エージェントループの仕組み(Observe → Act → Observe … → Result)
SDK の内部は Claude Code と同じ実行ループ。プロンプト受理 → 評価 → ツール実行 → 結果を Claude に戻す → を『ツール呼び出しなしの応答』が返るまで繰り返し、最後に ResultMessage で締める。ここを理解すると max_turns / hooks / 権限モードの意味が繋がる。
- ① プロンプト受理:SDK が prompt + system_prompt + tools + 履歴を送り、`SystemMessage(subtype="init")` を発行(session_id もここ)
- ② 評価と応答:Claude がテキスト or ツール呼び出しを返す → `AssistantMessage`
- ③ ツール実行:SDK が実行し結果を集める → `UserMessage`(tool_result)として Claude にフィードバック。ここに PreToolUse / PostToolUse フックが噛む
- ④ 繰返し:② と ③ を 1 ターンとして、ツール呼び出しがなくなるまでループ
- ⑤ 結果:最終テキストの `AssistantMessage` → `ResultMessage`(subtype / cost / tokens / session_id)
SystemMessage(init)
│
▼
┌──────────────────────────────── Turn N ─────────────────────────────┐
│ AssistantMessage ──► ツール呼び出し? │
│ │Yes │
│ ▼ │
│ [PreToolUse hook] → 実行 → [PostToolUse hook] │
│ │ │
│ ▼ │
│ UserMessage(tool_result) ─┐ │
└──────────────────────────────────────────────┼──────────────────────┘
│ ツールなし応答が出るまで反復
▼
AssistantMessage(最終) → ResultMessage1 ターン = Claude 応答 1 回 + それに含まれるツール実行群。「auth.ts のテストを直して」なら『npm test → Read → Edit + 再テスト → 完了報告』で 4 ターンほど。
メッセージタイプ 5 種(ストリーム消費の基本)
- `SystemMessage`:セッションライフサイクル。`subtype` = `init` / `compact_boundary` / `informational` / `worker_shutting_down`
- `AssistantMessage`:Claude 応答 1 回分。テキスト + tool_use ブロックを含む。TS では `.message.content` に注意
- `UserMessage`:ツール実行結果を Claude に戻すメッセージ。ストリーミング入力での追加プロンプトもここ
- `StreamEvent`:`include_partial_messages` を有効化した時だけ届く生 API デルタ
- `ResultMessage`:ループ終了。`subtype` / `result` / `total_cost_usd` / `usage` / `session_id`
# 型で分岐(Python)
if isinstance(m, AssistantMessage):
for block in m.content:
if hasattr(block, "text"): ... # 思考 / 説明
elif hasattr(block, "name"): ... # tool_use
elif isinstance(m, ResultMessage):
if m.subtype == "success": print(m.result)
// TS は type 文字列で分岐
if (msg.type === "assistant") { for (const b of msg.message.content) ... }
if (msg.type === "result") { if (msg.subtype === "success") ... }`prompt_suggestion` のような後続システムイベントが `ResultMessage` の後に来るので、result で break せずストリームは最後まで回し切る。
ターン / 予算 / effort でループを縛る
- `max_turns` / `maxTurns`:ツール使用ターン数の上限。超えると `ResultMessage.subtype = "error_max_turns"`
- `max_budget_usd` / `maxBudgetUsd`:総コスト上限。超えると `error_max_budget_usd`
- `effort`:`low` / `medium` / `high` / `xhigh` / `max`。推論深度とコストのトレードオフ
- 無制限だと『このコードベースを改善して』のようなプロンプトが延々回るので、本番は必ず両方入れる
options={
"allowed_tools": ["Read", "Edit", "Bash", "Glob", "Grep"],
"setting_sources": ["project"], # CLAUDE.md / skills / hooks を読む
"max_turns": 30,
"max_budget_usd": 5.0,
"effort": "high",
"permission_mode": "acceptEdits",
}単発 `query()` はエラー結果を yield したあと例外を投げる。try/except(try/catch)で包んでクリーンに終わらせる。ストリーミング入力セッションは投げずに生き続ける。
ツール実行と権限(並列 / 順次 / 拒否時の挙動)
- 同一ターンで複数呼び出し:読み取り系(Read / Glob / Grep / readOnlyHint=true な MCP)は並列、状態変更系(Edit / Write / Bash)は順次
- カスタムツールは既定で順次。並列化したい時はツール注釈で `readOnlyHint: true` を立てる
- `allowed_tools` は自動承認リスト、`disallowed_tools` は完全ブロック、それ以外は `permission_mode` に従う
- `"Bash(npm *)"` のようにコマンド単位でスコープ可能
- 拒否された時は Claude に『拒否』が tool_result として返り、別アプローチを試みる
権限モード 用途
acceptEdits 開発マシンの自律実行(編集は自動承認、Bash は許可ルール裏)
plan dry-run。読み取り専用、編集は canUseTool 経由
dontAsk allowedTools 外は拒否。ヘッドレスの厳格運用
auto モデル分類器で ok / deny を判定
bypassPermissions 隔離環境 / CI のみ。ホスト直では使わない
default canUseTool コールバックで承認 UI を自作コンテキストウィンドウと自動圧縮
- コンテキストはターン間で蓄積:system_prompt / tools / CLAUDE.md / 会話履歴 / tool 入力 & 出力 が全部乗る
- 変わらない部分(system_prompt / tools / CLAUDE.md)は prompt cache に自動で乗り、2 回目以降は激安
- 上限に近づくと SDK が自動圧縮。古い履歴を要約に置き換え、`SystemMessage(subtype="compact_boundary")` を発行
- 圧縮で消えて困るルールは初回プロンプトではなく CLAUDE.md に書く(全リクエスト再注入されるため)
- 手動で圧縮したい時は prompt に `/compact` を送る
- コンテキストを軽く保つ 4 戦術:
- ① サブエージェント:新規会話で走り、要約だけを親に返す(メインの履歴を膨らませない)
- ② ツール選別:`AgentDefinition.tools` で必要最小に絞る(ツール定義もトークンを食う)
- ③ MCP は Tool Search を有効化(既定で遅延ロード、多ツールサーバのコスト爆発を防ぐ)
- ④ ルーチンは `effort: "low"`
# CLAUDE.md(圧縮に耐えさせたいルールはここに)
## Summary instructions
When summarizing this conversation, always preserve:
- The current task objective and acceptance criteria
- File paths that have been read or modified
- Test results and error messages
- Decisions and reasoningセッションと再開・フォーク
- `ResultMessage.session_id` を保存しておけば、後から Resume できる(TS は init `SystemMessage` にも直接生える)
- Resume すると、読んだファイル・実行した分析・過去の意思決定まで含めて完全復元
- Fork すれば、元セッションを汚さず別アプローチを試せる
- Python の `ClaudeSDKClient` は複数呼び出し間で session_id を自動で持ち回してくれる
# 保存 → 復元の最小形(Python)
async for m in query(..., options=opts):
if isinstance(m, ResultMessage):
session_id = m.session_id
# 後で resume(オプションで session_id を渡す)
async for m in query(prompt="続き頼む", options=ClaudeAgentOptions(resume=session_id)):
...ResultMessage.subtype と stop_reason の読み方
subtype 結果 result フィールド
──────────────────────────────────── ────────────────
success あり(最終テキスト)
error_max_turns なし(ターン上限)
error_max_budget_usd なし(コスト上限)
error_during_execution なし(API / キャンセル)
error_max_structured_output_retries なし(構造化出力のリトライ超過)
stop_reason(最終アシスタント応答由来)
end_turn / max_tokens / refusal ...
→ refusal を検知したら『拒否された』表示に切替`total_cost_usd` / `usage` は Python では Optional。フォーマット前に None ガードする。
フック(Pre/PostToolUse / Stop / PreCompact)で挙動を差し込む
- `PreToolUse`:ツール実行前。危険コマンドをブロック、引数を書き換え可能
- `PostToolUse`:ツール結果後。監査ログ、副作用トリガー
- `UserPromptSubmit`:ユーザー入力にコンテキストを注入
- `Stop`:エージェント終了時。結果検証・セッション保存
- `SubagentStart` / `SubagentStop`:並列サブエージェントの追跡と集約
- `PreCompact`:圧縮前に完全なトランスクリプトをアーカイブ
フックはアプリプロセスで走り、Claude のコンテキストを消費しない。監査・ガードレール・ロギングの一等地。
セットアップ(TypeScript / 5分)
mkdir my-agent && cd my-agent
npm init -y
npm pkg set type=module
npm install @anthropic-ai/claude-agent-sdk
npm install --save-dev tsx
export ANTHROPIC_API_KEY=sk-ant-... # macOS / Linux
# PowerShell なら: $env:ANTHROPIC_API_KEY="sk-ant-..."`"type": "module"` を入れておくとトップレベル await が使える。`tsx` を dev 依存に入れておけば `.ts` をそのまま実行できる。
セットアップ(Python / 5分)
# uv 派
uv init my-agent && cd my-agent
uv add claude-agent-sdk
# pip 派
mkdir my-agent && cd my-agent
python -m venv .venv && source .venv/bin/activate
pip install claude-agent-sdk
export ANTHROPIC_API_KEY=sk-ant-...30分ワークスルー:バグ修正エージェントを作る
公式クイックスタートの再現。空リストで割り算する `calculate_average` と、None を受け取ると落ちる `get_user_name` を含む `utils.py` をエージェントに直させる。
# utils.py(意図的にバグ入り)
def calculate_average(numbers):
total = 0
for num in numbers:
total += num
return total / len(numbers) # 空リストで ZeroDivision
def get_user_name(user):
return user["name"].upper() # None で TypeError// agent.ts
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Review utils.py for bugs that would cause crashes. Fix any issues you find.",
options: {
allowedTools: ["Read", "Edit", "Glob"],
permissionMode: "acceptEdits",
},
})) {
if (message.type === "assistant") {
for (const block of message.message.content) {
if (block.type === "text") console.log(block.text);
else if (block.type === "tool_use") console.log(`Tool: ${block.name}`);
}
} else if (message.type === "result") {
console.log(`Done: ${message.subtype}`);
}
}# agent.py
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ResultMessage
async def main():
async for message in query(
prompt="Review utils.py for bugs that would cause crashes. Fix any issues you find.",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Glob"],
permission_mode="acceptEdits",
),
):
if isinstance(message, AssistantMessage):
for block in message.content:
if hasattr(block, "text"):
print(block.text)
elif hasattr(block, "name"):
print(f"Tool: {block.name}")
elif isinstance(message, ResultMessage):
print(f"Done: {message.subtype}")
asyncio.run(main())# 実行
npx tsx agent.ts # TS
uv run agent.py # Python (uv)
python agent.py # Python (pip)`async for` ループは Claude が『考える → ツール呼ぶ → 結果を観察する → 次を決める』を繰り返す間ずっと回る。ツール実行 / コンテキスト管理 / リトライは SDK 側が握っているので、こちらはストリームを消費するだけ。
主要オプション(ClaudeAgentOptions)
- `allowedTools`:事前承認するツール名の配列(Read / Edit / Glob / Grep / Bash / WebSearch など)
- `permissionMode`:`acceptEdits` / `plan` / `dontAsk` / `auto` / `bypassPermissions` / `default`
- `systemPrompt`:Claude に被せる役割・規約(例:『あなたは PEP8 を守る Python シニア』)
- `mcpServers`:MCP サーバー接続(DB / ブラウザ / GitHub / 独自 API)
- `canUseTool`:`default` モード時のカスタム承認コールバック。ユーザー確認 UI を自作するとき使う
options: {
allowedTools: ["Read", "Edit", "Glob", "Bash", "WebSearch"],
permissionMode: "acceptEdits",
systemPrompt: "You are a senior Python developer. Always follow PEP 8.",
}ツール一覧と権限モードの対応
ツール構成 できること
──────────────────────────────── ────────────────────────
Read / Glob / Grep 読み取り専用の解析
Read / Edit / Glob コードの読み書き
Read / Edit / Bash / Glob / Grep 完全自動化(テスト実行含む)
権限モード 動作
───────────────────── ─────────────────────────────────
acceptEdits ファイル編集を自動承認、他は確認
plan 読み取り専用のみ実行、編集は canUseTool
dontAsk allowedTools 外は拒否
auto モデル分類器が呼び出し毎に承認 / 拒否
bypassPermissions ask ルールに一致しない限り無条件許可
default canUseTool で自作承認フローを実装`bypassPermissions` はサンドボックス / 完全に信頼できる環境限定。ホスト直で使うと `rm -rf` 相当を無確認で走らせるリスク。
実務パターン 5 選
- ① GitHub Actions で PR に対して静的レビュー → コメント投稿
- ② Cron で毎晩ログを解析 → Slack に要約通知
- ③ 社内 Slack bot:メンションで Read/Edit/Bash を走らせ、成果を DM
- ④ `canUseTool` で承認 UI を作り、社内ダッシュボードにエージェント常駐
- ⑤ MCP サーバー経由で本番 DB を read-only で参照させ、SQL / レポート自動化
運用のコツと落とし穴
- ○ ライブ表示が要らないバックグラウンドは全メッセージ収集→まとめ処理(single-turn モード)
- ○ 長時間ジョブは `stopWhen` に相当する終了条件(イテレーション上限 / タイムアウト)を必ず入れる
- ○ 本番投入前に `permission_mode="plan"` で dry-run し、意図しない編集が出ないか確認
- △ `.env` は自動読み込みされない。`dotenv` で明示的に読む
- × claude.ai ログイン / Pro 契約を SDK 経由で使い回すのは規約違反
20分セットアップ手順
要約(非技術者向け)
SDK インストール → API キー設定 → バグ修正エージェントを一周させて成功体験を作る。
チェックリスト(自動保存)
0/10
次に何をすればよいか
- Anthropic Console で API キーを発行
- TS or Python どちらか片方で完走
- MCP か Bash 追加でカスタマイズを 1 回試す
チートシート
# TS
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const m of query({ prompt, options })) { /* ... */ }
# Python
from claude_agent_sdk import query, ClaudeAgentOptions
async for m in query(prompt=..., options=ClaudeAgentOptions(...)): ...
# 認証切替
ANTHROPIC_API_KEY=... # 既定
CLAUDE_CODE_USE_BEDROCK=1 # Amazon Bedrock
CLAUDE_CODE_USE_VERTEX=1 # Google Vertex
CLAUDE_CODE_USE_FOUNDRY=1 # Azure Foundry
# 主なオプション
allowedTools / allowed_tools
permissionMode / permission_mode
systemPrompt / system_prompt
mcpServers / mcp_servers
canUseTool / can_use_tool
# 次のステップ
権限 / Hooks / セッション / MCP サーバー / ホスティング
公式: https://docs.claude.com/en/docs/agent-sdk