Python wrapper around the Claude CLI — call Claude from code using your existing subscription, no API key needed.
Project description
Claude Subprocess SDK
A Python wrapper around the claude CLI that lets you call Claude from your code using your existing Claude subscription — no API key needed.
It works by spawning claude -p <prompt> --output-format json as a subprocess and parsing the response.
Installation
pip install claude-subprocess-sdk
Or install from GitHub:
pip install git+https://github.com/rmnjaat/claude_sdk.git
Or install from source:
git clone https://github.com/rmnjaat/claude_sdk.git
cd claude_sdk
pip install .
For development (editable install):
pip install -e .
Prerequisite: The Claude CLI must be installed and authenticated.
npm install -g @anthropic-ai/claude-code
Quick Start
from claude_sdk import Claude
# Safe by default — read-only, $1 budget cap
client = Claude()
response = client.ask("Explain Python decorators")
print(response.result)
print(response.cost_usd)
Features
- One-shot queries —
client.ask("prompt") - Streaming —
client.stream("prompt", on_event=callback)orclient.stream_iter("prompt") - Multi-turn conversations —
Conversationclass with automatic session tracking - Session management — resume, fork, name sessions, and resume from PRs
- Structured output — pass a JSON schema, get parsed dicts back
- Custom agents — define and use your own agent types
- Safety presets —
"safe","careful","full"with sane defaults - Fine-grained tool control — allow/disallow specific tools or tool patterns
- Directory sandboxing — restrict Claude's file access to specific directories
- Budget protection — per-call spending caps and turn limits
- No external dependencies — pure Python stdlib
Safety Presets
| Preset | Permission Mode | Tools | Max Turns | Budget |
|---|---|---|---|---|
safe (default) |
plan |
Read, Glob, Grep | 1 | $1 |
careful |
acceptEdits |
+ Edit, Write | 3 | $5 |
full |
auto |
All (including Bash, Agent) | 10 | $20 |
# Read-only (default)
client = Claude()
# Can edit files but not run shell commands
client = Claude(safety="careful")
# Full access — use with caution
client = Claude(safety="full")
Any explicit parameter overrides the preset:
# Start from "careful" but also allow Bash for git commands only
client = Claude(safety="careful", allowed_tools=["Bash(git:*)"])
Usage Examples
Choose a model
client = Claude(model="sonnet")
# Also: "opus", "haiku", or a full model ID like "claude-sonnet-4-6"
One-shot query
response = client.ask("Explain Python decorators")
print(response.result)
Continue a conversation
response = client.ask("What is recursion?")
response = client.ask("Show me an example", continue_session=True)
Resume a specific session
response = client.ask("Where were we?", resume="5b81a84a-c6d3-...")
Fork a session (branch the conversation)
# Creates a NEW session that starts with full history of the original
response = client.ask("Try a different approach", resume="abc-123", fork=True)
# response.session_id is now a new ID; the original session is untouched
Named sessions
response = client.ask("Start my code review", session_name="code-review-pr-42")
Custom session ID
import uuid
my_id = str(uuid.uuid4())
response = client.ask("Hello", session_id=my_id)
Resume from a PR
response = client.ask("What's the status?", from_pr="123")
response = client.ask("Review this", from_pr="https://github.com/org/repo/pull/123")
Multi-turn with Conversation helper
from claude_sdk import Claude, Conversation
client = Claude(model="sonnet")
conv = Conversation(client, system_prompt="You are a helpful tutor")
r1 = conv.say("What is recursion?")
r2 = conv.say("Show me a Python example") # auto-continues
r3 = conv.say("Now explain the base case") # still same session
print(conv.session_id) # session UUID
print(conv.total_cost_usd) # cumulative cost
print(conv.turn_count) # 3
print(conv.history) # list of (prompt, response) tuples
# Fork the conversation (try a different direction)
conv2 = conv.fork()
r4 = conv2.say("Try a tree analogy instead")
# conv2 has a new session; conv is untouched
Streaming (callback-based)
def on_event(event):
if event.get("type") == "assistant":
for block in event["message"]["content"]:
if block["type"] == "text":
print(block["text"], end="", flush=True)
response = client.stream("Write a poem about code", on_event=on_event)
Streaming (iterator-based)
for event in client.stream_iter("Write a poem about code"):
if event.get("type") == "assistant":
for block in event["message"]["content"]:
if block["type"] == "text":
print(block["text"], end="", flush=True)
Streaming with partial messages
response = client.stream(
"Write a story",
on_event=on_event,
include_partial_messages=True # get token-by-token chunks
)
Structured output
response = client.ask(
"Extract name and age from: John is 30",
json_schema={
"type": "object",
"properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
"required": ["name", "age"]
}
)
print(response.parsed) # {"name": "John", "age": 30}
Custom agents
client = Claude(
safety="full",
agents={
"reviewer": {
"description": "Reviews code for bugs and style",
"prompt": "You are a senior code reviewer."
},
"security": {
"description": "Security audit agent",
"prompt": "You are a security expert. Find vulnerabilities."
}
}
)
response = client.ask("Check auth.py", agent="reviewer")
Tool Control
Fine-grained control over what Claude can do:
# Only allow read operations (default in "safe" preset)
client = Claude(tools=["Read", "Glob", "Grep"])
# Allow Bash but ONLY for git commands
client = Claude(allowed_tools=["Bash(git:*)"])
# Allow everything EXCEPT file deletion
client = Claude(disallowed_tools=["Bash(rm:*)", "Bash(rmdir:*)"])
# No tools at all (pure text Q&A, like a chatbot)
client = Claude(tools=[])
Directory Sandboxing
Restrict which directories Claude can access:
# Claude can only see/touch files in /tmp/sandbox
client = Claude(cwd="/tmp/sandbox")
# Claude can access /tmp/sandbox + an additional directory
client = Claude(cwd="/tmp/sandbox", add_dirs=["/data/inputs"])
Budget Protection
Prevent runaway costs:
client = Claude(
max_budget_usd=5.0, # hard spending cap per call
max_turns=3, # max agentic turns per call
)
Dangerous Mode
Certain configurations require explicit opt-in:
# This RAISES ClaudeSafetyError:
client = Claude(permission_mode="bypassPermissions")
# This works (explicit acknowledgement):
client = Claude(permission_mode="bypassPermissions", confirm_unsafe=True)
Rules enforced:
permission_mode="bypassPermissions"requiresconfirm_unsafe=Truedangerously_skip_permissions=Truerequiresconfirm_unsafe=Trueallow_dangerously_skip_permissions=Truerequiresconfirm_unsafe=Truemax_turns > 20prints a warning about runaway cost
MCP & Plugins
# Use an MCP config file
client = Claude(mcp_config="/path/to/mcp-config.json")
# Multiple MCP configs
client = Claude(mcp_config=["/path/to/config1.json", "/path/to/config2.json"])
# Strict MCP (only use explicitly configured MCP servers)
client = Claude(mcp_config="/path/to/config.json", strict_mcp_config=True)
# Plugin directories
client = Claude(plugin_dirs=["/path/to/plugins"])
Advanced Options
client = Claude(
system_prompt="You are ...", # replace default system prompt
append_system_prompt="Also do ...", # add to default system prompt
effort="high", # "low", "medium", "high", "max"
fallback_model="haiku", # fallback model on overload
no_session_persistence=True, # ephemeral sessions (not saved to disk)
bare=True, # minimal mode (no hooks, LSP, plugins)
verbose=True, # verbose output
debug=True, # debug logging
debug_file="/tmp/claude-debug.log", # write debug logs to file
files=["file_abc:doc.txt"], # file resources
worktree=True, # create git worktree for isolation
brief=True, # enable SendUserMessage tool
settings="/path/to/settings.json", # custom settings file
setting_sources=["user", "project"], # which setting sources to use
betas=["beta-feature"], # beta feature flags
disable_slash_commands=True, # disable all skills/slash commands
exclude_dynamic_prompt=True, # exclude dynamic system prompt sections
)
Project Structure
claude_sdk/
├── pyproject.toml # Package configuration (pip installable)
├── claude_sdk/
│ ├── __init__.py # Public API exports
│ ├── client.py # Core Claude class — builds CLI commands, runs subprocess, parses output
│ ├── models.py # ClaudeResponse dataclass
│ ├── exceptions.py # Custom exceptions (CLINotFound, CLIError, SafetyError, etc.)
│ ├── conversation.py # Multi-turn Conversation helper with session tracking
│ └── streaming.py # Streaming response handler (stream-json parsing + callbacks)
No external dependencies — pure Python stdlib.
Response Object
response = client.ask("Hello")
response.result # The text response
response.is_error # Whether the CLI reported an error
response.cost_usd # Cost of the call
response.duration_ms # Wall clock time
response.duration_api_ms # API-only time
response.num_turns # Conversation turns
response.session_id # Session UUID for resuming later
response.stop_reason # "end_turn", "max_turns", etc.
response.usage # Raw token usage dict
response.model_usage # Per-model breakdown (tokens, cost, context window)
response.permission_denials # Tools blocked by permissions
response.parsed # Structured output dict (if json_schema used)
response.raw # Full raw JSON dict from the CLI
Error Handling
from claude_sdk.exceptions import (
ClaudeSDKError, # Base exception for all SDK errors
ClaudeCLINotFound, # claude binary not in PATH
ClaudeCLIError, # CLI returned an error (auth issues, invalid flags, etc.)
ClaudeSessionNotFound, # Invalid session ID for resume/continue
ClaudeSafetyError, # Unsafe config without confirm_unsafe=True
)
try:
response = client.ask("Hello")
except ClaudeCLINotFound:
print("Install Claude CLI: npm install -g @anthropic-ai/claude-code")
except ClaudeSessionNotFound as e:
print(f"Session {e.session_id} not found")
except ClaudeSafetyError as e:
print(f"Unsafe setting: {e.unsafe_setting}")
except ClaudeCLIError as e:
print(f"CLI error (exit {e.exit_code}): {e.message}")
CLI Flags Reference
Every claude CLI flag has a corresponding Python parameter:
| Python Parameter | CLI Flag | Type |
|---|---|---|
model |
--model |
str |
system_prompt |
--system-prompt |
str |
append_system_prompt |
--append-system-prompt |
str |
effort |
--effort |
str |
fallback_model |
--fallback-model |
str |
allowed_tools |
--allowedTools |
list[str] |
disallowed_tools |
--disallowedTools |
list[str] |
tools |
--tools |
list[str] |
permission_mode |
--permission-mode |
str |
dangerously_skip_permissions |
--dangerously-skip-permissions |
bool |
max_budget_usd |
--max-budget-usd |
float |
json_schema |
--json-schema |
dict |
mcp_config |
--mcp-config |
str or list[str] |
cwd |
subprocess working directory | str |
add_dirs |
--add-dir |
list[str] |
agent |
--agent |
str |
agents |
--agents |
dict |
verbose |
--verbose |
bool |
debug |
--debug |
bool or str |
bare |
--bare |
bool |
files |
--file |
list[str] |
worktree |
--worktree |
bool or str |
See the full parameter list in claude_sdk/client.py.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file claude_subprocess_sdk-0.1.0.tar.gz.
File metadata
- Download URL: claude_subprocess_sdk-0.1.0.tar.gz
- Upload date:
- Size: 18.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eb264113b31cefefe2313d688df5ae145275dabd5b7b5070b3a42192e35e0f2a
|
|
| MD5 |
7b7df539cab657fdd6639e4404e35fc9
|
|
| BLAKE2b-256 |
361bb5507cfbf19f87adc2753b5e1b92b6d1990e4e201cdc2d6117ec4fddf0f1
|
File details
Details for the file claude_subprocess_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: claude_subprocess_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bd5ad383253a46fee839b0935f71bb3995a63513125a538cbfaabba2b0a1a0fb
|
|
| MD5 |
f6d05dd15dcc82fbdf736c760e009344
|
|
| BLAKE2b-256 |
9ce4872bd3ce637b497a4a0f56c194fa768c9fcb8ef13ef41ce23f0031098cdd
|