Chapter 04 · Section II · 12 min read
4.2 Python SDK: ClaudeSDKClient and options
The Python SDK — the client class, the options object, streaming, and the patterns for integrating Claude Code into a Python program.
The Python SDK is a thin wrapper around the same headless invocation shape you saw in Section 4.1 — plus proper async streaming, structured options, and Python-native error types. Reach for it when you are building anything more than a shell script.
Installation
pip install claude-code-sdk
Python 3.10+.
Minimal example
import asyncio
from claude_code_sdk import ClaudeSDKClient, ClaudeCodeOptions
async def main():
async with ClaudeSDKClient(
options=ClaudeCodeOptions(
model="claude-sonnet-4-6",
permission_mode="acceptEdits",
),
) as client:
async for msg in client.query("Summarise src/README.md"):
if msg.type == "assistant":
print(msg.content)
asyncio.run(main())
Three moving parts:
ClaudeSDKClient— the client. Manages the session lifecycle.ClaudeCodeOptions— the options object: model, permission mode, tools, hooks, cwd, and so on.client.query(...)— returns an async iterator of messages.
The options surface
options = ClaudeCodeOptions(
model="claude-opus-4-7",
permission_mode="plan",
cwd="/path/to/repo",
allowed_tools=["Read", "Grep", "Glob"],
disallowed_tools=["Bash"],
max_thinking_tokens=8000,
system_prompt_append="Return replies as JSON.",
)
Every flag you would pass on the CLI has a corresponding field on ClaudeCodeOptions. This is a superset — the SDK also lets you attach in-process hooks and callbacks that a shell invocation cannot.
Streaming messages
The async iterator yields messages of several types:
assistant— model text.user— tool results, shown as user turns for the model.result— the final envelope with cost, exit reason, session id.
Filter for what you want:
async for msg in client.query("audit the branch"):
match msg.type:
case "assistant":
print(msg.content)
case "result":
print(f"cost: ${msg.total_cost_usd:.4f}")
Long-lived sessions
For multi-turn conversations, the same client can hold a session across queries:
async with ClaudeSDKClient(options=opts) as client:
async for _ in client.query("Read src/user.ts"):
pass
async for msg in client.query("Now propose a diff that adds validation"):
...
The second query has the context of the first.
Errors
The SDK raises typed exceptions: ClaudeSDKError (base), plus subtypes for permission denials, model errors, and network failures. Catch narrowly, not except Exception.
Check your understanding
Quick check
—