Claude Agent SDK 入門 2026 — Claude CodeをAPIから呼び出すカスタム自動化ガイド
Claude Agent SDK でClaude Codeをプログラムから呼び出す方法を完全解説。SDK インストール、ストリーミング応答、Tool Use、Hooks連携、本番運用パターンまで。
Claude Codeを「対話しながら使う」のとは別に、「プログラムから呼び出して自動で動かす」ニーズがある。
たとえばこんなケース。
- PRが来たらClaude Codeにレビューさせてステータスを更新したい
- 毎朝ログファイルを分析して異常を検知させたい
- Webhookを受け取ったらコードを自動修正して PR を作らせたい
こういう「インタラクティブじゃない用途」に答えるのが Claude Agent SDK だ。
CLIを手で操作するのではなく、PythonやTypeScriptのコードからClaude Codeのエージェントループをそのまま起動できる。読んでいるファイル、実行しているコマンド、文脈の管理まで全部SDKがやってくれるので、ツール実行ループを自分で書く必要がない。
この記事では、SDKの概念的な位置付けから実際の動かし方、本番投入する際の考え方まで一通り書く。
Claude Agent SDKとは(CLIとの違い)
Claude Agent SDKは、Claude Codeが持つエージェント機能をPythonまたはTypeScriptのライブラリとして提供するものだ。
Anthropicの公式説明を引用すると:
Build production AI agents with Claude Code as a library
「Claude Codeをライブラリとして」というのがポイント。CLIを使うときと同じツール(Read、Edit、Bash、Grep、Glob…)を、同じエージェントループで、コードから呼び出せる。
CLIとSDKの使い分け
| 用途 | 向いているもの |
|---|---|
| 日常の開発作業 | CLI |
| CI/CDパイプライン | SDK |
| カスタムアプリへの組み込み | SDK |
| 単発の一回タスク | CLI |
| 本番の自動化処理 | SDK |
多くのチームは「開発中はCLI、本番処理はSDK」という使い分けをするケースが多い。CLIで試した処理をそのままSDKに移植できるのが強みで、ワークフローの翻訳コストがほとんどかからない。
Anthropic Client SDKとの違い
混乱しやすいのが「Anthropic Client SDK」との区別だ。
Anthropic Client SDKは、Messages APIを直接叩くためのライブラリ。つまり「APIを呼ぶ → ツール使いたい → 自分でツール実行 → また呼ぶ」というループを自分で実装しなければならない。
Claude Agent SDKはそのループを全部内部でやってくれる。コードはこんなに変わる。
# Anthropic Client SDK: ツールループを自分で実装
response = client.messages.create(...)
while response.stop_reason == "tool_use":
result = your_tool_executor(response.tool_use)
response = client.messages.create(tool_result=result, **params)
# Claude Agent SDK: Claudeがツールを自律実行
async for message in query(prompt="auth.pyのバグを直して"):
print(message)
// Anthropic Client SDK: ツールループを自分で実装
let response = await client.messages.create({ ...params });
while (response.stop_reason === "tool_use") {
const result = yourToolExecutor(response.tool_use);
response = await client.messages.create({ tool_result: result, ...params });
}
// Claude Agent SDK: Claudeがツールを自律実行
for await (const message of query({ prompt: "auth.tsのバグを直して" })) {
console.log(message);
}
処理の意図が明確になるし、書くコード量も圧倒的に少なくなる。
SDKを使う3つの場面
実際にSDKが活きるのはどういうときか。僕が使っていて「これはSDKじゃないと無理だな」と思った場面を3つ挙げる。
1. CI/CDへの組み込み
GitHub ActionsなどのCI環境でClaude Codeを動かす場合、対話型のCLIは使えない。SDKならスクリプトとして実行できるので、PRの内容を自動レビューしたり、テスト失敗の原因を分析して修正案を作ったりできる。
2. アプリケーションへの組み込み
「ユーザーがボタンを押したらAIがファイルを分析して結果を返す」というようなアプリを作るとき、SDKを使えばClaude Codeのエージェント機能をAPIエンドポイントの中で普通に呼び出せる。
3. 定期実行・バッチ処理
毎朝決まった時間にコードをチェックしたり、ログを分析したりする定期タスクに使える。cron + Pythonスクリプトという形でClaude Codeの能力をバックグラウンドで走らせられる。
インストールと初期設定(Python / TypeScript)
必要な環境
- Python 3.10以上 または Node.js 18以上
- Anthropic APIキー(Consoleから取得)
Python
pip install claude-agent-sdk
uvを使うなら:
uv init
uv add claude-agent-sdk
Python 3.9以下では No matching distribution found for claude-agent-sdk というエラーが出る。python3 --version でバージョンを確認してから入れること。
TypeScript
npm install @anthropic-ai/claude-agent-sdk
TypeScript SDKはClaude CodeのネイティブバイナリをSDKパッケージ内にバンドルしているので、Claude Code本体を別途インストールする必要はない。
APIキーの設定
export ANTHROPIC_API_KEY=your-api-key
プロジェクトの .env ファイルに書いておくと管理しやすい。
SDKはAmazon Bedrock、Google Vertex AI、Microsoft Azureも認証プロバイダーとして対応している。
# Bedrockの場合
export CLAUDE_CODE_USE_BEDROCK=1
# + AWS認証情報の設定
# Vertex AIの場合
export CLAUDE_CODE_USE_VERTEX=1
# + Google Cloud認証情報の設定
基本的な使い方(質問→応答の最小例)
最小構成のコードを見てみる。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
async for message in query(
prompt="このディレクトリにあるファイルを一覧で教えて",
options=ClaudeAgentOptions(allowed_tools=["Bash", "Glob"]),
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "このディレクトリにあるファイルを一覧で教えて",
options: { allowedTools: ["Bash", "Glob"] }
})) {
if ("result" in message) console.log(message.result);
}
query() がメインのエントリポイントで、非同期イテレータを返す。async for で回すと、Claudeが作業しながら流してくる各メッセージを順番に受け取れる。
オプションの概要
ClaudeAgentOptions(Python)または options オブジェクト(TypeScript)に渡せる主なパラメータ:
| パラメータ | 説明 |
|---|---|
allowed_tools / allowedTools | 事前承認するツールのリスト |
permission_mode / permissionMode | 権限モード(後述) |
system_prompt / systemPrompt | カスタムシステムプロンプト |
max_turns / maxTurns | 最大ターン数 |
cwd | 作業ディレクトリ |
resume | 既存セッションのID(セッション再開用) |
パーミッションモード
| モード | 動作 |
|---|---|
acceptEdits | ファイル編集と一般的なコマンドを自動承認 |
dontAsk | allowedTools 以外をすべて拒否 |
bypassPermissions | すべてのツールをプロンプトなしで実行(テスト環境向け) |
default | canUseTool コールバックで承認フローを自分で実装 |
CI/CDやバックグラウンドジョブで使う場合は dontAsk か acceptEdits を明示するのが基本。default のままだと対話プロンプトが出てしまって処理が止まる。
ストリーミング応答の処理
query() はストリーミングで動作する。Claudeが何かを考え、ツールを呼び出し、結果を受け取り、また考える、というループの各ステップがメッセージとして流れてくる。
メッセージの種類と処理例:
import asyncio
from claude_agent_sdk import (
query,
ClaudeAgentOptions,
AssistantMessage,
ResultMessage,
SystemMessage,
)
async def main():
async for message in query(
prompt="utils.pyにあるバグを探して修正して",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Glob"],
permission_mode="acceptEdits",
),
):
if isinstance(message, SystemMessage) and message.subtype == "init":
# セッション開始。session_idが取れる
print(f"セッション開始: {message.data.get('session_id')}")
elif isinstance(message, AssistantMessage):
# Claudeの発言・思考
for block in message.content:
if hasattr(block, "text"):
print(f"[Claude] {block.text}")
elif hasattr(block, "name"):
print(f"[ツール呼び出し] {block.name}")
elif isinstance(message, ResultMessage):
# 最終結果
print(f"完了: {message.subtype}")
if message.subtype == "success":
print(message.result)
asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
let sessionId: string | undefined;
for await (const message of query({
prompt: "utils.tsにあるバグを探して修正して",
options: {
allowedTools: ["Read", "Edit", "Glob"],
permissionMode: "acceptEdits"
}
})) {
if (message.type === "system" && message.subtype === "init") {
// セッション開始
sessionId = (message as any).session_id;
console.log(`セッション開始: ${sessionId}`);
} else if (message.type === "assistant" && message.message?.content) {
// Claudeの発言・思考
for (const block of message.message.content) {
if ("text" in block) {
console.log(`[Claude] ${block.text}`);
} else if ("name" in block) {
console.log(`[ツール呼び出し] ${block.name}`);
}
}
} else if (message.type === "result") {
// 最終結果
console.log(`完了: ${message.subtype}`);
if ("result" in message) console.log(message.result);
}
}
バックグラウンドジョブでリアルタイム出力が不要な場合は、すべてのメッセージを配列に集めてから処理するシングルターンモードもある。ストリーミングか一括処理かは用途に合わせて選ぶ。
Tool Use(ファイル操作・コマンド実行)
SDKで使えるビルトインツールの一覧:
| ツール | できること |
|---|---|
Read | 作業ディレクトリ内のファイルを読む |
Write | 新規ファイルを作成する |
Edit | 既存ファイルを精密に編集する |
Bash | ターミナルコマンド、スクリプト、git操作 |
Monitor | バックグラウンドスクリプトを監視して各出力行を処理 |
Glob | パターンでファイルを検索(**/*.ts、src/**/*.py) |
Grep | 正規表現でファイル内容を検索 |
WebSearch | Webを検索する |
WebFetch | Webページのコンテンツを取得・解析 |
AskUserQuestion | ユーザーに確認を求める |
ツールの組み合わせパターン
# 読み取り専用の分析
options = ClaudeAgentOptions(allowed_tools=["Read", "Glob", "Grep"])
# コードを分析して修正まで
options = ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Glob"],
permission_mode="acceptEdits"
)
# フル自動化(テスト実行まで含む)
options = ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Bash", "Glob", "Grep"],
permission_mode="acceptEdits"
)
// 読み取り専用の分析
const readOnlyOptions = { allowedTools: ["Read", "Glob", "Grep"] };
// フル自動化
const fullOptions = {
allowedTools: ["Read", "Edit", "Bash", "Glob", "Grep"],
permissionMode: "acceptEdits" as const
};
MCP(Model Context Protocol)との接続
ビルトインツール以外に、MCPサーバー経由で外部システムへの接続もできる。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
async for message in query(
prompt="example.comを開いて、ページの内容を教えて",
options=ClaudeAgentOptions(
mcp_servers={
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
),
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())
for await (const message of query({
prompt: "example.comを開いて、ページの内容を教えて",
options: {
mcpServers: {
playwright: { command: "npx", args: ["@playwright/mcp@latest"] }
}
}
})) {
if ("result" in message) console.log(message.result);
}
Hooks連携(プログラムから挙動を制御)
Hooksは、エージェントのライフサイクルの特定のタイミングでカスタムコードを実行する仕組みだ。
「このコマンドは実行させない」「このファイルへの書き込みをログに残す」「外部APIに通知を送る」といった挙動をプログラムから制御できる。
主なHookイベント
| イベント | タイミング | 用途例 |
|---|---|---|
PreToolUse | ツール呼び出し前 | 危険なコマンドをブロック |
PostToolUse | ツール実行後 | 変更内容をログに記録 |
PostToolUseFailure | ツール実行失敗時 | エラーを通知 |
UserPromptSubmit | プロンプト送信時 | プロンプトにコンテキストを追加 |
Stop | 実行終了時 | セッション状態を保存 |
Notification | ステータス通知時 | Slackなどに転送 |
SubagentStart | サブエージェント開始時 | 並列タスクの追跡 |
SubagentStop | サブエージェント完了時 | 結果の集約 |
基本的なHook設定
import asyncio
from datetime import datetime
from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher
async def log_file_change(input_data, tool_use_id, context):
"""ファイル変更をaudit.logに記録する"""
file_path = input_data.get("tool_input", {}).get("file_path", "unknown")
with open("./audit.log", "a") as f:
f.write(f"{datetime.now()}: modified {file_path}\n")
return {}
async def main():
async for message in query(
prompt="utils.pyをリファクタリングして可読性を上げて",
options=ClaudeAgentOptions(
permission_mode="acceptEdits",
hooks={
"PostToolUse": [
HookMatcher(matcher="Edit|Write", hooks=[log_file_change])
]
},
),
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())
import { query, HookCallback } from "@anthropic-ai/claude-agent-sdk";
import { appendFile } from "fs/promises";
const logFileChange: HookCallback = async (input) => {
const filePath = (input as any).tool_input?.file_path ?? "unknown";
await appendFile("./audit.log", `${new Date().toISOString()}: modified ${filePath}\n`);
return {};
};
for await (const message of query({
prompt: "utils.tsをリファクタリングして可読性を上げて",
options: {
permissionMode: "acceptEdits",
hooks: {
PostToolUse: [{ matcher: "Edit|Write", hooks: [logFileChange] }]
}
}
})) {
if ("result" in message) console.log(message.result);
}
.envファイルへの書き込みをブロックする
セキュリティ上重要な制御の例として、 .env ファイルへの書き込みを禁止するHookを作ってみる。
async def protect_env_files(input_data, tool_use_id, context):
file_path = input_data["tool_input"].get("file_path", "")
file_name = file_path.split("/")[-1]
if file_name == ".env":
return {
"hookSpecificOutput": {
"hookEventName": input_data["hook_event_name"],
"permissionDecision": "deny",
"permissionDecisionReason": ".envファイルは変更できません",
}
}
return {}
options = ClaudeAgentOptions(
hooks={
"PreToolUse": [
HookMatcher(matcher="Write|Edit", hooks=[protect_env_files])
]
}
)
import { query, HookCallback, PreToolUseHookInput } from "@anthropic-ai/claude-agent-sdk";
const protectEnvFiles: HookCallback = async (input) => {
const preInput = input as PreToolUseHookInput;
const toolInput = preInput.tool_input as Record<string, unknown>;
const filePath = toolInput?.file_path as string;
const fileName = filePath?.split("/").pop();
if (fileName === ".env") {
return {
hookSpecificOutput: {
hookEventName: preInput.hook_event_name,
permissionDecision: "deny",
permissionDecisionReason: ".envファイルは変更できません"
}
};
}
return {};
};
permissionDecision は "allow" / "deny" / "ask" / "defer" の4種類。複数のHookが衝突した場合は deny が最優先になる。
本番運用パターン(エラーハンドリング・タイムアウト・コスト管理)
エラーハンドリング
Claudeが実行に失敗すると ResultMessage の subtype が "error" になる。これを必ず拾う。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def run_with_error_handling(prompt: str, max_retries: int = 3):
for attempt in range(max_retries):
try:
async for message in query(
prompt=prompt,
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Bash"],
permission_mode="acceptEdits",
max_turns=20, # 無限ループ防止
),
):
if isinstance(message, ResultMessage):
if message.subtype == "success":
return message.result
elif message.subtype == "error":
print(f"実行エラー (attempt {attempt + 1}): {message}")
break
except Exception as e:
print(f"例外 (attempt {attempt + 1}): {e}")
if attempt == max_retries - 1:
raise
return None
asyncio.run(run_with_error_handling("src/auth.pyのバグを直して"))
import { query, ResultMessage } from "@anthropic-ai/claude-agent-sdk";
async function runWithRetry(prompt: string, maxRetries = 3): Promise<string | null> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
for await (const message of query({
prompt,
options: {
allowedTools: ["Read", "Edit", "Bash"],
permissionMode: "acceptEdits",
maxTurns: 20
}
})) {
if (message.type === "result") {
if (message.subtype === "success" && "result" in message) {
return message.result as string;
} else if (message.subtype === "error") {
console.log(`実行エラー (attempt ${attempt + 1})`);
break;
}
}
}
} catch (e) {
console.log(`例外 (attempt ${attempt + 1}): ${e}`);
if (attempt === maxRetries - 1) throw e;
}
}
return null;
}
タイムアウト制御
SDKにはセッション単位のタイムアウト機能がない。maxTurns でターン数を制限するのが現実的な制御方法だ。
options = ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Bash"],
permission_mode="acceptEdits",
max_turns=30, # 最大30ターンで強制終了
)
const options = {
allowedTools: ["Read", "Edit", "Bash"],
permissionMode: "acceptEdits" as const,
maxTurns: 30
};
処理時間でのタイムアウトが必要な場合は Promise.race() や asyncio.wait_for() と組み合わせる。
コスト管理
トークンコストがインフラコストを大きく上回ることが多いので、コスト計測は重要だ。
# セッションIDでコスト追跡
async def main():
session_id = None
total_cost_info = []
async for message in query(
prompt="コードベース全体を分析して改善点をリストアップして",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Glob", "Grep"],
),
):
# SystemMessageからセッションIDを取得
if hasattr(message, "subtype") and message.subtype == "init":
if hasattr(message, "data"):
session_id = message.data.get("session_id")
# ResultMessageにはコスト情報が含まれることがある
if hasattr(message, "usage"):
total_cost_info.append(message.usage)
print(f"Session: {session_id}")
# cost_tracking オプションの詳細はAnthropicドキュメントを参照
asyncio.run(main())
本番ではOpenTelemetryを使った観測も有効だ。
# .env
CLAUDE_CODE_ENABLE_TELEMETRY=1
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=otlp
OTEL_EXPORTER_OTLP_ENDPOINT=http://collector.example.com:4318
マルチテナント環境での分離
複数のユーザーのジョブを1台のサーバーで処理する場合は、テナント間でファイルシステムが混在しないよう分離する。
from claude_agent_sdk import query, ClaudeAgentOptions
async def run_for_tenant(tenant_id: str, prompt: str, tenant_dir: str):
"""テナントごとに作業ディレクトリと設定を分離する"""
async for message in query(
prompt=prompt,
options=ClaudeAgentOptions(
cwd=tenant_dir,
setting_sources=[], # ファイルシステムの設定を読み込まない
env={
"CLAUDE_CONFIG_DIR": f"/configs/{tenant_id}",
"CLAUDE_CODE_DISABLE_AUTO_MEMORY": "1",
},
),
):
yield message
async function* runForTenant(tenantId: string, prompt: string, tenantDir: string) {
for await (const message of query({
prompt,
options: {
cwd: tenantDir,
settingSources: [],
env: {
...process.env,
CLAUDE_CONFIG_DIR: `/configs/${tenantId}`,
CLAUDE_CODE_DISABLE_AUTO_MEMORY: "1"
}
}
})) {
yield message;
}
}
GitHub Actions / Webhook連携サンプル
GitHub Actions でPRを自動レビュー
.github/workflows/claude-review.yml として配置する。
name: Claude Code Review
on:
pull_request:
types: [opened, synchronize]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install Claude Agent SDK
run: pip install claude-agent-sdk
- name: Run code review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: python .github/scripts/review.py
# .github/scripts/review.py
import asyncio
import os
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
pr_number = os.getenv("PR_NUMBER")
prompt = f"""
このPR(#{pr_number})の変更内容をレビューしてください。
以下の観点で確認し、Markdownで報告書を作成してください:
- バグの可能性
- セキュリティ上の懸念
- コード品質
- テストの十分性
"""
async for message in query(
prompt=prompt,
options=ClaudeAgentOptions(
allowed_tools=["Read", "Glob", "Grep", "Bash"],
permission_mode="dontAsk", # CI環境なので対話プロンプト禁止
system_prompt="あなたはシニアエンジニアです。コードレビューを行ってください。",
max_turns=20,
),
):
if isinstance(message, ResultMessage):
if message.subtype == "success":
print(message.result)
# GitHubコメントAPIでPRに結果を投稿する処理をここに追加
break
asyncio.run(main())
// .github/scripts/review.ts
import { query, ResultMessage } from "@anthropic-ai/claude-agent-sdk";
const prNumber = process.env.PR_NUMBER;
const prompt = `
このPR(#${prNumber})の変更内容をレビューしてください。
以下の観点で確認し、Markdownで報告書を作成してください:
- バグの可能性
- セキュリティ上の懸念
- コード品質
- テストの十分性
`;
for await (const message of query({
prompt,
options: {
allowedTools: ["Read", "Glob", "Grep", "Bash"],
permissionMode: "dontAsk",
systemPrompt: "あなたはシニアエンジニアです。コードレビューを行ってください。",
maxTurns: 20
}
})) {
if (message.type === "result") {
if (message.subtype === "success" && "result" in message) {
console.log(message.result);
// GitHubコメントAPIでPRに結果を投稿する処理をここに追加
}
break;
}
}
Webhook受信時に自動修正
Express.jsのWebhookサーバーの例:
import express from "express";
import { query } from "@anthropic-ai/claude-agent-sdk";
const app = express();
app.use(express.json());
app.post("/webhook/fix-bug", async (req, res) => {
const { filePath, errorMessage, repository } = req.body;
// 即座にレスポンスを返してWebhookのタイムアウトを防ぐ
res.json({ status: "processing", message: "修正を開始しました" });
// バックグラウンドで修正を実行
(async () => {
const prompt = `
${filePath} でエラーが発生しています:
${errorMessage}
ファイルを読んでエラーの原因を特定し、修正してください。
修正後はテストを実行して動作確認してください。
`;
for await (const message of query({
prompt,
options: {
allowedTools: ["Read", "Edit", "Bash"],
permissionMode: "acceptEdits",
cwd: `/repos/${repository}`,
maxTurns: 15
}
})) {
if (message.type === "result") {
// Slackなどへの通知処理
console.log(`修正完了: ${message.subtype}`);
}
}
})();
});
app.listen(3000);
FAQ(よくある質問)
Q. Claude Agent SDKとManaged Agentsはどう違う?
A. Agent SDKは自分のサーバー上でエージェントループを動かすライブラリ。Managed AgentsはAnthropicのインフラ上でエージェントを動かすREST API。手元のファイルシステムに直接アクセスしたい場合やカスタムHooksが必要な場合はAgent SDK、インフラ管理を任せたい場合はManaged Agentsが向いている。
Q. クレジット消費はAPIキーと別?
A. 2026年6月15日以降、サブスクリプションプランでのAgent SDKと claude -p の使用は、インタラクティブ利用とは別の「月次Agent SDKクレジット」から引き落とされるようになった。詳細はAnthropicのサポートページを確認してほしい。
Q. セッションを跨いで会話を続けられる?
A. できる。SystemMessage の init イベントからセッションIDを取得しておいて、次の query() で resume=session_id を渡すと、前のセッションの文脈(読んだファイル、分析内容、会話履歴)をすべて引き継いで作業を続けられる。
# セッションIDを保存しておく
session_id = None
async for message in query(prompt="認証モジュールを読んで"):
if hasattr(message, "subtype") and message.subtype == "init":
if hasattr(message, "data"):
session_id = message.data["session_id"]
# 別の処理で再開
async for message in query(
prompt="それを呼び出している箇所をすべて見つけて",
options=ClaudeAgentOptions(resume=session_id),
):
if hasattr(message, "result"):
print(message.result)
Q. サブエージェントを使うと何が嬉しい?
A. 並列処理ができる。「コードレビューエージェント」「テスト生成エージェント」「ドキュメント更新エージェント」みたいに専門化したエージェントを定義しておいて、メインエージェントが仕事を振り分けるアーキテクチャが作れる。allowed_tools に "Agent" を追加すると有効になる。
Q. Python 3.9で動かしたらエラーになった
A. Claude Agent SDKはPython 3.10以上が必要。python3 --version でバージョンを確認してアップグレードすること。
Q. Hooksでエラーが発生するとエージェントも止まる?
A. Hook関数内で例外をcatchしておかないと、エージェントの実行が中断される可能性がある。ログ送信や通知など副作用だけのHookは、必ず内部でtry/catchするか、async: true の非同期モードを使って影響を切り離しておく。
Q. claude -p コマンドとの関係は?
A. claude -p はCLIからnon-interactiveにClaude Codeを呼び出すコマンド。Agent SDKはその機能をPython/TypeScriptのライブラリから使えるようにしたもの。内部的には同じエンジンが動いている。
おわりに
Claude Agent SDKを使えば、「CLIで手でやっていた作業」をコードに変換できる。
最初は「APIキーを設定して query() を呼ぶだけ」から始めて、Hooks で細かい制御を加えていくのがスムーズだと思う。GitHubActionsやWebhookとの連携は、一度動くサンプルを作ってから本番に繋げるのが順番として楽だ。
2026年6月以降はサブスクリプションプランでのAgent SDK利用が別クレジットになったので、コスト感は初めに確認しておくといい。