Python SDK for programmatically interacting with Claude Code, enabling AI-powered automation workflows with support for bidirectional conversations, custom in-process tools, hooks, and fine-grained permission control
—
—
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
—
The risk profile of this skill
This plugin was archived by the owner on Jun 3, 2026
Reason: Retiring all tiles created prior to the transition to plugin support
Content blocks are the building blocks of messages in conversations with Claude. They represent different types of content including text, thinking, tool uses, and tool results.
Union of all possible content block types.
ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock
"""
Union of all content block types.
Content blocks appear in AssistantMessage and UserMessage objects to
represent different types of content:
- TextBlock: Normal text output from Claude
- ThinkingBlock: Extended thinking content (when enabled)
- ToolUseBlock: Request to execute a tool
- ToolResultBlock: Result from tool execution
Use isinstance() to determine the specific block type and access
type-specific fields.
"""Plain text content from Claude or user.
@dataclass
class TextBlock:
"""
Text content block.
Represents plain text in a message. This is the most common content
block type for normal conversation text.
Attributes:
text: The text content
"""
text: str
"""Text content.
The plain text content of this block. Can be a single word, sentence,
paragraph, or longer text.
Examples:
"Hello, how can I help you?"
"To solve this problem, we need to..."
"The result is 42."
"""Extended thinking content from Claude.
@dataclass
class ThinkingBlock:
"""
Thinking content block.
Represents extended thinking from Claude when using models with
thinking capabilities (like Claude Opus with extended thinking enabled).
This shows Claude's internal reasoning process.
Attributes:
thinking: The thinking content
signature: Digital signature for the thinking block
"""
thinking: str
"""Thinking content.
Claude's internal reasoning and thought process. This text shows how
Claude is analyzing the problem, considering options, and planning
its response.
Example:
"Let me think through this step by step. First, I need to
understand what the user is asking. They want to know about...
I should consider... The best approach would be..."
"""
signature: str
"""Digital signature.
Cryptographic signature that verifies the authenticity of the thinking
content. Ensures the thinking wasn't modified after generation.
"""Request from Claude to execute a tool.
@dataclass
class ToolUseBlock:
"""
Tool use content block.
Represents a request from Claude to execute a tool. When Claude needs
to perform an action like reading a file or running a command, it
generates a ToolUseBlock with the tool name and input parameters.
The SDK or CLI handles executing the tool and providing results back
to Claude via ToolResultBlock.
Attributes:
id: Unique identifier for this tool use
name: Name of the tool to execute
input: Input parameters for the tool
"""
id: str
"""Unique tool use identifier.
A unique ID for this specific tool execution. Used to match tool
uses with their results (ToolResultBlock.tool_use_id).
Example: "toolu_01A2B3C4D5E6F7G8H9I0J1K2"
"""
name: str
"""Tool name.
The name of the tool Claude wants to execute. This matches tool
names from the allowed_tools configuration or MCP server tools.
Examples:
"Read" - Read a file
"Write" - Write a file
"Bash" - Execute a bash command
"Grep" - Search files
"custom_tool" - Your custom MCP tool
"""
input: dict[str, Any]
"""Tool input parameters.
Dictionary of parameters to pass to the tool. Structure varies by
tool type.
Examples:
{"file_path": "/home/user/file.txt"} # Read tool
{"command": "ls -la"} # Bash tool
{"pattern": "TODO", "path": "./src"} # Grep tool
"""Result from executing a tool.
@dataclass
class ToolResultBlock:
"""
Tool result content block.
Contains the result of a tool execution. After Claude requests a tool
use via ToolUseBlock, the SDK executes the tool and provides results
back to Claude in a ToolResultBlock.
Attributes:
tool_use_id: ID of the tool use this is a result for
content: The result content
is_error: Whether the tool execution resulted in an error
"""
tool_use_id: str
"""Tool use identifier.
The ID of the ToolUseBlock this result corresponds to. Used to match
results with their requests.
Example: "toolu_01A2B3C4D5E6F7G8H9I0J1K2"
"""
content: str | list[dict[str, Any]] | None = None
"""Result content.
The output from the tool execution. Can be:
- A string for simple text results
- A list of content dictionaries for rich content
- None if the tool produced no output
Examples:
"File contents: Hello World"
[{"type": "text", "text": "Success"}]
None
"""
is_error: bool | None = None
"""Error flag.
Indicates whether the tool execution resulted in an error:
- True: Tool execution failed
- False: Tool execution succeeded
- None: Error status not specified (usually means success)
When True, the content typically contains error details.
"""from claude_agent_sdk import query, AssistantMessage, TextBlock
async for msg in query(prompt="Explain Python"):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, TextBlock):
print(block.text)from claude_agent_sdk import (
query, AssistantMessage, TextBlock, ThinkingBlock,
ToolUseBlock, ToolResultBlock, ClaudeAgentOptions
)
options = ClaudeAgentOptions(allowed_tools=["Read", "Bash"])
async for msg in query(prompt="Analyze this project", options=options):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, TextBlock):
print(f"[Text] {block.text}")
elif isinstance(block, ThinkingBlock):
print(f"[Thinking] {block.thinking}")
elif isinstance(block, ToolUseBlock):
print(f"[Tool Use] {block.name}: {block.input}")
elif isinstance(block, ToolResultBlock):
error_status = " (ERROR)" if block.is_error else ""
print(f"[Tool Result{error_status}] {block.content}")from claude_agent_sdk import query, AssistantMessage, TextBlock
all_text = []
async for msg in query(prompt="Write a story"):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, TextBlock):
all_text.append(block.text)
full_response = "\n".join(all_text)
print(full_response)from claude_agent_sdk import (
query, AssistantMessage, ToolUseBlock, ClaudeAgentOptions
)
options = ClaudeAgentOptions(allowed_tools=["Read", "Write", "Bash"])
tools_used = []
async for msg in query(prompt="Build a web server", options=options):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, ToolUseBlock):
tools_used.append({
"id": block.id,
"name": block.name,
"input": block.input
})
print(f"Claude used {len(tools_used)} tools:")
for tool in tools_used:
print(f" - {tool['name']}: {tool['input']}")from claude_agent_sdk import (
query, AssistantMessage, ToolResultBlock, ClaudeAgentOptions
)
options = ClaudeAgentOptions(allowed_tools=["Bash"])
async for msg in query(prompt="Run an invalid command", options=options):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, ToolResultBlock):
if block.is_error:
print(f"Error in tool {block.tool_use_id}:")
print(f" {block.content}")from claude_agent_sdk import (
query, AssistantMessage, TextBlock, ToolUseBlock,
ToolResultBlock, ClaudeAgentOptions
)
options = ClaudeAgentOptions(allowed_tools=["Read"])
log = []
async for msg in query(prompt="Read config.json", options=options):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, TextBlock):
log.append({"type": "text", "content": block.text})
elif isinstance(block, ToolUseBlock):
log.append({
"type": "tool_use",
"tool": block.name,
"input": block.input
})
elif isinstance(block, ToolResultBlock):
log.append({
"type": "tool_result",
"content": block.content,
"error": block.is_error
})
# Display log
for entry in log:
print(f"{entry['type']}: {entry.get('content', entry.get('tool', ''))}")from claude_agent_sdk import (
query, AssistantMessage, TextBlock, ToolUseBlock
)
text_blocks = []
tool_blocks = []
async for msg in query(prompt="Analyze files"):
if isinstance(msg, AssistantMessage):
text_blocks.extend([b for b in msg.content if isinstance(b, TextBlock)])
tool_blocks.extend([b for b in msg.content if isinstance(b, ToolUseBlock)])
print(f"Text blocks: {len(text_blocks)}")
print(f"Tool blocks: {len(tool_blocks)}")from claude_agent_sdk import (
query, AssistantMessage, ThinkingBlock, ClaudeAgentOptions
)
# Note: Thinking blocks require extended thinking enabled
options = ClaudeAgentOptions(
model="claude-opus-4-20250514" # Model with extended thinking
)
async for msg in query(prompt="Solve this complex problem", options=options):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, ThinkingBlock):
print("=== Claude's Thinking Process ===")
print(block.thinking)
print(f"Signature: {block.signature[:50]}...")from claude_agent_sdk import (
query, AssistantMessage, ToolUseBlock, ToolResultBlock,
ClaudeAgentOptions
)
options = ClaudeAgentOptions(allowed_tools=["Read", "Write", "Bash"])
tool_chain = []
async for msg in query(prompt="Create and test a script", options=options):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, ToolUseBlock):
tool_chain.append({
"id": block.id,
"type": "use",
"name": block.name,
"input": block.input
})
elif isinstance(block, ToolResultBlock):
# Find the matching tool use
for entry in tool_chain:
if entry["id"] == block.tool_use_id and entry["type"] == "use":
entry["result"] = block.content
entry["error"] = block.is_error
break
# Display tool chain
print("Tool Execution Chain:")
for i, entry in enumerate(tool_chain, 1):
if entry["type"] == "use":
status = "ERROR" if entry.get("error") else "SUCCESS"
print(f"{i}. {entry['name']} [{status}]")
print(f" Input: {entry['input']}")
if "result" in entry:
result_preview = str(entry["result"])[:100]
print(f" Result: {result_preview}...")from claude_agent_sdk import (
query, AssistantMessage, TextBlock, ThinkingBlock,
ToolUseBlock, ToolResultBlock
)
stats = {
"text": 0,
"thinking": 0,
"tool_use": 0,
"tool_result": 0
}
async for msg in query(prompt="Complex task"):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, TextBlock):
stats["text"] += 1
elif isinstance(block, ThinkingBlock):
stats["thinking"] += 1
elif isinstance(block, ToolUseBlock):
stats["tool_use"] += 1
elif isinstance(block, ToolResultBlock):
stats["tool_result"] += 1
print("Content Block Statistics:")
for block_type, count in stats.items():
print(f" {block_type}: {count}")from claude_agent_sdk import query, AssistantMessage, ToolResultBlock
async for msg in query(prompt="Task with rich output"):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, ToolResultBlock):
content = block.content
# Handle different content types
if isinstance(content, str):
print(f"Text result: {content}")
elif isinstance(content, list):
print("Rich content result:")
for item in content:
if isinstance(item, dict):
item_type = item.get("type", "unknown")
print(f" - Type: {item_type}")
if item_type == "text":
print(f" Text: {item.get('text', '')}")
elif content is None:
print("No output from tool")from claude_agent_sdk import (
query, AssistantMessage, ToolUseBlock, ClaudeAgentOptions
)
options = ClaudeAgentOptions(allowed_tools=["Bash", "Read", "Write"])
tool_inputs = {}
async for msg in query(prompt="Work on this project", options=options):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, ToolUseBlock):
if block.name not in tool_inputs:
tool_inputs[block.name] = []
tool_inputs[block.name].append(block.input)
print("Tool Input Analysis:")
for tool_name, inputs in tool_inputs.items():
print(f"\n{tool_name} ({len(inputs)} uses):")
for i, input_data in enumerate(inputs, 1):
print(f" {i}. {input_data}")from claude_agent_sdk import (
query, AssistantMessage, TextBlock, ToolUseBlock,
ClaudeAgentOptions
)
options = ClaudeAgentOptions(allowed_tools=["Read", "Write"])
explanations = []
actions = []
async for msg in query(prompt="Fix this bug", options=options):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, TextBlock):
explanations.append(block.text)
elif isinstance(block, ToolUseBlock):
actions.append(f"{block.name}: {block.input}")
print("=== What Claude Said ===")
print("\n".join(explanations))
print("\n=== What Claude Did ===")
print("\n".join(actions))from claude_agent_sdk import (
query, AssistantMessage, ToolUseBlock, ToolResultBlock,
ClaudeAgentOptions
)
options = ClaudeAgentOptions(allowed_tools=["Bash"])
current_tool_use = None
async for msg in query(prompt="Try a command", options=options):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, ToolUseBlock):
current_tool_use = block
print(f"Attempting: {block.name} with {block.input}")
elif isinstance(block, ToolResultBlock):
if block.is_error and current_tool_use:
print(f"Failed: {current_tool_use.name}")
print(f"Error: {block.content}")
print("Claude will likely try an alternative...")
elif current_tool_use:
print(f"Success: {current_tool_use.name}")
current_tool_use = Nonefrom claude_agent_sdk import (
query, AssistantMessage, TextBlock, ThinkingBlock,
ToolUseBlock, ToolResultBlock
)
def get_block_type_name(block):
if isinstance(block, TextBlock):
return "text"
elif isinstance(block, ThinkingBlock):
return "thinking"
elif isinstance(block, ToolUseBlock):
return "tool_use"
elif isinstance(block, ToolResultBlock):
return "tool_result"
else:
return "unknown"
block_sequence = []
async for msg in query(prompt="Multi-step task"):
if isinstance(msg, AssistantMessage):
for block in msg.content:
block_sequence.append(get_block_type_name(block))
print("Block sequence:")
print(" -> ".join(block_sequence))docs