Python SDK
The claude-agent-sdk package gives Python an async query() for one-shot runs and a ClaudeSDKClient context manager for stateful, multi-turn conversations.
Why it matters
Python dominates data, ML, and ops tooling, so this SDK is how Claude Code agents land inside notebooks, Airflow tasks, and FastAPI services. The two entry points map cleanly to two shapes of work: fire-and-forget (query) versus a long-lived conversational session (ClaudeSDKClient).
How it works
Everything is async; you need an async runtime (asyncio or anyio). Config lives in ClaudeAgentOptions (renamed from ClaudeCodeOptions).
async def query(*, prompt, options=None) -> AsyncIterator[Message]query()opens a fresh session and yields messages; use it for scripts and CI.ClaudeSDKClientkeeps context across turns. Key methods:connect(),query(prompt),receive_response(),receive_messages(),interrupt(),set_permission_mode(),disconnect(). Preferasync withso disconnect is automatic.ClaudeAgentOptionsfields:system_prompt,model,allowed_tools/disallowed_tools,permission_mode,max_turns,mcp_servers,hooks,can_use_tool,cwd,resume,continue_conversation,setting_sources,max_budget_usd.- Message dataclasses:
AssistantMessage(a.contentlist of blocks likeTextBlock),UserMessage,SystemMessage, andResultMessage(total_cost_usd,num_turns,usage). Branch withisinstance. - Install:
pip install claude-agent-sdk. Requires Python 3.10+ and pulls inanyio.
Example
Multi-turn with a retained session, extracting text blocks:
from claude_agent_sdk import ClaudeSDKClient, AssistantMessage, TextBlock
async with ClaudeSDKClient() as client:
await client.query("What's the capital of France?")
async for m in client.receive_response():
if isinstance(m, AssistantMessage):
for b in m.content:
if isinstance(b, TextBlock):
print(b.text)
await client.query("What's its population?") # "its" resolves — context keptPitfalls
receive_response()ends at the result;receive_messages()does not. The former stops after theResultMessagefor the current turn; the latter streams forever and will hang aforloop awaiting the next turn.No matching distribution foundonpip installalmost always means the interpreter is< 3.10— checkpython3 --version.ClaudeAgentOptions, notClaudeCodeOptions. Code or tutorials predating the rename import the old name andImportError.- Synthetic code paths. Calling these from sync code without
asyncio.run(...)/anyio.run(...)silently never executes the coroutine.