or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

agent-definitions.mdagents.mdclient.mdconfiguration-options.mdcontent-blocks.mdcore-query-interface.mdcustom-tools.mderror-handling.mderrors.mdhook-system.mdhooks.mdindex.mdmcp-config.mdmcp-server-configuration.mdmessages-and-content.mdmessages.mdoptions.mdpermission-control.mdpermissions.mdquery.mdtransport.md
COMPLETION_SUMMARY.mdtile.json

tessl/pypi-claude-agent-sdk

Python SDK for Claude Code enabling AI agents with tool usage, hooks, permissions, and bidirectional conversations

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/claude-agent-sdk@0.1.x

To install, run

npx @tessl/cli install tessl/pypi-claude-agent-sdk@0.1.1

index.mddocs/

Claude Agent SDK

Python SDK for Claude Code enabling developers to build AI agents with tool usage, hooks, permission control, and bidirectional conversations. Provides both simple query-based interactions and advanced streaming client capabilities for complex use cases.

Package Information

  • Package Name: claude-agent-sdk
  • Package Type: pypi
  • Language: Python
  • Installation: pip install claude-agent-sdk
  • Python Version: 3.10+
  • Dependencies: anyio>=4.0.0, typing_extensions>=4.0.0 (Python <3.11), mcp>=0.1.0

Core Imports

from claude_agent_sdk import query, ClaudeSDKClient, ClaudeAgentOptions

All public exports are available from the main package namespace:

from claude_agent_sdk import (
    # Main functions
    query,
    __version__,

    # Client
    ClaudeSDKClient,
    Transport,

    # Configuration
    ClaudeAgentOptions,

    # Message types
    UserMessage,
    AssistantMessage,
    SystemMessage,
    ResultMessage,
    StreamEvent,
    Message,

    # Content blocks
    TextBlock,
    ThinkingBlock,
    ToolUseBlock,
    ToolResultBlock,
    ContentBlock,

    # MCP server support
    create_sdk_mcp_server,
    tool,
    SdkMcpTool,
    McpServerConfig,
    McpSdkServerConfig,

    # Hook system
    HookCallback,
    HookContext,
    HookInput,
    HookJSONOutput,
    HookMatcher,

    # Permission system
    PermissionMode,
    CanUseTool,
    ToolPermissionContext,
    PermissionResult,
    PermissionResultAllow,
    PermissionResultDeny,
    PermissionUpdate,

    # Agent system
    AgentDefinition,
    SettingSource,

    # Plugin support
    SdkPluginConfig,

    # Error types
    ClaudeSDKError,
    CLIConnectionError,
    CLINotFoundError,
    ProcessError,
    CLIJSONDecodeError,
)

Basic Usage

Simple Query

The query() function provides the simplest way to interact with Claude:

import anyio
from claude_agent_sdk import query, AssistantMessage, TextBlock

async def main():
    # Simple question
    async for message in query(prompt="What is 2 + 2?"):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, TextBlock):
                    print(block.text)

anyio.run(main)

Query with Tools

Enable Claude to use file operations and shell commands:

from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    options = ClaudeAgentOptions(
        allowed_tools=["Read", "Write", "Bash"],
        permission_mode="acceptEdits",  # Auto-accept file edits
        cwd="/path/to/project"
    )

    async for message in query(
        prompt="Create a hello.py file that prints Hello World",
        options=options
    ):
        print(message)

anyio.run(main)

Interactive Client

For bidirectional conversations with state:

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions

async def main():
    options = ClaudeAgentOptions(
        allowed_tools=["Read", "Write"],
        permission_mode="acceptEdits"
    )

    async with ClaudeSDKClient(options=options) as client:
        # First query
        await client.query("Create a todo.txt file")
        async for msg in client.receive_response():
            print(msg)

        # Follow-up query in same session
        await client.query("Add 'Buy groceries' to the file")
        async for msg in client.receive_response():
            print(msg)

anyio.run(main)

Architecture

The SDK provides two interaction patterns:

  1. query() Function: Stateless, one-shot interactions. Best for simple queries, batch processing, or when you don't need conversation context.

  2. ClaudeSDKClient Class: Stateful, bidirectional streaming. Supports custom tools (via in-process MCP servers), hooks for intercepting operations, and multi-turn conversations with session management.

Key Components:

  • Messages: Structured communication with UserMessage, AssistantMessage, SystemMessage, ResultMessage, StreamEvent
  • Content Blocks: Message content as TextBlock, ThinkingBlock, ToolUseBlock, ToolResultBlock
  • Configuration: Comprehensive options via ClaudeAgentOptions dataclass
  • MCP Servers: In-process tool execution without subprocess overhead
  • Hooks: Intercept and control operations at PreToolUse, PostToolUse, UserPromptSubmit, Stop, SubagentStop, PreCompact
  • Permissions: Runtime control via modes, callbacks, and hooks

Bundled CLI: Claude Code CLI is automatically included—no separate installation needed. The SDK manages the CLI lifecycle transparently.

Capabilities

Core Query Interface

The query() function for simple, stateless interactions and ClaudeSDKClient for bidirectional streaming with state management.

async def query(
    *,
    prompt: str | AsyncIterable[dict[str, Any]],
    options: ClaudeAgentOptions | None = None,
    transport: Transport | None = None,
) -> AsyncIterator[Message]:
    """
    One-shot or unidirectional streaming query to Claude.

    Args:
        prompt: User message string or async iterable of message dicts
        options: Configuration options (default: ClaudeAgentOptions())
        transport: Custom transport implementation (default: subprocess CLI)

    Returns:
        AsyncIterator yielding Message objects
    """
class ClaudeSDKClient:
    """Bidirectional streaming client for interactive conversations."""

    def __init__(
        self,
        options: ClaudeAgentOptions | None = None,
        transport: Transport | None = None,
    ):
        """
        Initialize client.

        Args:
            options: Configuration options
            transport: Custom transport implementation
        """

    async def connect(
        self, prompt: str | AsyncIterable[dict[str, Any]] | None = None
    ) -> None:
        """Establish connection and optionally send initial prompt."""

    async def query(
        self, prompt: str | AsyncIterable[dict[str, Any]], session_id: str = "default"
    ) -> None:
        """Send a message to Claude."""

    async def receive_messages(self) -> AsyncIterator[Message]:
        """Receive all messages until connection closes."""

    async def receive_response(self) -> AsyncIterator[Message]:
        """Receive messages until ResultMessage is received."""

    async def interrupt(self) -> None:
        """Send interrupt signal to stop current operation."""

    async def set_permission_mode(self, mode: str) -> None:
        """Change permission mode during conversation."""

    async def set_model(self, model: str | None = None) -> None:
        """Switch AI model during conversation."""

    async def get_server_info(self) -> dict[str, Any] | None:
        """Get server capabilities and information."""

    async def disconnect(self) -> None:
        """Close connection and clean up resources."""

Core Query Interface

Messages and Content

Message types for communication between user and Claude, and content blocks that compose messages.

@dataclass
class UserMessage:
    """Message from user to Claude."""
    content: str | list[ContentBlock]
    parent_tool_use_id: str | None = None

@dataclass
class AssistantMessage:
    """Message from Claude to user."""
    content: list[ContentBlock]
    model: str
    parent_tool_use_id: str | None = None

@dataclass
class SystemMessage:
    """System-level message."""
    subtype: str
    data: dict[str, Any]

@dataclass
class ResultMessage:
    """Final result of conversation turn."""
    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 = None

@dataclass
class StreamEvent:
    """Raw stream event from Anthropic API."""
    uuid: str
    session_id: str
    event: dict[str, Any]
    parent_tool_use_id: str | None = None

Message = UserMessage | AssistantMessage | SystemMessage | ResultMessage | StreamEvent
@dataclass
class TextBlock:
    """Plain text content."""
    text: str

@dataclass
class ThinkingBlock:
    """Extended thinking content."""
    thinking: str
    signature: str

@dataclass
class ToolUseBlock:
    """Tool invocation request."""
    id: str
    name: str
    input: dict[str, Any]

@dataclass
class ToolResultBlock:
    """Tool execution result."""
    tool_use_id: str
    content: str | list[dict[str, Any]] | None = None
    is_error: bool | None = None

ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock

Messages and Content

Configuration Options

Comprehensive configuration via ClaudeAgentOptions dataclass covering tools, prompts, permissions, budgets, models, and more.

@dataclass
class ClaudeAgentOptions:
    """Configuration options for Claude SDK."""

    # Tool configuration
    allowed_tools: list[str] = field(default_factory=list)
    disallowed_tools: list[str] = field(default_factory=list)

    # Prompt configuration
    system_prompt: str | SystemPromptPreset | None = None

    # MCP server configuration
    mcp_servers: dict[str, McpServerConfig] | str | Path = field(default_factory=dict)

    # Permission configuration
    permission_mode: PermissionMode | None = None
    permission_prompt_tool_name: str | None = None
    can_use_tool: CanUseTool | None = None

    # Session configuration
    continue_conversation: bool = False
    resume: str | None = None
    fork_session: bool = False

    # Budget and limits
    max_turns: int | None = None
    max_budget_usd: float | None = None
    max_thinking_tokens: int | None = None

    # Model configuration
    model: str | None = None
    fallback_model: str | None = None

    # Working directory and CLI
    cwd: str | Path | None = None
    cli_path: str | Path | None = None
    add_dirs: list[str | Path] = field(default_factory=list)

    # Settings and sources
    settings: str | None = None
    setting_sources: list[SettingSource] | None = None

    # Environment
    env: dict[str, str] = field(default_factory=dict)
    extra_args: dict[str, str | None] = field(default_factory=dict)

    # Callbacks
    stderr: Callable[[str], None] | None = None
    debug_stderr: Any = sys.stderr  # Deprecated: Use stderr callback instead

    # Hooks and plugins
    hooks: dict[HookEvent, list[HookMatcher]] | None = None
    agents: dict[str, AgentDefinition] | None = None
    plugins: list[SdkPluginConfig] = field(default_factory=list)

    # Advanced features
    include_partial_messages: bool = False
    output_format: dict[str, Any] | None = None
    max_buffer_size: int | None = None
    user: str | None = None

Configuration Options

Custom Tools (In-Process MCP Servers)

Define custom tools as Python functions that Claude can invoke, running in the same process without subprocess overhead.

def tool(
    name: str,
    description: str,
    input_schema: type | dict[str, Any]
) -> Callable[[Callable[[Any], Awaitable[dict[str, Any]]]], SdkMcpTool[Any]]:
    """
    Decorator for creating custom tools.

    Args:
        name: Tool name
        description: Tool description for Claude
        input_schema: Input schema as type or dict

    Returns:
        Decorator that wraps handler function
    """

def create_sdk_mcp_server(
    name: str,
    version: str = "1.0.0",
    tools: list[SdkMcpTool[Any]] | None = None
) -> McpSdkServerConfig:
    """
    Create an in-process MCP server with custom tools.

    Args:
        name: Server name
        version: Server version
        tools: List of tool definitions

    Returns:
        Server configuration for use in ClaudeAgentOptions.mcp_servers
    """

@dataclass
class SdkMcpTool(Generic[T]):
    """Custom tool definition."""
    name: str
    description: str
    input_schema: type[T] | dict[str, Any]
    handler: Callable[[T], Awaitable[dict[str, Any]]]

Custom Tools (MCP Servers)

Hook System

Intercept and control Claude's operations at specific points in the agent loop with PreToolUse, PostToolUse, UserPromptSubmit, Stop, SubagentStop, and PreCompact hooks.

HookEvent = Literal[
    "PreToolUse",
    "PostToolUse",
    "UserPromptSubmit",
    "Stop",
    "SubagentStop",
    "PreCompact"
]

@dataclass
class HookMatcher:
    """Hook configuration with pattern matching."""
    matcher: str | None = None  # Tool name pattern (e.g., "Bash", "Write|Edit")
    hooks: list[HookCallback] = field(default_factory=list)

HookCallback = Callable[
    [HookInput, str | None, HookContext],
    Awaitable[HookJSONOutput],
]

class HookContext(TypedDict):
    """Context provided to hooks."""
    signal: Any | None

Hook System

Permission Control

Runtime permission control via modes, programmatic callbacks, and permission updates.

PermissionMode = Literal["default", "acceptEdits", "plan", "bypassPermissions"]

CanUseTool = Callable[
    [str, dict[str, Any], ToolPermissionContext],
    Awaitable[PermissionResult]
]

@dataclass
class ToolPermissionContext:
    """Context for permission callbacks."""
    signal: Any | None = None
    suggestions: list[PermissionUpdate] = field(default_factory=list)

@dataclass
class PermissionResultAllow:
    """Allow permission decision."""
    behavior: Literal["allow"] = "allow"
    updated_input: dict[str, Any] | None = None
    updated_permissions: list[PermissionUpdate] | None = None

@dataclass
class PermissionResultDeny:
    """Deny permission decision."""
    behavior: Literal["deny"] = "deny"
    message: str = ""
    interrupt: bool = False

PermissionResult = PermissionResultAllow | PermissionResultDeny

@dataclass
class PermissionUpdate:
    """Permission configuration update."""
    type: Literal[
        "addRules", "replaceRules", "removeRules",
        "setMode", "addDirectories", "removeDirectories"
    ]
    rules: list[PermissionRuleValue] | None = None
    behavior: PermissionBehavior | None = None
    mode: PermissionMode | None = None
    directories: list[str] | None = None
    destination: PermissionUpdateDestination | None = None

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary for CLI."""

Permission Control

Agent Definitions

Define custom agents with specific tools, prompts, and models for specialized tasks.

@dataclass
class AgentDefinition:
    """Custom agent configuration."""
    description: str
    prompt: str
    tools: list[str] | None = None
    model: Literal["sonnet", "opus", "haiku", "inherit"] | None = None

SettingSource = Literal["user", "project", "local"]

Agent Definitions

MCP Server Configuration

Configure external MCP servers via stdio, SSE, or HTTP transports, in addition to in-process SDK servers.

class McpStdioServerConfig(TypedDict):
    """Subprocess MCP server via stdio."""
    type: NotRequired[Literal["stdio"]]
    command: str
    args: NotRequired[list[str]]
    env: NotRequired[dict[str, str]]

class McpSSEServerConfig(TypedDict):
    """MCP server via Server-Sent Events."""
    type: Literal["sse"]
    url: str
    headers: NotRequired[dict[str, str]]

class McpHttpServerConfig(TypedDict):
    """MCP server via HTTP."""
    type: Literal["http"]
    url: str
    headers: NotRequired[dict[str, str]]

class McpSdkServerConfig(TypedDict):
    """In-process SDK MCP server."""
    type: Literal["sdk"]
    name: str
    instance: McpServer

McpServerConfig = (
    McpStdioServerConfig | McpSSEServerConfig |
    McpHttpServerConfig | McpSdkServerConfig
)

MCP Server Configuration

Error Handling

Exception types for handling SDK errors including connection issues, process failures, and parsing errors.

class ClaudeSDKError(Exception):
    """Base exception for all Claude SDK errors."""

class CLIConnectionError(ClaudeSDKError):
    """Raised when unable to connect to Claude Code."""

class CLINotFoundError(CLIConnectionError):
    """Raised when Claude Code is not found or not installed."""

    def __init__(
        self,
        message: str = "Claude Code not found",
        cli_path: str | None = None
    ):
        ...

    cli_path: str | None

class ProcessError(ClaudeSDKError):
    """Raised when the CLI process fails."""

    def __init__(
        self,
        message: str,
        exit_code: int | None = None,
        stderr: str | None = None
    ):
        ...

    exit_code: int | None
    stderr: str | None

class CLIJSONDecodeError(ClaudeSDKError):
    """Raised when unable to decode JSON from CLI output."""

    def __init__(self, line: str, original_error: Exception):
        ...

    line: str
    original_error: Exception

Error Handling

Version Information

__version__: str  # Current SDK version (e.g., "0.1.8")

System Prompt Configuration

Configure Claude's system prompt using presets or custom text:

class SystemPromptPreset(TypedDict):
    """System prompt preset configuration."""
    type: Literal["preset"]
    preset: Literal["claude_code"]
    append: NotRequired[str]

Usage:

# Use Claude Code's default system prompt
options = ClaudeAgentOptions(
    system_prompt={"type": "preset", "preset": "claude_code"}
)

# Append additional instructions
options = ClaudeAgentOptions(
    system_prompt={
        "type": "preset",
        "preset": "claude_code",
        "append": "Always explain your reasoning step by step."
    }
)

# Use custom system prompt
options = ClaudeAgentOptions(
    system_prompt="You are a helpful Python expert specializing in async programming."
)

Plugin Support

Load external plugins to extend SDK functionality:

class SdkPluginConfig(TypedDict):
    """Plugin configuration."""
    type: Literal["local"]
    path: str

Usage:

options = ClaudeAgentOptions(
    plugins=[
        {"type": "local", "path": "/path/to/plugin"}
    ]
)