Was this page helpful?
pip install claude-agent-sdkquery() et ClaudeSDKClientLe SDK Python fournit deux façons d'interagir avec Claude Code :
| Fonctionnalité | query() | ClaudeSDKClient |
|---|---|---|
| Session | Crée une nouvelle session à chaque fois | Réutilise la même session |
| Conversation | Échange unique | Plusieurs échanges dans le même contexte |
| Connexion | Gérée automatiquement | Contrôle manuel |
| Entrée en streaming | ✅ Supportée | ✅ Supportée |
| Interruptions | ❌ Non supportée | ✅ Supportée |
| Hooks | ❌ Non supporté | ✅ Supporté |
| Outils personnalisés | ❌ Non supporté | ✅ Supporté |
| Continuer la conversation | ❌ Nouvelle session à chaque fois | ✅ Maintient la conversation |
| Cas d'usage | Tâches ponctuelles | Conversations continues |
query() (Nouvelle session à chaque fois)Idéal pour :
ClaudeSDKClient (Conversation continue)Idéal pour :
query()Crée une nouvelle session pour chaque interaction avec Claude Code. Retourne un itérateur asynchrone qui produit des messages au fur et à mesure qu'ils arrivent. Chaque appel à query() recommence à zéro sans mémoire des interactions précédentes.
async def query(
*,
prompt: str | AsyncIterable[dict[str, Any]],
options: ClaudeAgentOptions | None = None
) -> AsyncIterator[Message]| Paramètre | Type | Description |
|---|---|---|
prompt | str | AsyncIterable[dict] | Le prompt d'entrée sous forme de chaîne ou d'itérable asynchrone pour le mode streaming |
options | ClaudeAgentOptions | None | Objet de configuration optionnel (par défaut ClaudeAgentOptions() si None) |
Retourne un AsyncIterator[Message] qui produit des messages de la conversation.
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()Décorateur pour définir les outils MCP avec la sécurité des types.
def tool(
name: str,
description: str,
input_schema: type | dict[str, Any]
) -> Callable[[Callable[[Any], Awaitable[dict[str, Any]]]], SdkMcpTool[Any]]| Paramètre | Type | Description |
|---|---|---|
name | str | Identifiant unique pour l'outil |
description | str | Description lisible par l'homme de ce que fait l'outil |
input_schema | type | dict[str, Any] | Schéma définissant les paramètres d'entrée de l'outil (voir ci-dessous) |
Mappage de type simple (recommandé) :
{"text": str, "count": int, "enabled": bool}Format JSON Schema (pour la validation complexe) :
{
"type": "object",
"properties": {
"text": {"type": "string"},
"count": {"type": "integer", "minimum": 0}
},
"required": ["text"]
}Une fonction décorateur qui enveloppe l'implémentation de l'outil et retourne une instance 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()Créer un serveur MCP en processus qui s'exécute dans votre application Python.
def create_sdk_mcp_server(
name: str,
version: str = "1.0.0",
tools: list[SdkMcpTool[Any]] | None = None
) -> McpSdkServerConfig| Paramètre | Type | Par défaut | Description |
|---|---|---|---|
name | str | - | Identifiant unique pour le serveur |
version | str | "1.0.0" | Chaîne de version du serveur |
tools | list[SdkMcpTool[Any]] | None | None | Liste des fonctions d'outil créées avec le décorateur @tool |
Retourne un objet McpSdkServerConfig qui peut être passé à ClaudeAgentOptions.mcp_servers.
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"]
)ClaudeSDKClientMaintient une session de conversation sur plusieurs échanges. C'est l'équivalent Python de la façon dont la fonction query() du SDK TypeScript fonctionne en interne - elle crée un objet client qui peut continuer les conversations.
query()@tool) et les hooksclass 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| Méthode | Description |
|---|---|
__init__(options) | Initialiser le client avec une configuration optionnelle |
connect(prompt) | Se connecter à Claude avec un prompt initial optionnel ou un flux de messages |
query(prompt, session_id) | Envoyer une nouvelle requête en mode streaming |
receive_messages() | Recevoir tous les messages de Claude sous forme d'itérateur asynchrone |
receive_response() | Recevoir les messages jusqu'à et incluant un ResultMessage |
interrupt() | Envoyer un signal d'interruption (fonctionne uniquement en mode streaming) |
rewind_files(user_message_uuid) | Restaurer les fichiers à leur état au message utilisateur spécifié. Nécessite . Voir |
Le client peut être utilisé comme gestionnaire de contexte asynchrone pour la gestion automatique de la connexion :
async with ClaudeSDKClient() as client:
await client.query("Hello Claude")
async for message in client.receive_response():
print(message)Important : Lors de l'itération sur les messages, évitez d'utiliser
breakpour quitter tôt car cela peut causer des problèmes de nettoyage asyncio. À la place, laissez l'itération se terminer naturellement ou utilisez des drapeaux pour suivre quand vous avez trouvé ce que vous cherchiez.
import asyncio
from claude_agent_sdk import ClaudeSDKClient, AssistantMessage, TextBlock, ResultMessage
async def main():
async with ClaudeSDKClient() as client:
# First question
await client.query("What's the capital of France?")
# Process response
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}")
# Follow-up question - Claude remembers the previous context
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}")
# Another follow-up - still in the same conversation
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():
"""Generate messages dynamically."""
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:
# Stream input to Claude
await client.query(message_stream())
# Process response
async for message in client.receive_response():
print(message)
# Follow-up in same session
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:
# Start a long-running task
await client.query("Count from 1 to 100 slowly")
# Let it run for a bit
await asyncio.sleep(2)
# Interrupt the task
await client.interrupt()
print("Task interrupted!")
# Send a new command
await client.query("Just say hello instead")
async for message in client.receive_response():
# Process the new 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:
"""Custom logic for tool permissions."""
# Block writes to system directories
if tool_name == "Write" and input_data.get("file_path", "").startswith("/system/"):
return PermissionResultDeny(
message="System directory write not allowed",
interrupt=True
)
# Redirect sensitive file operations
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}
)
# Allow everything else
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():
# Will use sandbox path instead
print(message)
asyncio.run(main())SdkMcpToolDéfinition pour un outil MCP SDK créé avec le décorateur @tool.
@dataclass
class SdkMcpTool(Generic[T]):
name: str
description: str
input_schema: type[T] | dict[str, Any]
handler: Callable[[T], Awaitable[dict[str, Any]]]| Propriété | Type | Description |
|---|---|---|
name | str | Identifiant unique pour l'outil |
description | str | Description lisible par l'homme |
input_schema | type[T] | dict[str, Any] | Schéma pour la validation des entrées |
handler | Callable[[T], Awaitable[dict[str, Any]]] | Fonction asynchrone qui gère l'exécution de l'outil |
ClaudeAgentOptionsClasse de données de configuration pour les requêtes Claude 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| Propriété | Type | Par défaut | Description |
|---|---|---|---|
tools | list[str] | ToolsPreset | None | None | Configuration des outils. Utilisez {"type": "preset", "preset": "claude_code"} pour les outils par défaut de Claude Code |
allowed_tools | list[str] | [] | Liste des noms d'outils autorisés |
system_prompt | str | SystemPromptPreset | None | None | Configuration du prompt système. Passez une chaîne pour un prompt personnalisé, ou utilisez pour le prompt système de Claude Code. Ajoutez pour étendre le preset |
OutputFormatConfiguration pour la validation de sortie structurée.
class OutputFormat(TypedDict):
type: Literal["json_schema"]
schema: dict[str, Any]| Champ | Requis | Description |
|---|---|---|
type | Oui | Doit être "json_schema" pour la validation JSON Schema |
schema | Oui | Définition JSON Schema pour la validation de sortie |
SystemPromptPresetConfiguration pour utiliser le prompt système prédéfini de Claude Code avec des ajouts optionnels.
class SystemPromptPreset(TypedDict):
type: Literal["preset"]
preset: Literal["claude_code"]
append: NotRequired[str]| Champ | Requis | Description |
|---|---|---|
type | Oui | Doit être "preset" pour utiliser un prompt système prédéfini |
preset | Oui | Doit être "claude_code" pour utiliser le prompt système de Claude Code |
append | Non | Instructions supplémentaires à ajouter au prompt système prédéfini |
SettingSourceContrôle quelles sources de configuration basées sur le système de fichiers le SDK charge les paramètres à partir de.
SettingSource = Literal["user", "project", "local"]| Valeur | Description | Emplacement |
|---|---|---|
"user" | Paramètres utilisateur globaux | ~/.claude/settings.json |
"project" | Paramètres de projet partagés (contrôle de version) | .claude/settings.json |
"local" | Paramètres de projet locaux (gitignorés) | .claude/settings.local.json |
Quand setting_sources est omis ou None, le SDK ne charge pas les paramètres du système de fichiers. Cela fournit l'isolation pour les applications SDK.
Charger tous les paramètres du système de fichiers (comportement hérité) :
# Load all settings like SDK v0.0.x did
from claude_agent_sdk import query, ClaudeAgentOptions
async for message in query(
prompt="Analyze this code",
options=ClaudeAgentOptions(
setting_sources=["user", "project", "local"] # Load all settings
)
):
print(message)Charger uniquement des sources de paramètres spécifiques :
# Load only project settings, ignore user and local
async for message in query(
prompt="Run CI checks",
options=ClaudeAgentOptions(
setting_sources=["project"] # Only .claude/settings.json
)
):
print(message)Environnements de test et CI :
# Ensure consistent behavior in CI by excluding local settings
async for message in query(
prompt="Run tests",
options=ClaudeAgentOptions(
setting_sources=["project"], # Only team-shared settings
permission_mode="bypassPermissions"
)
):
print(message)Applications SDK uniquement :
# Define everything programmatically (default behavior)
# No filesystem dependencies - setting_sources defaults to None
async for message in query(
prompt="Review this PR",
options=ClaudeAgentOptions(
# setting_sources=None is the default, no need to specify
agents={ /* ... */ },
mcp_servers={ /* ... */ },
allowed_tools=["Read", "Grep", "Glob"]
)
):
print(message)Chargement des instructions de projet CLAUDE.md :
# Load project settings to include CLAUDE.md files
async for message in query(
prompt="Add a new feature following project conventions",
options=ClaudeAgentOptions(
system_prompt={
"type": "preset",
"preset": "claude_code" # Use Claude Code's system prompt
},
setting_sources=["project"], # Required to load CLAUDE.md from project
allowed_tools=["Read", "Write", "Edit"]
)
):
print(message)Quand plusieurs sources sont chargées, les paramètres sont fusionnés avec cette précédence (la plus haute à la plus basse) :
.claude/settings.local.json).claude/settings.json)~/.claude/settings.json)Les options programmatiques (comme agents, allowed_tools) remplacent toujours les paramètres du système de fichiers.
AgentDefinitionConfiguration pour un sous-agent défini par programmation.
@dataclass
class AgentDefinition:
description: str
prompt: str
tools: list[str] | None = None
model: Literal["sonnet", "opus", "haiku", "inherit"] | None = None| Champ | Requis | Description |
|---|---|---|
description | Oui | Description en langage naturel de quand utiliser cet agent |
tools | Non | Tableau des noms d'outils autorisés. Si omis, hérite de tous les outils |
prompt | Oui | Le prompt système de l'agent |
model | Non | Remplacement de modèle pour cet agent. Si omis, utilise le modèle principal |
PermissionModeModes de permission pour contrôler l'exécution des outils.
PermissionMode = Literal[
"default", # Standard permission behavior
"acceptEdits", # Auto-accept file edits
"plan", # Planning mode - no execution
"bypassPermissions" # Bypass all permission checks (use with caution)
]CanUseToolAlias de type pour les fonctions de rappel de permission d'outil.
CanUseTool = Callable[
[str, dict[str, Any], ToolPermissionContext],
Awaitable[PermissionResult]
]Le rappel reçoit :
tool_name : Nom de l'outil appeléinput_data : Les paramètres d'entrée de l'outilcontext : Un ToolPermissionContext avec des informations supplémentairesRetourne un PermissionResult (soit PermissionResultAllow soit PermissionResultDeny).
ToolPermissionContextInformations de contexte transmises aux rappels de permission d'outil.
@dataclass
class ToolPermissionContext:
signal: Any | None = None # Future: abort signal support
suggestions: list[PermissionUpdate] = field(default_factory=list)| Champ | Type | Description |
|---|---|---|
signal | Any | None | Réservé pour le support futur du signal d'abandon |
suggestions | list[PermissionUpdate] | Suggestions de mise à jour de permission depuis la CLI |
PermissionResultType union pour les résultats de rappel de permission.
PermissionResult = PermissionResultAllow | PermissionResultDenyPermissionResultAllowRésultat indiquant que l'appel d'outil doit être autorisé.
@dataclass
class PermissionResultAllow:
behavior: Literal["allow"] = "allow"
updated_input: dict[str, Any] | None = None
updated_permissions: list[PermissionUpdate] | None = None| Champ | Type | Par défaut | Description |
|---|---|---|---|
behavior | Literal["allow"] | "allow" | Doit être "allow" |
updated_input | dict[str, Any] | None | None | Entrée modifiée à utiliser à la place de l'original |
updated_permissions | list[PermissionUpdate] | None | None | Mises à jour de permission à appliquer |
PermissionResultDenyRésultat indiquant que l'appel d'outil doit être refusé.
@dataclass
class PermissionResultDeny:
behavior: Literal["deny"] = "deny"
message: str = ""
interrupt: bool = False| Champ | Type | Par défaut | Description |
|---|---|---|---|
behavior | Literal["deny"] | "deny" | Doit être "deny" |
message | str | "" | Message expliquant pourquoi l'outil a été refusé |
interrupt | bool | False | S'il faut interrompre l'exécution actuelle |
PermissionUpdateConfiguration pour mettre à jour les permissions par programmation.
@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| Champ | Type | Description |
|---|---|---|
type | Literal[...] | Le type d'opération de mise à jour de permission |
rules | list[PermissionRuleValue] | None | Règles pour les opérations d'ajout/remplacement/suppression |
behavior | Literal["allow", "deny", "ask"] | None | Comportement pour les opérations basées sur les règles |
mode | PermissionMode | None | Mode pour l'opération setMode |
directories |
SdkBetaType littéral pour les fonctionnalités bêta du SDK.
SdkBeta = Literal["context-1m-2025-08-07"]À utiliser avec le champ betas dans ClaudeAgentOptions pour activer les fonctionnalités bêta.
McpSdkServerConfigConfiguration pour les serveurs MCP du SDK créés avec create_sdk_mcp_server().
class McpSdkServerConfig(TypedDict):
type: Literal["sdk"]
name: str
instance: Any # MCP Server instanceMcpServerConfigType union pour les configurations de serveur MCP.
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]]SdkPluginConfigConfiguration pour charger les plugins dans le SDK.
class SdkPluginConfig(TypedDict):
type: Literal["local"]
path: str| Champ | Type | Description |
|---|---|---|
type | Literal["local"] | Doit être "local" (seuls les plugins locaux sont actuellement supportés) |
path | str | Chemin absolu ou relatif vers le répertoire du plugin |
Exemple :
plugins=[
{"type": "local", "path": "./my-plugin"},
{"type": "local", "path": "/absolute/path/to/plugin"}
]Pour des informations complètes sur la création et l'utilisation de plugins, voir Plugins.
MessageType union de tous les messages possibles.
Message = UserMessage | AssistantMessage | SystemMessage | ResultMessage | StreamEventUserMessageMessage d'entrée utilisateur.
@dataclass
class UserMessage:
content: str | list[ContentBlock]AssistantMessageMessage de réponse d'assistant avec blocs de contenu.
@dataclass
class AssistantMessage:
content: list[ContentBlock]
model: strSystemMessageMessage système avec métadonnées.
@dataclass
class SystemMessage:
subtype: str
data: dict[str, Any]ResultMessageMessage de résultat final avec informations de coût et d'utilisation.
@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Événement de flux pour les mises à jour de message partielles lors du streaming. Reçu uniquement lorsque include_partial_messages=True dans ClaudeAgentOptions.
@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| Champ | Type | Description |
|---|---|---|
uuid | str | Identifiant unique pour cet événement |
session_id | str | Identifiant de session |
event | dict[str, Any] | Les données d'événement de flux brutes de l'API Anthropic |
parent_tool_use_id | str | None | ID d'utilisation d'outil parent si cet événement provient d'un sous-agent |
ContentBlockType union de tous les blocs de contenu.
ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlockTextBlockBloc de contenu texte.
@dataclass
class TextBlock:
text: strThinkingBlockBloc de contenu de réflexion (pour les modèles avec capacité de réflexion).
@dataclass
class ThinkingBlock:
thinking: str
signature: strToolUseBlockBloc de demande d'utilisation d'outil.
@dataclass
class ToolUseBlock:
id: str
name: str
input: dict[str, Any]ToolResultBlockBloc de résultat d'exécution d'outil.
@dataclass
class ToolResultBlock:
tool_use_id: str
content: str | list[dict[str, Any]] | None = None
is_error: bool | None = NoneClaudeSDKErrorClasse d'exception de base pour toutes les erreurs du SDK.
class ClaudeSDKError(Exception):
"""Base error for Claude SDK."""CLINotFoundErrorLevée lorsque Claude Code CLI n'est pas installé ou introuvable.
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
"""CLIConnectionErrorLevée lorsque la connexion à Claude Code échoue.
class CLIConnectionError(ClaudeSDKError):
"""Failed to connect to Claude Code."""ProcessErrorLevée lorsque le processus Claude Code échoue.
class ProcessError(ClaudeSDKError):
def __init__(self, message: str, exit_code: int | None = None, stderr: str | None = None):
self.exit_code = exit_code
self.stderr = stderrCLIJSONDecodeErrorLevée lorsque l'analyse JSON échoue.
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_errorPour un guide complet sur l'utilisation des hooks avec des exemples et des modèles courants, voir le guide des hooks.
HookEventTypes d'événements de hook supportés. Notez que en raison des limitations de configuration, le SDK Python ne supporte pas les hooks SessionStart, SessionEnd et 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
]HookCallbackDéfinition de type pour les fonctions de rappel de hook.
HookCallback = Callable[
[dict[str, Any], str | None, HookContext],
Awaitable[dict[str, Any]]
]Paramètres :
input_data : Données d'entrée spécifiques au hook (voir guide des hooks)tool_use_id : Identifiant d'utilisation d'outil optionnel (pour les hooks liés aux outils)context : Contexte du hook avec des informations supplémentairesRetourne un dictionnaire qui peut contenir :
decision : "block" pour bloquer l'actionsystemMessage : Message système à ajouter à la transcriptionhookSpecificOutput : Données de sortie spécifiques au hookHookContextInformations de contexte transmises aux rappels de hook.
@dataclass
class HookContext:
signal: Any | None = None # Future: abort signal supportHookMatcherConfiguration pour faire correspondre les hooks à des événements ou outils spécifiques.
@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)HookInputType union de tous les types d'entrée de hook. Le type réel dépend du champ hook_event_name.
HookInput = (
PreToolUseHookInput
| PostToolUseHookInput
| UserPromptSubmitHookInput
| StopHookInput
| SubagentStopHookInput
| PreCompactHookInput
)BaseHookInputChamps de base présents dans tous les types d'entrée de hook.
class BaseHookInput(TypedDict):
session_id: str
transcript_path: str
cwd: str
permission_mode: NotRequired[str]| Champ | Type | Description |
|---|---|---|
session_id | str | Identifiant de session actuel |
transcript_path | str | Chemin vers le fichier de transcription de session |
cwd | str | Répertoire de travail actuel |
permission_mode | str (optionnel) | Mode de permission actuel |
PreToolUseHookInputDonnées d'entrée pour les événements de hook PreToolUse.
class PreToolUseHookInput(BaseHookInput):
hook_event_name: Literal["PreToolUse"]
tool_name: str
tool_input: dict[str, Any]| Champ | Type | Description |
|---|---|---|
hook_event_name | Literal["PreToolUse"] | Toujours "PreToolUse" |
tool_name | str | Nom de l'outil sur le point d'être exécuté |
tool_input | dict[str, Any] | Paramètres d'entrée pour l'outil |
PostToolUseHookInputDonnées d'entrée pour les événements de hook PostToolUse.
class PostToolUseHookInput(BaseHookInput):
hook_event_name: Literal["PostToolUse"]
tool_name: str
tool_input: dict[str, Any]
tool_response: Any| Champ | Type | Description |
|---|---|---|
hook_event_name | Literal["PostToolUse"] | Toujours "PostToolUse" |
tool_name | str | Nom de l'outil qui a été exécuté |
tool_input | dict[str, Any] | Paramètres d'entrée qui ont été utilisés |
tool_response | Any | Réponse de l'exécution de l'outil |
UserPromptSubmitHookInputDonnées d'entrée pour les événements de hook UserPromptSubmit.
class UserPromptSubmitHookInput(BaseHookInput):
hook_event_name: Literal["UserPromptSubmit"]
prompt: str| Champ | Type | Description |
|---|---|---|
hook_event_name | Literal["UserPromptSubmit"] | Toujours "UserPromptSubmit" |
prompt | str | L'invite soumise par l'utilisateur |
StopHookInputDonnées d'entrée pour les événements de hook Stop.
class StopHookInput(BaseHookInput):
hook_event_name: Literal["Stop"]
stop_hook_active: bool| Champ | Type | Description |
|---|---|---|
hook_event_name | Literal["Stop"] | Toujours "Stop" |
stop_hook_active | bool | S'il le hook d'arrêt est actif |
SubagentStopHookInputDonnées d'entrée pour les événements de hook SubagentStop.
class SubagentStopHookInput(BaseHookInput):
hook_event_name: Literal["SubagentStop"]
stop_hook_active: bool| Champ | Type | Description |
|---|---|---|
hook_event_name | Literal["SubagentStop"] | Toujours "SubagentStop" |
stop_hook_active | bool | S'il le hook d'arrêt est actif |
PreCompactHookInputDonnées d'entrée pour les événements de hook PreCompact.
class PreCompactHookInput(BaseHookInput):
hook_event_name: Literal["PreCompact"]
trigger: Literal["manual", "auto"]
custom_instructions: str | None| Champ | Type | Description |
|---|---|---|
hook_event_name | Literal["PreCompact"] | Toujours "PreCompact" |
trigger | Literal["manual", "auto"] | Ce qui a déclenché la compaction |
custom_instructions | str | None | Instructions personnalisées pour la compaction |
HookJSONOutputType union pour les valeurs de retour de rappel de hook.
HookJSONOutput = AsyncHookJSONOutput | SyncHookJSONOutputSyncHookJSONOutputSortie de hook synchrone avec champs de contrôle et de décision.
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]]Utilisez continue_ (avec tiret bas) dans le code Python. Il est automatiquement converti en continue lors de l'envoi à la CLI.
AsyncHookJSONOutputSortie de hook asynchrone qui reporte l'exécution du hook.
class AsyncHookJSONOutput(TypedDict):
async_: Literal[True] # Set to True to defer execution
asyncTimeout: NotRequired[int] # Timeout in millisecondsUtilisez async_ (avec tiret bas) dans le code Python. Il est automatiquement converti en async lors de l'envoi à la CLI.
Cet exemple enregistre deux hooks : l'un qui bloque les commandes bash dangereuses comme rm -rf /, et un autre qui enregistre toute l'utilisation d'outils pour l'audit. Le hook de sécurité s'exécute uniquement sur les commandes Bash (via le matcher), tandis que le hook de journalisation s'exécute sur tous les outils.
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)Documentation des schémas d'entrée/sortie pour tous les outils Claude Code intégrés. Bien que le SDK Python n'exporte pas ces éléments en tant que types, ils représentent la structure des entrées et sorties d'outils dans les messages.
Nom de l'outil : Task
Entrée :
{
"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
}Sortie :
{
"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
}Nom de l'outil : AskUserQuestion
Pose des questions de clarification à l'utilisateur lors de l'exécution. Voir Gérer les approbations et l'entrée utilisateur pour les détails d'utilisation.
Entrée :
{
"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
}Sortie :
{
"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
}Nom de l'outil : Bash
Entrée :
{
"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
}Sortie :
{
"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
}Nom de l'outil : Edit
Entrée :
{
"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)
}Sortie :
{
"message": str, # Confirmation message
"replacements": int, # Number of replacements made
"file_path": str # File path that was edited
}Nom de l'outil : Read
Entrée :
{
"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
}Sortie (fichiers texte) :
{
"content": str, # File contents with line numbers
"total_lines": int, # Total number of lines in file
"lines_returned": int # Lines actually returned
}Sortie (images) :
{
"image": str, # Base64 encoded image data
"mime_type": str, # Image MIME type
"file_size": int # File size in bytes
}Nom de l'outil : Write
Entrée :
{
"file_path": str, # The absolute path to the file to write
"content": str # The content to write to the file
}Sortie :
{
"message": str, # Success message
"bytes_written": int, # Number of bytes written
"file_path": str # File path that was written
}Nom de l'outil : Glob
Entrée :
{
"pattern": str, # The glob pattern to match files against
"path": str | None # The directory to search in (defaults to cwd)
}Sortie :
{
"matches": list[str], # Array of matching file paths
"count": int, # Number of matches found
"search_path": str # Search directory used
}Nom de l'outil : Grep
Entrée :
{
"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
}Sortie (mode contenu) :
{
"matches": [
{
"file": str,
"line_number": int | None,
"line": str,
"before_context": list[str] | None,
"after_context": list[str] | None
}
],
"total_matches": int
}Sortie (mode fichiers_avec_correspondances) :
{
"files": list[str], # Files containing matches
"count": int # Number of files with matches
}Nom de l'outil : NotebookEdit
Entrée :
{
"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
}Sortie :
{
"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
}Nom de l'outil : WebFetch
Entrée :
{
"url": str, # The URL to fetch content from
"prompt": str # The prompt to run on the fetched content
}Sortie :
{
"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
}Nom de l'outil : WebSearch
Entrée :
{
"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
}Sortie :
{
"results": [
{
"title": str,
"url": str,
"snippet": str,
"metadata": dict | None
}
],
"total_results": int,
"query": str
}Nom de l'outil : TodoWrite
Entrée :
{
"todos": [
{
"content": str, # The task description
"status": "pending" | "in_progress" | "completed", # Task status
"activeForm": str # Active form of the description
}
]
}Sortie :
{
"message": str, # Success message
"stats": {
"total": int,
"pending": int,
"in_progress": int,
"completed": int
}
}Nom de l'outil : BashOutput
Entrée :
{
"bash_id": str, # The ID of the background shell
"filter": str | None # Optional regex to filter output lines
}Sortie :
{
"output": str, # New output since last check
"status": "running" | "completed" | "failed", # Current shell status
"exitCode": int | None # Exit code when completed
}Nom de l'outil : KillBash
Entrée :
{
"shell_id": str # The ID of the background shell to kill
}Sortie :
{
"message": str, # Success message
"shell_id": str # ID of the killed shell
}Nom de l'outil : ExitPlanMode
Entrée :
{
"plan": str # The plan to run by the user for approval
}Sortie :
{
"message": str, # Confirmation message
"approved": bool | None # Whether user approved the plan
}Nom de l'outil : ListMcpResources
Entrée :
{
"server": str | None # Optional server name to filter resources by
}Sortie :
{
"resources": [
{
"uri": str,
"name": str,
"description": str | None,
"mimeType": str | None,
"server": str
}
],
"total": int
}Nom de l'outil : ReadMcpResource
Entrée :
{
"server": str, # The MCP server name
"uri": str # The resource URI to read
}Sortie :
{
"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())SandboxSettingsConfiguration du comportement du bac à sable. Utilisez ceci pour activer le sandboxing des commandes et configurer les restrictions réseau par programmation.
class SandboxSettings(TypedDict, total=False):
enabled: bool
autoAllowBashIfSandboxed: bool
excludedCommands: list[str]
allowUnsandboxedCommands: bool
network: SandboxNetworkConfig
ignoreViolations: SandboxIgnoreViolations
enableWeakerNestedSandbox: bool| Propriété | Type | Par défaut | Description |
|---|---|---|---|
enabled | bool | False | Activer le mode bac à sable pour l'exécution des commandes |
autoAllowBashIfSandboxed | bool | False | Approuver automatiquement les commandes bash lorsque le bac à sable est activé |
excludedCommands | list[str] | [] | Commandes qui contournent toujours les restrictions du bac à sable (par exemple, ["docker"]). Celles-ci s'exécutent automatiquement sans bac à sable sans intervention du modèle |
Les restrictions d'accès au système de fichiers et au réseau ne sont PAS configurées via les paramètres du bac à sable. Au lieu de cela, elles sont dérivées des règles de permission :
Utilisez les paramètres du bac à sable pour le sandboxing de l'exécution des commandes, et les règles de permission pour le contrôle d'accès au système de fichiers et au réseau.
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)Sécurité des sockets Unix : L'option allowUnixSockets peut accorder l'accès à des services système puissants. Par exemple, autoriser /var/run/docker.sock accorde effectivement un accès complet au système hôte via l'API Docker, contournant l'isolation du bac à sable. N'autorisez que les sockets Unix strictement nécessaires et comprenez les implications de sécurité de chacun.
SandboxNetworkConfigConfiguration spécifique au réseau pour le mode bac à sable.
class SandboxNetworkConfig(TypedDict, total=False):
allowLocalBinding: bool
allowUnixSockets: list[str]
allowAllUnixSockets: bool
httpProxyPort: int
socksProxyPort: int| Propriété | Type | Par défaut | Description |
|---|---|---|---|
allowLocalBinding | bool | False | Permettre aux processus de se lier aux ports locaux (par exemple, pour les serveurs de développement) |
allowUnixSockets | list[str] | [] | Chemins de socket Unix auxquels les processus peuvent accéder (par exemple, socket Docker) |
allowAllUnixSockets | bool | False | Permettre l'accès à tous les sockets Unix |
SandboxIgnoreViolationsConfiguration pour ignorer les violations spécifiques du bac à sable.
class SandboxIgnoreViolations(TypedDict, total=False):
file: list[str]
network: list[str]| Propriété | Type | Par défaut | Description |
|---|---|---|---|
file | list[str] | [] | Modèles de chemin de fichier pour lesquels ignorer les violations |
network | list[str] | [] | Modèles réseau pour lesquels ignorer les violations |
Lorsque allowUnsandboxedCommands est activé, le modèle peut demander l'exécution de commandes en dehors du bac à sable en définissant dangerouslyDisableSandbox: True dans l'entrée de l'outil. Ces demandes reviennent au système de permissions existant, ce qui signifie que votre gestionnaire can_use_tool sera invoqué, vous permettant d'implémenter une logique d'autorisation personnalisée.
excludedCommands vs allowUnsandboxedCommands :
excludedCommands : Une liste statique de commandes qui contournent toujours automatiquement le bac à sable (par exemple, ["docker"]). Le modèle n'a aucun contrôle sur ceci.allowUnsandboxedCommands : Permet au modèle de décider à l'exécution s'il faut demander une exécution non sandboxée en définissant dangerouslyDisableSandbox: True dans l'entrée de l'outil.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)Ce modèle vous permet de :
Les commandes s'exécutant avec dangerouslyDisableSandbox: True ont un accès complet au système. Assurez-vous que votre gestionnaire can_use_tool valide ces demandes avec soin.
Si permission_mode est défini sur bypassPermissions et allow_unsandboxed_commands est activé, le modèle peut exécuter de manière autonome des commandes en dehors du bac à sable sans aucune invite d'approbation. Cette combinaison permet effectivement au modèle d'échapper à l'isolation du bac à sable silencieusement.
enable_file_checkpointing=Truedisconnect() | Se déconnecter de Claude |
{"type": "preset", "preset": "claude_code"}"append"mcp_servers | dict[str, McpServerConfig] | str | Path | {} | Configurations du serveur MCP ou chemin vers le fichier de configuration |
permission_mode | PermissionMode | None | None | Mode de permission pour l'utilisation des outils |
continue_conversation | bool | False | Continuer la conversation la plus récente |
resume | str | None | None | ID de session à reprendre |
max_turns | int | None | None | Nombre maximum de tours de conversation |
max_budget_usd | float | None | None | Budget maximum en USD pour la session |
disallowed_tools | list[str] | [] | Liste des noms d'outils non autorisés |
enable_file_checkpointing | bool | False | Activer le suivi des modifications de fichiers pour la rembobinage. Voir Sauvegarde de fichiers |
model | str | None | None | Modèle Claude à utiliser |
fallback_model | str | None | None | Modèle de secours à utiliser si le modèle principal échoue |
betas | list[SdkBeta] | [] | Fonctionnalités bêta à activer. Voir SdkBeta pour les options disponibles |
output_format | OutputFormat | None | None | Définir le format de sortie pour les résultats de l'agent. Voir Sorties structurées pour les détails |
permission_prompt_tool_name | str | None | None | Nom de l'outil MCP pour les prompts de permission |
cwd | str | Path | None | None | Répertoire de travail courant |
cli_path | str | Path | None | None | Chemin personnalisé vers l'exécutable CLI de Claude Code |
settings | str | None | None | Chemin vers le fichier de paramètres |
add_dirs | list[str | Path] | [] | Répertoires supplémentaires auxquels Claude peut accéder |
env | dict[str, str] | {} | Variables d'environnement |
extra_args | dict[str, str | None] | {} | Arguments CLI supplémentaires à passer directement au CLI |
max_buffer_size | int | None | None | Nombre maximum d'octets lors de la mise en mémoire tampon de la sortie standard du CLI |
debug_stderr | Any | sys.stderr | Obsolète - Objet de type fichier pour la sortie de débogage. Utilisez plutôt le rappel stderr |
stderr | Callable[[str], None] | None | None | Fonction de rappel pour la sortie stderr du CLI |
can_use_tool | CanUseTool | None | None | Fonction de rappel de permission d'outil. Voir Types de permission pour les détails |
hooks | dict[HookEvent, list[HookMatcher]] | None | None | Configurations de hook pour intercepter les événements |
user | str | None | None | Identifiant utilisateur |
include_partial_messages | bool | False | Inclure les événements de streaming de messages partiels. Quand activé, les messages StreamEvent sont produits |
fork_session | bool | False | Lors de la reprise avec resume, bifurquer vers un nouvel ID de session au lieu de continuer la session d'origine |
agents | dict[str, AgentDefinition] | None | None | Sous-agents définis par programmation |
plugins | list[SdkPluginConfig] | [] | Charger les plugins personnalisés à partir de chemins locaux. Voir Plugins pour les détails |
sandbox | SandboxSettings | None | None | Configurer le comportement du sandbox par programmation. Voir Paramètres du sandbox pour les détails |
setting_sources | list[SettingSource] | None | None (pas de paramètres) | Contrôler quels paramètres du système de fichiers charger. Quand omis, aucun paramètre n'est chargé. Remarque : Doit inclure "project" pour charger les fichiers CLAUDE.md |
max_thinking_tokens | int | None | None | Nombre maximum de tokens pour les blocs de réflexion |
list[str] | None |
| Répertoires pour les opérations d'ajout/suppression de répertoire |
destination | Literal[...] | None | Où appliquer la mise à jour de permission |
allowUnsandboxedCommands | bool | False | Permettre au modèle de demander l'exécution de commandes en dehors du bac à sable. Lorsque True, le modèle peut définir dangerouslyDisableSandbox dans l'entrée de l'outil, ce qui revient au système de permissions |
network | SandboxNetworkConfig | None | Configuration du bac à sable spécifique au réseau |
ignoreViolations | SandboxIgnoreViolations | None | Configurer les violations du bac à sable à ignorer |
enableWeakerNestedSandbox | bool | False | Activer un bac à sable imbriqué plus faible pour la compatibilité |
httpProxyPortint |
None |
| Port du proxy HTTP pour les requêtes réseau |
socksProxyPort | int | None | Port du proxy SOCKS pour les requêtes réseau |