pip install claude-agent-sdkquery() と ClaudeSDKClient の選択Python SDKは、Claude Codeと対話するための2つの方法を提供します:
| 機能 | query() | ClaudeSDKClient |
|---|---|---|
| セッション | 毎回新しいセッションを作成 | 同じセッションを再利用 |
| 会話 | 単一のやり取り | 同じコンテキストで複数のやり取り |
| 接続 | 自動的に管理 | 手動制御 |
| ストリーミング入力 | ✅ サポート | ✅ サポート |
| 中断 | ❌ 非サポート | ✅ サポート |
| フック | ❌ 非サポート | ✅ サポート |
| カスタムツール | ❌ 非サポート | ✅ サポート |
| チャット継続 | ❌ 毎回新しいセッション | ✅ 会話を維持 |
| ユースケース | 単発タスク | 継続的な会話 |
query() を使用する場合(毎回新しいセッション)最適な用途:
ClaudeSDKClient を使用する場合(継続的な会話)最適な用途:
query()Claude Codeとの各インタラクションごとに新しいセッションを作成します。メッセージが到着するたびにそれを生成する非同期イテレータを返します。query() の各呼び出しは、以前のインタラクションの記憶なしに新しく開始されます。
async def query(
*,
prompt: str | AsyncIterable[dict[str, Any]],
options: ClaudeAgentOptions | None = None
) -> AsyncIterator[Message]| パラメータ | 型 | 説明 |
|---|---|---|
prompt | str | AsyncIterable[dict] | 文字列としての入力プロンプト、またはストリーミングモード用の非同期イテラブル |
options | ClaudeAgentOptions | None | オプションの設定オブジェクト(Noneの場合は ClaudeAgentOptions() がデフォルト) |
会話からのメッセージを生成する AsyncIterator[Message] を返します。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
options = ClaudeAgentOptions(
system_prompt="You are an expert Python developer",
permission_mode='acceptEdits',
cwd="/home/user/project"
)
async for message in query(
prompt="Create a Python web server",
options=options
):
print(message)
asyncio.run(main())tool()型安全性を備えたMCPツールを定義するためのデコレータ。
def tool(
name: str,
description: str,
input_schema: type | dict[str, Any]
) -> Callable[[Callable[[Any], Awaitable[dict[str, Any]]]], SdkMcpTool[Any]]| パラメータ | 型 | 説明 |
|---|---|---|
name | str | ツールの一意の識別子 |
description | str | ツールの機能を説明する人間が読める説明 |
input_schema | type | dict[str, Any] | ツールの入力パラメータを定義するスキーマ(以下参照) |
シンプルな型マッピング(推奨):
{"text": str, "count": int, "enabled": bool}JSONスキーマ形式(複雑なバリデーション用):
{
"type": "object",
"properties": {
"text": {"type": "string"},
"count": {"type": "integer", "minimum": 0}
},
"required": ["text"]
}ツールの実装をラップし、SdkMcpTool インスタンスを返すデコレータ関数。
from claude_agent_sdk import tool
from typing import Any
@tool("greet", "Greet a user", {"name": str})
async def greet(args: dict[str, Any]) -> dict[str, Any]:
return {
"content": [{
"type": "text",
"text": f"Hello, {args['name']}!"
}]
}create_sdk_mcp_server()Pythonアプリケーション内で実行されるインプロセスMCPサーバーを作成します。
def create_sdk_mcp_server(
name: str,
version: str = "1.0.0",
tools: list[SdkMcpTool[Any]] | None = None
) -> McpSdkServerConfig| パラメータ | 型 | デフォルト | 説明 |
|---|---|---|---|
name | str | - | サーバーの一意の識別子 |
version | str | "1.0.0" | サーバーバージョン文字列 |
tools | list[SdkMcpTool[Any]] | None | None | @tool デコレータで作成されたツール関数のリスト |
ClaudeAgentOptions.mcp_servers に渡すことができる McpSdkServerConfig オブジェクトを返します。
from claude_agent_sdk import tool, create_sdk_mcp_server
@tool("add", "Add two numbers", {"a": float, "b": float})
async def add(args):
return {
"content": [{
"type": "text",
"text": f"Sum: {args['a'] + args['b']}"
}]
}
@tool("multiply", "Multiply two numbers", {"a": float, "b": float})
async def multiply(args):
return {
"content": [{
"type": "text",
"text": f"Product: {args['a'] * args['b']}"
}]
}
calculator = create_sdk_mcp_server(
name="calculator",
version="2.0.0",
tools=[add, multiply] # Pass decorated functions
)
# Use with Claude
options = ClaudeAgentOptions(
mcp_servers={"calc": calculator},
allowed_tools=["mcp__calc__add", "mcp__calc__multiply"]
)ClaudeSDKClient複数のやり取りにわたって会話セッションを維持します。 これは、TypeScript SDKの query() 関数が内部的に動作する方法のPython版に相当します - 会話を継続できるクライアントオブジェクトを作成します。
query() 呼び出しにわたって会話コンテキストを維持@tool デコレータで作成)とフックをサポートclass ClaudeSDKClient:
def __init__(self, options: ClaudeAgentOptions | None = None)
async def connect(self, prompt: str | AsyncIterable[dict] | None = None) -> None
async def query(self, prompt: str | AsyncIterable[dict], session_id: str = "default") -> None
async def receive_messages(self) -> AsyncIterator[Message]
async def receive_response(self) -> AsyncIterator[Message]
async def interrupt(self) -> None
async def rewind_files(self, user_message_uuid: str) -> None
async def disconnect(self) -> None| メソッド | 説明 |
|---|---|
__init__(options) | オプションの設定でクライアントを初期化 |
connect(prompt) | オプションの初期プロンプトまたはメッセージストリームでClaudeに接続 |
query(prompt, session_id) | ストリーミングモードで新しいリクエストを送信 |
receive_messages() | Claudeからのすべてのメッセージを非同期イテレータとして受信 |
receive_response() | ResultMessageを含むまでメッセージを受信 |
interrupt() | 中断シグナルを送信(ストリーミングモードでのみ動作) |
rewind_files(user_message_uuid) | 指定されたユーザーメッセージの状態にファイルを復元。enable_file_checkpointing=True が必要。ファイルチェックポイントを参照 |
disconnect() | Claudeから切断 |
クライアントは、自動接続管理のための非同期コンテキストマネージャーとして使用できます:
async with ClaudeSDKClient() as client:
await client.query("Hello Claude")
async for message in client.receive_response():
print(message)重要: メッセージをイテレートする際、
breakを使用して早期に終了することは避けてください。asyncioのクリーンアップの問題が発生する可能性があります。代わりに、イテレーションを自然に完了させるか、必要なものが見つかったことを追跡するフラグを使用してください。
import asyncio
from claude_agent_sdk import ClaudeSDKClient, AssistantMessage, TextBlock, ResultMessage
async def main():
async with ClaudeSDKClient() as client:
# 最初の質問
await client.query("What's the capital of France?")
# 応答を処理
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Claude: {block.text}")
# フォローアップの質問 - Claudeは以前のコンテキストを記憶している
await client.query("What's the population of that city?")
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Claude: {block.text}")
# さらにフォローアップ - まだ同じ会話内
await client.query("What are some famous landmarks there?")
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Claude: {block.text}")
asyncio.run(main())import asyncio
from claude_agent_sdk import ClaudeSDKClient
async def message_stream():
"""メッセージを動的に生成。"""
yield {"type": "text", "text": "Analyze the following data:"}
await asyncio.sleep(0.5)
yield {"type": "text", "text": "Temperature: 25°C"}
await asyncio.sleep(0.5)
yield {"type": "text", "text": "Humidity: 60%"}
await asyncio.sleep(0.5)
yield {"type": "text", "text": "What patterns do you see?"}
async def main():
async with ClaudeSDKClient() as client:
# Claudeに入力をストリーミング
await client.query(message_stream())
# 応答を処理
async for message in client.receive_response():
print(message)
# 同じセッションでフォローアップ
await client.query("Should we be concerned about these readings?")
async for message in client.receive_response():
print(message)
asyncio.run(main())import asyncio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
async def interruptible_task():
options = ClaudeAgentOptions(
allowed_tools=["Bash"],
permission_mode="acceptEdits"
)
async with ClaudeSDKClient(options=options) as client:
# 長時間実行タスクを開始
await client.query("Count from 1 to 100 slowly")
# しばらく実行させる
await asyncio.sleep(2)
# タスクを中断
await client.interrupt()
print("Task interrupted!")
# 新しいコマンドを送信
await client.query("Just say hello instead")
async for message in client.receive_response():
# 新しい応答を処理
pass
asyncio.run(interruptible_task())from claude_agent_sdk import (
ClaudeSDKClient,
ClaudeAgentOptions
)
from claude_agent_sdk.types import PermissionResultAllow, PermissionResultDeny
async def custom_permission_handler(
tool_name: str,
input_data: dict,
context: dict
) -> PermissionResultAllow | PermissionResultDeny:
"""ツール権限のカスタムロジック。"""
# システムディレクトリへの書き込みをブロック
if tool_name == "Write" and input_data.get("file_path", "").startswith("/system/"):
return PermissionResultDeny(
message="System directory write not allowed",
interrupt=True
)
# 機密ファイル操作をリダイレクト
if tool_name in ["Write", "Edit"] and "config" in input_data.get("file_path", ""):
safe_path = f"./sandbox/{input_data['file_path']}"
return PermissionResultAllow(
updated_input={**input_data, "file_path": safe_path}
)
# その他はすべて許可
return PermissionResultAllow(updated_input=input_data)
async def main():
options = ClaudeAgentOptions(
can_use_tool=custom_permission_handler,
allowed_tools=["Read", "Write", "Edit"]
)
async with ClaudeSDKClient(options=options) as client:
await client.query("Update the system config file")
async for message in client.receive_response():
# サンドボックスパスを代わりに使用
print(message)
asyncio.run(main())SdkMcpTool@tool デコレータで作成されたSDK MCPツールの定義。
@dataclass
class SdkMcpTool(Generic[T]):
name: str
description: str
input_schema: type[T] | dict[str, Any]
handler: Callable[[T], Awaitable[dict[str, Any]]]| プロパティ | 型 | 説明 |
|---|---|---|
name | str | ツールの一意の識別子 |
description | str | 人間が読める説明 |
input_schema | type[T] | dict[str, Any] | 入力バリデーション用スキーマ |
handler | Callable[[T], Awaitable[dict[str, Any]]] | ツール実行を処理する非同期関数 |
ClaudeAgentOptionsClaude Codeクエリ用の設定データクラス。
@dataclass
class ClaudeAgentOptions:
tools: list[str] | ToolsPreset | None = None
allowed_tools: list[str] = field(default_factory=list)
system_prompt: str | SystemPromptPreset | None = None
mcp_servers: dict[str, McpServerConfig] | str | Path = field(default_factory=dict)
permission_mode: PermissionMode | None = None
continue_conversation: bool = False
resume: str | None = None
max_turns: int | None = None
max_budget_usd: float | None = None
disallowed_tools: list[str] = field(default_factory=list)
model: str | None = None
fallback_model: str | None = None
betas: list[SdkBeta] = field(default_factory=list)
output_format: OutputFormat | None = None
permission_prompt_tool_name: str | None = None
cwd: str | Path | None = None
cli_path: str | Path | None = None
settings: str | None = None
add_dirs: list[str | Path] = field(default_factory=list)
env: dict[str, str] = field(default_factory=dict)
extra_args: dict[str, str | None] = field(default_factory=dict)
max_buffer_size: int | None = None
debug_stderr: Any = sys.stderr # Deprecated
stderr: Callable[[str], None] | None = None
can_use_tool: CanUseTool | None = None
hooks: dict[HookEvent, list[HookMatcher]] | None = None
user: str | None = None
include_partial_messages: bool = False
fork_session: bool = False
agents: dict[str, AgentDefinition] | None = None
setting_sources: list[SettingSource] | None = None
max_thinking_tokens: int | None = None| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
tools | list[str] | ToolsPreset | None | None | ツール設定。Claude Codeのデフォルトツールには {"type": "preset", "preset": "claude_code"} を使用 |
allowed_tools | list[str] | [] | 許可されたツール名のリスト |
system_prompt | str | SystemPromptPreset | None | None | システムプロンプト設定。カスタムプロンプトには文字列を渡すか、Claude Codeのシステムプロンプトには {"type": "preset", "preset": "claude_code"} を使用。プリセットを拡張するには "append" を追加 |
mcp_servers | dict[str, McpServerConfig] | str | Path | {} | MCPサーバー設定または設定ファイルへのパス |
permission_mode | PermissionMode | None | None | ツール使用の権限モード |
continue_conversation | bool | False | 最新の会話を継続 |
resume | str | None | None | 再開するセッションID |
max_turns | int | None | None | 最大会話ターン数 |
max_budget_usd | float | None | None | セッションの最大予算(USD) |
disallowed_tools | list[str] | [] | 禁止されたツール名のリスト |
enable_file_checkpointing | bool | False | 巻き戻し用のファイル変更追跡を有効化。ファイルチェックポイントを参照 |
model | str | None | None | 使用するClaudeモデル |
fallback_model | str | None | None | プライマリモデルが失敗した場合に使用するフォールバックモデル |
betas | list[SdkBeta] | [] | 有効にするベータ機能。利用可能なオプションについては SdkBeta を参照 |
output_format | OutputFormat | None | None | エージェント結果の出力形式を定義。詳細は構造化出力を参照 |
permission_prompt_tool_name | str | None | None | 権限プロンプト用のMCPツール名 |
cwd | str | Path | None | None | 現在の作業ディレクトリ |
cli_path | str | Path | None | None | Claude Code CLI実行ファイルへのカスタムパス |
settings | str | None | None | 設定ファイルへのパス |
add_dirs | list[str | Path] | [] | Claudeがアクセスできる追加ディレクトリ |
env | dict[str, str] | {} | 環境変数 |
extra_args | dict[str, str | None] | {} | CLIに直接渡す追加のCLI引数 |
max_buffer_size | int | None | None | CLI stdoutをバッファリングする際の最大バイト数 |
debug_stderr | Any | sys.stderr | 非推奨 - デバッグ出力用のファイルライクオブジェクト。代わりに stderr コールバックを使用 |
stderr | Callable[[str], None] | None | None | CLIからのstderr出力用コールバック関数 |
can_use_tool | CanUseTool | None | None | ツール権限コールバック関数。詳細は権限タイプを参照 |
hooks | dict[HookEvent, list[HookMatcher]] | None | None | イベントをインターセプトするためのフック設定 |
user | str | None | None | ユーザー識別子 |
include_partial_messages | bool | False | 部分メッセージストリーミングイベントを含める。有効にすると、StreamEvent メッセージが生成される |
fork_session | bool | False | resume で再開する際、元のセッションを継続する代わりに新しいセッションIDにフォーク |
agents | dict[str, AgentDefinition] | None | None | プログラムで定義されたサブエージェント |
plugins | list[SdkPluginConfig] | [] | ローカルパスからカスタムプラグインを読み込む。詳細はプラグインを参照 |
sandbox | SandboxSettings | None | None | サンドボックスの動作をプログラムで設定。詳細はサンドボックス設定を参照 |
setting_sources | list[SettingSource] | None | None(設定なし) | 読み込むファイルシステム設定を制御。省略時は設定が読み込まれない。注意: CLAUDE.mdファイルを読み込むには "project" を含める必要がある |
max_thinking_tokens | int | None | None | 思考ブロックの最大トークン数 |
OutputFormat構造化出力バリデーション用の設定。
class OutputFormat(TypedDict):
type: Literal["json_schema"]
schema: dict[str, Any]| フィールド | 必須 | 説明 |
|---|---|---|
type | はい | JSONスキーマバリデーション用に "json_schema" でなければならない |
schema | はい | 出力バリデーション用のJSONスキーマ定義 |
SystemPromptPresetClaude Codeのプリセットシステムプロンプトをオプションの追加付きで使用するための設定。
class SystemPromptPreset(TypedDict):
type: Literal["preset"]
preset: Literal["claude_code"]
append: NotRequired[str]| フィールド | 必須 | 説明 |
|---|---|---|
type | はい | プリセットシステムプロンプトを使用するには "preset" でなければならない |
preset | はい | Claude Codeのシステムプロンプトを使用するには "claude_code" でなければならない |
append | いいえ | プリセットシステムプロンプトに追加する追加の指示 |
SettingSourceSDKが設定を読み込むファイルシステムベースの設定ソースを制御します。
SettingSource = Literal["user", "project", "local"]| 値 | 説明 | 場所 |
|---|---|---|
"user" | グローバルユーザー設定 | ~/.claude/settings.json |
"project" | 共有プロジェクト設定(バージョン管理対象) | .claude/settings.json |
"local" | ローカルプロジェクト設定(gitignore対象) | .claude/settings.local.json |
setting_sources が省略または**Noneの場合、SDKはファイルシステム設定を読み込みません**。これにより、SDKアプリケーションの分離が提供されます。
すべてのファイルシステム設定を読み込む(レガシー動作):
# SDK v0.0.xのようにすべての設定を読み込む
from claude_agent_sdk import query, ClaudeAgentOptions
async for message in query(
prompt="Analyze this code",
options=ClaudeAgentOptions(
setting_sources=["user", "project", "local"] # すべての設定を読み込む
)
):
print(message)特定の設定ソースのみを読み込む:
# プロジェクト設定のみを読み込み、ユーザーとローカルは無視
async for message in query(
prompt="Run CI checks",
options=ClaudeAgentOptions(
setting_sources=["project"] # .claude/settings.json のみ
)
):
print(message)テストおよびCI環境:
# ローカル設定を除外してCIでの一貫した動作を確保
async for message in query(
prompt="Run tests",
options=ClaudeAgentOptions(
setting_sources=["project"], # チーム共有設定のみ
permission_mode="bypassPermissions"
)
):
print(message)SDK専用アプリケーション:
# すべてをプログラムで定義(デフォルトの動作)
# ファイルシステム依存なし - setting_sourcesはデフォルトでNone
async for message in query(
prompt="Review this PR",
options=ClaudeAgentOptions(
# setting_sources=None がデフォルト、指定不要
agents={ /* ... */ },
mcp_servers={ /* ... */ },
allowed_tools=["Read", "Grep", "Glob"]
)
):
print(message)CLAUDE.mdプロジェクト指示の読み込み:
# CLAUDE.mdファイルを含めるためにプロジェクト設定を読み込む
async for message in query(
prompt="Add a new feature following project conventions",
options=ClaudeAgentOptions(
system_prompt={
"type": "preset",
"preset": "claude_code" # Claude Codeのシステムプロンプトを使用
},
setting_sources=["project"], # プロジェクトからCLAUDE.mdを読み込むために必要
allowed_tools=["Read", "Write", "Edit"]
)
):
print(message)複数のソースが読み込まれる場合、設定は以下の優先順位でマージされます(高い順):
.claude/settings.local.json).claude/settings.json)~/.claude/settings.json)プログラムオプション(agents、allowed_tools など)は常にファイルシステム設定を上書きします。
AgentDefinitionプログラムで定義されたサブエージェントの設定。
@dataclass
class AgentDefinition:
description: str
prompt: str
tools: list[str] | None = None
model: Literal["sonnet", "opus", "haiku", "inherit"] | None = None| フィールド | 必須 | 説明 |
|---|---|---|
description | はい | このエージェントをいつ使用するかの自然言語による説明 |
tools | いいえ | 許可されたツール名の配列。省略時はすべてのツールを継承 |
prompt | はい | エージェントのシステムプロンプト |
model | いいえ | このエージェントのモデルオーバーライド。省略時はメインモデルを使用 |
PermissionModeツール実行を制御するための権限モード。
PermissionMode = Literal[
"default", # 標準の権限動作
"acceptEdits", # ファイル編集を自動承認
"plan", # 計画モード - 実行なし
"bypassPermissions" # すべての権限チェックをバイパス(注意して使用)
]CanUseToolツール権限コールバック関数の型エイリアス。
CanUseTool = Callable[
[str, dict[str, Any], ToolPermissionContext],
Awaitable[PermissionResult]
]コールバックは以下を受け取ります:
tool_name: 呼び出されるツールの名前input_data: ツールの入力パラメータcontext: 追加情報を含む ToolPermissionContextPermissionResult(PermissionResultAllow または PermissionResultDeny)を返します。
ToolPermissionContextツール権限コールバックに渡されるコンテキスト情報。
@dataclass
class ToolPermissionContext:
signal: Any | None = None # Future: abort signal support
suggestions: list[PermissionUpdate] = field(default_factory=list)| フィールド | 型 | 説明 |
|---|---|---|
signal | Any | None | 将来のアボートシグナルサポート用に予約済み |
suggestions | list[PermissionUpdate] | CLIからの権限更新の提案 |
PermissionResult権限コールバック結果のユニオン型。
PermissionResult = PermissionResultAllow | PermissionResultDenyPermissionResultAllowツール呼び出しを許可すべきことを示す結果。
@dataclass
class PermissionResultAllow:
behavior: Literal["allow"] = "allow"
updated_input: dict[str, Any] | None = None
updated_permissions: list[PermissionUpdate] | None = None| フィールド | 型 | デフォルト | 説明 |
|---|---|---|---|
behavior | Literal["allow"] | "allow" | "allow" でなければならない |
updated_input | dict[str, Any] | None | None | 元の入力の代わりに使用する変更された入力 |
updated_permissions | list[PermissionUpdate] | None | None | 適用する権限の更新 |
PermissionResultDenyツール呼び出しを拒否すべきことを示す結果。
@dataclass
class PermissionResultDeny:
behavior: Literal["deny"] = "deny"
message: str = ""
interrupt: bool = False| フィールド | 型 | デフォルト | 説明 |
|---|---|---|---|
behavior | Literal["deny"] | "deny" | "deny" でなければならない |
message | str | "" | ツールが拒否された理由を説明するメッセージ |
interrupt | bool | False | 現在の実行を中断するかどうか |
PermissionUpdateプログラムによる権限更新の設定。
@dataclass
class PermissionUpdate:
type: Literal[
"addRules",
"replaceRules",
"removeRules",
"setMode",
"addDirectories",
"removeDirectories",
]
rules: list[PermissionRuleValue] | None = None
behavior: Literal["allow", "deny", "ask"] | None = None
mode: PermissionMode | None = None
directories: list[str] | None = None
destination: Literal["userSettings", "projectSettings", "localSettings", "session"] | None = None| フィールド | 型 | 説明 |
|---|---|---|
type | Literal[...] | 権限更新操作の種類 |
rules | list[PermissionRuleValue] | None | 追加/置換/削除操作のルール |
behavior | Literal["allow", "deny", "ask"] | None | ルールベース操作の動作 |
mode | PermissionMode | None | setMode操作のモード |
directories | list[str] | None | ディレクトリの追加/削除操作のディレクトリ |
destination | Literal[...] | None | 権限更新を適用する場所 |
SdkBetaSDKベータ機能のリテラル型。
SdkBeta = Literal["context-1m-2025-08-07"]ClaudeAgentOptions の betas フィールドと共に使用してベータ機能を有効にします。
McpSdkServerConfigcreate_sdk_mcp_server() で作成されたSDK MCPサーバーの設定。
class McpSdkServerConfig(TypedDict):
type: Literal["sdk"]
name: str
instance: Any # MCP Server instanceMcpServerConfigMCPサーバー設定のユニオン型。
McpServerConfig = McpStdioServerConfig | McpSSEServerConfig | McpHttpServerConfig | McpSdkServerConfigMcpStdioServerConfigclass McpStdioServerConfig(TypedDict):
type: NotRequired[Literal["stdio"]] # Optional for backwards compatibility
command: str
args: NotRequired[list[str]]
env: NotRequired[dict[str, str]]McpSSEServerConfigclass McpSSEServerConfig(TypedDict):
type: Literal["sse"]
url: str
headers: NotRequired[dict[str, str]]McpHttpServerConfigclass McpHttpServerConfig(TypedDict):
type: Literal["http"]
url: str
headers: NotRequired[dict[str, str]]SdkPluginConfigSDKでプラグインを読み込むための設定。
class SdkPluginConfig(TypedDict):
type: Literal["local"]
path: str| フィールド | 型 | 説明 |
|---|---|---|
type | Literal["local"] | "local" でなければならない(現在ローカルプラグインのみサポート) |
path | str | プラグインディレクトリへの絶対パスまたは相対パス |
例:
plugins=[
{"type": "local", "path": "./my-plugin"},
{"type": "local", "path": "/absolute/path/to/plugin"}
]プラグインの作成と使用に関する完全な情報については、プラグインを参照してください。
Messageすべての可能なメッセージのユニオン型。
Message = UserMessage | AssistantMessage | SystemMessage | ResultMessage | StreamEventUserMessageユーザー入力メッセージ。
@dataclass
class UserMessage:
content: str | list[ContentBlock]AssistantMessageコンテンツブロックを含むアシスタント応答メッセージ。
@dataclass
class AssistantMessage:
content: list[ContentBlock]
model: strSystemMessageメタデータを含むシステムメッセージ。
@dataclass
class SystemMessage:
subtype: str
data: dict[str, Any]ResultMessageコストと使用量情報を含む最終結果メッセージ。
@dataclass
class ResultMessage:
subtype: str
duration_ms: int
duration_api_ms: int
is_error: bool
num_turns: int
session_id: str
total_cost_usd: float | None = None
usage: dict[str, Any] | None = None
result: str | None = None
structured_output: Any = NoneStreamEventストリーミング中の部分的なメッセージ更新のためのストリームイベント。ClaudeAgentOptions で include_partial_messages=True の場合にのみ受信されます。
@dataclass
class StreamEvent:
uuid: str
session_id: str
event: dict[str, Any] # The raw Anthropic API stream event
parent_tool_use_id: str | None = None| フィールド | 型 | 説明 |
|---|---|---|
uuid | str | このイベントの一意識別子 |
session_id | str | セッション識別子 |
event | dict[str, Any] | 生のAnthropic APIストリームイベントデータ |
parent_tool_use_id | str | None | このイベントがサブエージェントからのものである場合の親ツール使用ID |
ContentBlockすべてのコンテンツブロックのユニオン型。
ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlockTextBlockテキストコンテンツブロック。
@dataclass
class TextBlock:
text: strThinkingBlock思考コンテンツブロック(思考機能を持つモデル用)。
@dataclass
class ThinkingBlock:
thinking: str
signature: strToolUseBlockツール使用リクエストブロック。
@dataclass
class ToolUseBlock:
id: str
name: str
input: dict[str, Any]ToolResultBlockツール実行結果ブロック。
@dataclass
class ToolResultBlock:
tool_use_id: str
content: str | list[dict[str, Any]] | None = None
is_error: bool | None = NoneClaudeSDKErrorすべてのSDKエラーの基底例外クラス。
class ClaudeSDKError(Exception):
"""Base error for Claude SDK."""CLINotFoundErrorClaude Code CLIがインストールされていないか見つからない場合に発生します。
class CLINotFoundError(CLIConnectionError):
def __init__(self, message: str = "Claude Code not found", cli_path: str | None = None):
"""
Args:
message: Error message (default: "Claude Code not found")
cli_path: Optional path to the CLI that was not found
"""CLIConnectionErrorClaude Codeへの接続が失敗した場合に発生します。
class CLIConnectionError(ClaudeSDKError):
"""Failed to connect to Claude Code."""ProcessErrorClaude Codeプロセスが失敗した場合に発生します。
class ProcessError(ClaudeSDKError):
def __init__(self, message: str, exit_code: int | None = None, stderr: str | None = None):
self.exit_code = exit_code
self.stderr = stderrCLIJSONDecodeErrorJSONパースが失敗した場合に発生します。
class CLIJSONDecodeError(ClaudeSDKError):
def __init__(self, line: str, original_error: Exception):
"""
Args:
line: The line that failed to parse
original_error: The original JSON decode exception
"""
self.line = line
self.original_error = original_errorフックの使用方法に関する包括的なガイド(例と一般的なパターンを含む)については、フックガイドを参照してください。
HookEventサポートされるフックイベント型。セットアップの制限により、Python SDKはSessionStart、SessionEnd、およびNotificationフックをサポートしていないことに注意してください。
HookEvent = Literal[
"PreToolUse", # Called before tool execution
"PostToolUse", # Called after tool execution
"UserPromptSubmit", # Called when user submits a prompt
"Stop", # Called when stopping execution
"SubagentStop", # Called when a subagent stops
"PreCompact" # Called before message compaction
]HookCallbackフックコールバック関数の型定義。
HookCallback = Callable[
[dict[str, Any], str | None, HookContext],
Awaitable[dict[str, Any]]
]パラメータ:
input_data: フック固有の入力データ(フックガイドを参照)tool_use_id: オプションのツール使用識別子(ツール関連のフック用)context: 追加情報を含むフックコンテキスト以下を含む可能性のある辞書を返します:
decision: アクションをブロックする場合は "block"systemMessage: トランスクリプトに追加するシステムメッセージhookSpecificOutput: フック固有の出力データHookContextフックコールバックに渡されるコンテキスト情報。
@dataclass
class HookContext:
signal: Any | None = None # Future: abort signal supportHookMatcher特定のイベントやツールにフックをマッチングするための設定。
@dataclass
class HookMatcher:
matcher: str | None = None # Tool name or pattern to match (e.g., "Bash", "Write|Edit")
hooks: list[HookCallback] = field(default_factory=list) # List of callbacks to execute
timeout: float | None = None # Timeout in seconds for all hooks in this matcher (default: 60)HookInputすべてのフック入力型のユニオン型。実際の型は hook_event_name フィールドに依存します。
HookInput = (
PreToolUseHookInput
| PostToolUseHookInput
| UserPromptSubmitHookInput
| StopHookInput
| SubagentStopHookInput
| PreCompactHookInput
)BaseHookInputすべてのフック入力型に存在する基本フィールド。
class BaseHookInput(TypedDict):
session_id: str
transcript_path: str
cwd: str
permission_mode: NotRequired[str]| フィールド | 型 | 説明 |
|---|---|---|
session_id | str | 現在のセッション識別子 |
transcript_path | str | セッショントランスクリプトファイルへのパス |
cwd | str | 現在の作業ディレクトリ |
permission_mode | str(オプション) | 現在の権限モード |
PreToolUseHookInputPreToolUse フックイベントの入力データ。
class PreToolUseHookInput(BaseHookInput):
hook_event_name: Literal["PreToolUse"]
tool_name: str
tool_input: dict[str, Any]| フィールド | 型 | 説明 |
|---|---|---|
hook_event_name | Literal["PreToolUse"] | 常に "PreToolUse" |
tool_name | str | 実行されようとしているツールの名前 |
tool_input | dict[str, Any] | ツールの入力パラメータ |
PostToolUseHookInputPostToolUse フックイベントの入力データ。
class PostToolUseHookInput(BaseHookInput):
hook_event_name: Literal["PostToolUse"]
tool_name: str
tool_input: dict[str, Any]
tool_response: Any| フィールド | 型 | 説明 |
|---|---|---|
hook_event_name | Literal["PostToolUse"] | 常に "PostToolUse" |
tool_name | str | 実行されたツールの名前 |
tool_input | dict[str, Any] | 使用された入力パラメータ |
tool_response | Any | ツール実行からの応答 |
UserPromptSubmitHookInputUserPromptSubmit フックイベントの入力データ。
class UserPromptSubmitHookInput(BaseHookInput):
hook_event_name: Literal["UserPromptSubmit"]
prompt: str| フィールド | 型 | 説明 |
|---|---|---|
hook_event_name | Literal["UserPromptSubmit"] | 常に "UserPromptSubmit" |
prompt | str | ユーザーが送信したプロンプト |
StopHookInputStop フックイベントの入力データ。
class StopHookInput(BaseHookInput):
hook_event_name: Literal["Stop"]
stop_hook_active: bool| フィールド | 型 | 説明 |
|---|---|---|
hook_event_name | Literal["Stop"] | 常に "Stop" |
stop_hook_active | bool | ストップフックがアクティブかどうか |
SubagentStopHookInputSubagentStop フックイベントの入力データ。
class SubagentStopHookInput(BaseHookInput):
hook_event_name: Literal["SubagentStop"]
stop_hook_active: bool| フィールド | 型 | 説明 |
|---|---|---|
hook_event_name | Literal["SubagentStop"] | 常に "SubagentStop" |
stop_hook_active | bool | ストップフックがアクティブかどうか |
PreCompactHookInputPreCompact フックイベントの入力データ。
class PreCompactHookInput(BaseHookInput):
hook_event_name: Literal["PreCompact"]
trigger: Literal["manual", "auto"]
custom_instructions: str | None| フィールド | 型 | 説明 |
|---|---|---|
hook_event_name | Literal["PreCompact"] | 常に "PreCompact" |
trigger | Literal["manual", "auto"] | コンパクションをトリガーしたもの |
custom_instructions | str | None | コンパクション用のカスタム指示 |
HookJSONOutputフックコールバック戻り値のユニオン型。
HookJSONOutput = AsyncHookJSONOutput | SyncHookJSONOutputSyncHookJSONOutput制御フィールドと決定フィールドを含む同期フック出力。
class SyncHookJSONOutput(TypedDict):
# Control fields
continue_: NotRequired[bool] # Whether to proceed (default: True)
suppressOutput: NotRequired[bool] # Hide stdout from transcript
stopReason: NotRequired[str] # Message when continue is False
# Decision fields
decision: NotRequired[Literal["block"]]
systemMessage: NotRequired[str] # Warning message for user
reason: NotRequired[str] # Feedback for Claude
# Hook-specific output
hookSpecificOutput: NotRequired[dict[str, Any]]Pythonコードでは continue_(アンダースコア付き)を使用してください。CLIに送信される際に自動的に continue に変換されます。
AsyncHookJSONOutputフック実行を遅延させる非同期フック出力。
class AsyncHookJSONOutput(TypedDict):
async_: Literal[True] # Set to True to defer execution
asyncTimeout: NotRequired[int] # Timeout in millisecondsPythonコードでは async_(アンダースコア付き)を使用してください。CLIに送信される際に自動的に async に変換されます。
この例では2つのフックを登録しています:rm -rf / のような危険なbashコマンドをブロックするものと、監査のためにすべてのツール使用をログに記録するものです。セキュリティフックは(matcher を介して)Bashコマンドに対してのみ実行され、ログフックはすべてのツールに対して実行されます。
from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher, HookContext
from typing import Any
async def validate_bash_command(
input_data: dict[str, Any],
tool_use_id: str | None,
context: HookContext
) -> dict[str, Any]:
"""Validate and potentially block dangerous bash commands."""
if input_data['tool_name'] == 'Bash':
command = input_data['tool_input'].get('command', '')
if 'rm -rf /' in command:
return {
'hookSpecificOutput': {
'hookEventName': 'PreToolUse',
'permissionDecision': 'deny',
'permissionDecisionReason': 'Dangerous command blocked'
}
}
return {}
async def log_tool_use(
input_data: dict[str, Any],
tool_use_id: str | None,
context: HookContext
) -> dict[str, Any]:
"""Log all tool usage for auditing."""
print(f"Tool used: {input_data.get('tool_name')}")
return {}
options = ClaudeAgentOptions(
hooks={
'PreToolUse': [
HookMatcher(matcher='Bash', hooks=[validate_bash_command], timeout=120), # 2 min for validation
HookMatcher(hooks=[log_tool_use]) # Applies to all tools (default 60s timeout)
],
'PostToolUse': [
HookMatcher(hooks=[log_tool_use])
]
}
)
async for message in query(
prompt="Analyze this codebase",
options=options
):
print(message)すべての組み込みClaude Codeツールの入出力スキーマのドキュメント。Python SDKはこれらを型としてエクスポートしませんが、メッセージ内のツール入出力の構造を表しています。
ツール名: Task
入力:
{
"description": str, # A short (3-5 word) description of the task
"prompt": str, # The task for the agent to perform
"subagent_type": str # The type of specialized agent to use
}出力:
{
"result": str, # Final result from the subagent
"usage": dict | None, # Token usage statistics
"total_cost_usd": float | None, # Total cost in USD
"duration_ms": int | None # Execution duration in milliseconds
}ツール名: AskUserQuestion
実行中にユーザーに明確化のための質問をします。使用方法の詳細については、承認とユーザー入力の処理を参照してください。
入力:
{
"questions": [ # Questions to ask the user (1-4 questions)
{
"question": str, # The complete question to ask the user
"header": str, # Very short label displayed as a chip/tag (max 12 chars)
"options": [ # The available choices (2-4 options)
{
"label": str, # Display text for this option (1-5 words)
"description": str # Explanation of what this option means
}
],
"multiSelect": bool # Set to true to allow multiple selections
}
],
"answers": dict | None # User answers populated by the permission system
}出力:
{
"questions": [ # The questions that were asked
{
"question": str,
"header": str,
"options": [{"label": str, "description": str}],
"multiSelect": bool
}
],
"answers": dict[str, str] # Maps question text to answer string
# Multi-select answers are comma-separated
}ツール名: Bash
入力:
{
"command": str, # The command to execute
"timeout": int | None, # Optional timeout in milliseconds (max 600000)
"description": str | None, # Clear, concise description (5-10 words)
"run_in_background": bool | None # Set to true to run in background
}出力:
{
"output": str, # Combined stdout and stderr output
"exitCode": int, # Exit code of the command
"killed": bool | None, # Whether command was killed due to timeout
"shellId": str | None # Shell ID for background processes
}ツール名: Edit
入力:
{
"file_path": str, # The absolute path to the file to modify
"old_string": str, # The text to replace
"new_string": str, # The text to replace it with
"replace_all": bool | None # Replace all occurrences (default False)
}出力:
{
"message": str, # Confirmation message
"replacements": int, # Number of replacements made
"file_path": str # File path that was edited
}ツール名: Read
入力:
{
"file_path": str, # The absolute path to the file to read
"offset": int | None, # The line number to start reading from
"limit": int | None # The number of lines to read
}出力(テキストファイル):
{
"content": str, # File contents with line numbers
"total_lines": int, # Total number of lines in file
"lines_returned": int # Lines actually returned
}出力(画像):
{
"image": str, # Base64 encoded image data
"mime_type": str, # Image MIME type
"file_size": int # File size in bytes
}ツール名: Write
入力:
{
"file_path": str, # The absolute path to the file to write
"content": str # The content to write to the file
}出力:
{
"message": str, # Success message
"bytes_written": int, # Number of bytes written
"file_path": str # File path that was written
}ツール名: Glob
入力:
{
"pattern": str, # The glob pattern to match files against
"path": str | None # The directory to search in (defaults to cwd)
}出力:
{
"matches": list[str], # Array of matching file paths
"count": int, # Number of matches found
"search_path": str # Search directory used
}ツール名: Grep
入力:
{
"pattern": str, # The regular expression pattern
"path": str | None, # File or directory to search in
"glob": str | None, # Glob pattern to filter files
"type": str | None, # File type to search
"output_mode": str | None, # "content", "files_with_matches", or "count"
"-i": bool | None, # Case insensitive search
"-n": bool | None, # Show line numbers
"-B": int | None, # Lines to show before each match
"-A": int | None, # Lines to show after each match
"-C": int | None, # Lines to show before and after
"head_limit": int | None, # Limit output to first N lines/entries
"multiline": bool | None # Enable multiline mode
}出力(contentモード):
{
"matches": [
{
"file": str,
"line_number": int | None,
"line": str,
"before_context": list[str] | None,
"after_context": list[str] | None
}
],
"total_matches": int
}出力(files_with_matchesモード):
{
"files": list[str], # Files containing matches
"count": int # Number of files with matches
}ツール名: NotebookEdit
入力:
{
"notebook_path": str, # Absolute path to the Jupyter notebook
"cell_id": str | None, # The ID of the cell to edit
"new_source": str, # The new source for the cell
"cell_type": "code" | "markdown" | None, # The type of the cell
"edit_mode": "replace" | "insert" | "delete" | None # Edit operation type
}出力:
{
"message": str, # Success message
"edit_type": "replaced" | "inserted" | "deleted", # Type of edit performed
"cell_id": str | None, # Cell ID that was affected
"total_cells": int # Total cells in notebook after edit
}ツール名: WebFetch
入力:
{
"url": str, # The URL to fetch content from
"prompt": str # The prompt to run on the fetched content
}出力:
{
"response": str, # AI model's response to the prompt
"url": str, # URL that was fetched
"final_url": str | None, # Final URL after redirects
"status_code": int | None # HTTP status code
}ツール名: WebSearch
入力:
{
"query": str, # The search query to use
"allowed_domains": list[str] | None, # Only include results from these domains
"blocked_domains": list[str] | None # Never include results from these domains
}出力:
{
"results": [
{
"title": str,
"url": str,
"snippet": str,
"metadata": dict | None
}
],
"total_results": int,
"query": str
}ツール名: TodoWrite
入力:
{
"todos": [
{
"content": str, # The task description
"status": "pending" | "in_progress" | "completed", # Task status
"activeForm": str # Active form of the description
}
]
}出力:
{
"message": str, # Success message
"stats": {
"total": int,
"pending": int,
"in_progress": int,
"completed": int
}
}ツール名: BashOutput
入力:
{
"bash_id": str, # The ID of the background shell
"filter": str | None # Optional regex to filter output lines
}出力:
{
"output": str, # New output since last check
"status": "running" | "completed" | "failed", # Current shell status
"exitCode": int | None # Exit code when completed
}ツール名: KillBash
入力:
{
"shell_id": str # The ID of the background shell to kill
}出力:
{
"message": str, # Success message
"shell_id": str # ID of the killed shell
}ツール名: ExitPlanMode
入力:
{
"plan": str # The plan to run by the user for approval
}出力:
{
"message": str, # Confirmation message
"approved": bool | None # Whether user approved the plan
}ツール名: ListMcpResources
入力:
{
"server": str | None # Optional server name to filter resources by
}出力:
{
"resources": [
{
"uri": str,
"name": str,
"description": str | None,
"mimeType": str | None,
"server": str
}
],
"total": int
}ツール名: ReadMcpResource
入力:
{
"server": str, # The MCP server name
"uri": str # The resource URI to read
}出力:
{
"contents": [
{
"uri": str,
"mimeType": str | None,
"text": str | None,
"blob": str | None
}
],
"server": str
}from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, AssistantMessage, TextBlock
import asyncio
class ConversationSession:
"""Maintains a single conversation session with Claude."""
def __init__(self, options: ClaudeAgentOptions = None):
self.client = ClaudeSDKClient(options)
self.turn_count = 0
async def start(self):
await self.client.connect()
print("Starting conversation session. Claude will remember context.")
print("Commands: 'exit' to quit, 'interrupt' to stop current task, 'new' for new session")
while True:
user_input = input(f"\n[Turn {self.turn_count + 1}] You: ")
if user_input.lower() == 'exit':
break
elif user_input.lower() == 'interrupt':
await self.client.interrupt()
print("Task interrupted!")
continue
elif user_input.lower() == 'new':
# Disconnect and reconnect for a fresh session
await self.client.disconnect()
await self.client.connect()
self.turn_count = 0
print("Started new conversation session (previous context cleared)")
continue
# Send message - Claude remembers all previous messages in this session
await self.client.query(user_input)
self.turn_count += 1
# Process response
print(f"[Turn {self.turn_count}] Claude: ", end="")
async for message in self.client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(block.text, end="")
print() # New line after response
await self.client.disconnect()
print(f"Conversation ended after {self.turn_count} turns.")
async def main():
options = ClaudeAgentOptions(
allowed_tools=["Read", "Write", "Bash"],
permission_mode="acceptEdits"
)
session = ConversationSession(options)
await session.start()
# Example conversation:
# Turn 1 - You: "Create a file called hello.py"
# Turn 1 - Claude: "I'll create a hello.py file for you..."
# Turn 2 - You: "What's in that file?"
# Turn 2 - Claude: "The hello.py file I just created contains..." (remembers!)
# Turn 3 - You: "Add a main function to it"
# Turn 3 - Claude: "I'll add a main function to hello.py..." (knows which file!)
asyncio.run(main())from claude_agent_sdk import (
ClaudeSDKClient,
ClaudeAgentOptions,
HookMatcher,
HookContext
)
import asyncio
from typing import Any
async def pre_tool_logger(
input_data: dict[str, Any],
tool_use_id: str | None,
context: HookContext
) -> dict[str, Any]:
"""Log all tool usage before execution."""
tool_name = input_data.get('tool_name', 'unknown')
print(f"[PRE-TOOL] About to use: {tool_name}")
# You can modify or block the tool execution here
if tool_name == "Bash" and "rm -rf" in str(input_data.get('tool_input', {})):
return {
'hookSpecificOutput': {
'hookEventName': 'PreToolUse',
'permissionDecision': 'deny',
'permissionDecisionReason': 'Dangerous command blocked'
}
}
return {}
async def post_tool_logger(
input_data: dict[str, Any],
tool_use_id: str | None,
context: HookContext
) -> dict[str, Any]:
"""Log results after tool execution."""
tool_name = input_data.get('tool_name', 'unknown')
print(f"[POST-TOOL] Completed: {tool_name}")
return {}
async def user_prompt_modifier(
input_data: dict[str, Any],
tool_use_id: str | None,
context: HookContext
) -> dict[str, Any]:
"""Add context to user prompts."""
original_prompt = input_data.get('prompt', '')
# Add timestamp to all prompts
from datetime import datetime
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return {
'hookSpecificOutput': {
'hookEventName': 'UserPromptSubmit',
'updatedPrompt': f"[{timestamp}] {original_prompt}"
}
}
async def main():
options = ClaudeAgentOptions(
hooks={
'PreToolUse': [
HookMatcher(hooks=[pre_tool_logger]),
HookMatcher(matcher='Bash', hooks=[pre_tool_logger])
],
'PostToolUse': [
HookMatcher(hooks=[post_tool_logger])
],
'UserPromptSubmit': [
HookMatcher(hooks=[user_prompt_modifier])
]
},
allowed_tools=["Read", "Write", "Bash"]
)
async with ClaudeSDKClient(options=options) as client:
await client.query("List files in current directory")
async for message in client.receive_response():
# Hooks will automatically log tool usage
pass
asyncio.run(main())from claude_agent_sdk import (
ClaudeSDKClient,
ClaudeAgentOptions,
AssistantMessage,
ToolUseBlock,
ToolResultBlock,
TextBlock
)
import asyncio
async def monitor_progress():
options = ClaudeAgentOptions(
allowed_tools=["Write", "Bash"],
permission_mode="acceptEdits"
)
async with ClaudeSDKClient(options=options) as client:
await client.query(
"Create 5 Python files with different sorting algorithms"
)
# Monitor progress in real-time
files_created = []
async for message in client.receive_messages():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, ToolUseBlock):
if block.name == "Write":
file_path = block.input.get("file_path", "")
print(f"🔨 Creating: {file_path}")
elif isinstance(block, ToolResultBlock):
print(f"✅ Completed tool execution")
elif isinstance(block, TextBlock):
print(f"💭 Claude says: {block.text[:100]}...")
# Check if we've received the final result
if hasattr(message, 'subtype') and message.subtype in ['success', 'error']:
print(f"\n🎯 Task completed!")
break
asyncio.run(monitor_progress())from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ToolUseBlock
import asyncio
async def create_project():
options = ClaudeAgentOptions(
allowed_tools=["Read", "Write", "Bash"],
permission_mode='acceptEdits',
cwd="/home/user/project"
)
async for message in query(
prompt="Create a Python project structure with setup.py",
options=options
):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, ToolUseBlock):
print(f"Using tool: {block.name}")
asyncio.run(create_project())from claude_agent_sdk import (
query,
CLINotFoundError,
ProcessError,
CLIJSONDecodeError
)
try:
async for message in query(prompt="Hello"):
print(message)
except CLINotFoundError:
print("Please install Claude Code: npm install -g @anthropic-ai/claude-code")
except ProcessError as e:
print(f"Process failed with exit code: {e.exit_code}")
except CLIJSONDecodeError as e:
print(f"Failed to parse response: {e}")from claude_agent_sdk import ClaudeSDKClient
import asyncio
async def interactive_session():
async with ClaudeSDKClient() as client:
# Send initial message
await client.query("What's the weather like?")
# Process responses
async for msg in client.receive_response():
print(msg)
# Send follow-up
await client.query("Tell me more about that")
# Process follow-up response
async for msg in client.receive_response():
print(msg)
asyncio.run(interactive_session())from claude_agent_sdk import (
ClaudeSDKClient,
ClaudeAgentOptions,
tool,
create_sdk_mcp_server,
AssistantMessage,
TextBlock
)
import asyncio
from typing import Any
# Define custom tools with @tool decorator
@tool("calculate", "Perform mathematical calculations", {"expression": str})
async def calculate(args: dict[str, Any]) -> dict[str, Any]:
try:
result = eval(args["expression"], {"__builtins__": {}})
return {
"content": [{
"type": "text",
"text": f"Result: {result}"
}]
}
except Exception as e:
return {
"content": [{
"type": "text",
"text": f"Error: {str(e)}"
}],
"is_error": True
}
@tool("get_time", "Get current time", {})
async def get_time(args: dict[str, Any]) -> dict[str, Any]:
from datetime import datetime
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return {
"content": [{
"type": "text",
"text": f"Current time: {current_time}"
}]
}
async def main():
# Create SDK MCP server with custom tools
my_server = create_sdk_mcp_server(
name="utilities",
version="1.0.0",
tools=[calculate, get_time]
)
# Configure options with the server
options = ClaudeAgentOptions(
mcp_servers={"utils": my_server},
allowed_tools=[
"mcp__utils__calculate",
"mcp__utils__get_time"
]
)
# Use ClaudeSDKClient for interactive tool usage
async with ClaudeSDKClient(options=options) as client:
await client.query("What's 123 * 456?")
# Process calculation response
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Calculation: {block.text}")
# Follow up with time query
await client.query("What time is it now?")
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Time: {block.text}")
asyncio.run(main())SandboxSettingsサンドボックスの動作に関する設定です。コマンドのサンドボックス化を有効にし、ネットワーク制限をプログラムで設定するために使用します。
class SandboxSettings(TypedDict, total=False):
enabled: bool
autoAllowBashIfSandboxed: bool
excludedCommands: list[str]
allowUnsandboxedCommands: bool
network: SandboxNetworkConfig
ignoreViolations: SandboxIgnoreViolations
enableWeakerNestedSandbox: bool| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
enabled | bool | False | コマンド実行のサンドボックスモードを有効にする |
autoAllowBashIfSandboxed | bool | False | サンドボックスが有効な場合にbashコマンドを自動承認する |
excludedCommands | list[str] | [] | サンドボックス制限を常にバイパスするコマンド(例:["docker"])。これらはモデルの関与なしに自動的にサンドボックス外で実行されます |
allowUnsandboxedCommands | bool | False | モデルがサンドボックス外でのコマンド実行をリクエストすることを許可する。Trueの場合、モデルはツール入力でdangerouslyDisableSandboxを設定でき、パーミッションシステムにフォールバックします |
network | SandboxNetworkConfig | None | ネットワーク固有のサンドボックス設定 |
ignoreViolations | SandboxIgnoreViolations | None | 無視するサンドボックス違反の設定 |
enableWeakerNestedSandbox | bool | False | 互換性のためにより弱いネストされたサンドボックスを有効にする |
ファイルシステムとネットワークのアクセス制限はサンドボックス設定では設定しません。代わりに、パーミッションルールから導出されます:
コマンド実行のサンドボックス化にはサンドボックス設定を使用し、ファイルシステムとネットワークのアクセス制御にはパーミッションルールを使用してください。
from claude_agent_sdk import query, ClaudeAgentOptions, SandboxSettings
sandbox_settings: SandboxSettings = {
"enabled": True,
"autoAllowBashIfSandboxed": True,
"network": {
"allowLocalBinding": True
}
}
async for message in query(
prompt="Build and test my project",
options=ClaudeAgentOptions(sandbox=sandbox_settings)
):
print(message)Unixソケットのセキュリティ:allowUnixSocketsオプションは強力なシステムサービスへのアクセスを許可する可能性があります。例えば、/var/run/docker.sockを許可すると、Docker APIを通じてホストシステムへの完全なアクセスが事実上許可され、サンドボックスの分離がバイパスされます。厳密に必要なUnixソケットのみを許可し、各ソケットのセキュリティ上の影響を理解してください。
SandboxNetworkConfigサンドボックスモードのネットワーク固有の設定です。
class SandboxNetworkConfig(TypedDict, total=False):
allowLocalBinding: bool
allowUnixSockets: list[str]
allowAllUnixSockets: bool
httpProxyPort: int
socksProxyPort: int| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
allowLocalBinding | bool | False | プロセスがローカルポートにバインドすることを許可する(例:開発サーバー用) |
allowUnixSockets | list[str] | [] | プロセスがアクセスできるUnixソケットパス(例:Dockerソケット) |
allowAllUnixSockets | bool | False | すべてのUnixソケットへのアクセスを許可する |
httpProxyPort | int | None | ネットワークリクエスト用のHTTPプロキシポート |
socksProxyPort | int | None | ネットワークリクエスト用のSOCKSプロキシポート |
SandboxIgnoreViolations特定のサンドボックス違反を無視するための設定です。
class SandboxIgnoreViolations(TypedDict, total=False):
file: list[str]
network: list[str]| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
file | list[str] | [] | 違反を無視するファイルパスパターン |
network | list[str] | [] | 違反を無視するネットワークパターン |
allowUnsandboxedCommandsが有効な場合、モデルはツール入力でdangerouslyDisableSandbox: Trueを設定することで、サンドボックス外でのコマンド実行をリクエストできます。これらのリクエストは既存のパーミッションシステムにフォールバックし、can_use_toolハンドラーが呼び出されるため、カスタム認可ロジックを実装できます。
excludedCommands vs allowUnsandboxedCommands:
excludedCommands:常にサンドボックスを自動的にバイパスするコマンドの静的リスト(例:["docker"])。モデルはこれを制御できません。allowUnsandboxedCommands:モデルがツール入力でdangerouslyDisableSandbox: Trueを設定することで、実行時にサンドボックス外での実行をリクエストするかどうかを決定できるようにします。from claude_agent_sdk import query, ClaudeAgentOptions
async def can_use_tool(tool: str, input: dict) -> bool:
# Check if the model is requesting to bypass the sandbox
if tool == "Bash" and input.get("dangerouslyDisableSandbox"):
# The model wants to run this command outside the sandbox
print(f"Unsandboxed command requested: {input.get('command')}")
# Return True to allow, False to deny
return is_command_authorized(input.get("command"))
return True
async def main():
async for message in query(
prompt="Deploy my application",
options=ClaudeAgentOptions(
sandbox={
"enabled": True,
"allowUnsandboxedCommands": True # Model can request unsandboxed execution
},
permission_mode="default",
can_use_tool=can_use_tool
)
):
print(message)このパターンにより、以下のことが可能になります:
dangerouslyDisableSandbox: Trueで実行されるコマンドは、完全なシステムアクセス権を持ちます。can_use_toolハンドラーでこれらのリクエストを慎重に検証してください。
permission_modeがbypassPermissionsに設定され、allow_unsandboxed_commandsが有効な場合、モデルは承認プロンプトなしにサンドボックス外でコマンドを自律的に実行できます。この組み合わせにより、モデルはサンドボックスの分離を暗黙的に回避できるようになります。
Was this page helpful?