Readme
Claude Code SDK for Rust
A Rust SDK for interacting with Claude Code CLI, providing both simple query interfaces and full interactive client capabilities.
v0.4.0 : 🎉 100% Feature Parity with Python SDK v0.1.14 - Including automatic CLI download!
Features
🚀 Simple Query Interface - One-shot queries with the query ( ) function
💬 Interactive Client - Stateful conversations with context retention
🔄 Streaming Support - Real-time message streaming
🛑 Interrupt Capability - Cancel ongoing operations
🔧 Full Configuration - Comprehensive options for Claude Code
📦 Type Safety - Strongly typed with serde support
⚡ Async/Await - Built on Tokio for async operations
🔒 Control Protocol - Full support for permissions, hooks, and MCP servers
💰 Token Optimization - Built-in tools to minimize costs and track usage
📥 Auto CLI Download - Automatically downloads Claude Code CLI if not found (v0.4.0+)
📁 File Checkpointing - Rewind file changes to any point in conversation (v0.4.0+)
📊 Structured Output - JSON schema validation for responses (v0.4.0+)
Python SDK Parity (v0.4.0)
This Rust SDK achieves 100% feature parity with the official Python claude-agent-sdk v0.1.14:
Feature
Python SDK
Rust SDK
Status
Simple query API
✅
✅
✅ Parity
Interactive client
✅
✅
✅ Parity
Streaming messages
✅
✅
✅ Parity
tools (base tool set)
✅
✅
✅ Parity
permission_mode
✅
✅
✅ Parity
max_budget_usd
✅
✅
✅ Parity
fallback_model
✅
✅
✅ Parity
output_format (structured)
✅
✅
✅ Parity
enable_file_checkpointing
✅
✅
✅ Parity
rewind_files ( )
✅
✅
✅ Parity
sandbox
✅
✅
✅ Parity
plugins
✅
✅
✅ Parity
betas (SDK beta features)
✅
✅
✅ Parity
Permission callbacks
✅
✅
✅ Parity
Hook callbacks
✅
✅
✅ Parity
MCP servers (all types)
✅
✅
✅ Parity
Bundled/Auto CLI
✅ (bundled)
✅ (auto-download)
✅ Equivalent
Note : Only user (OS setuid) is not implemented due to platform/privilege requirements.
Token Optimization (New in v0.1.12)
Minimize token consumption and control costs with built-in optimization tools:
use cc_sdk:: { ClaudeCodeOptions, ClaudeSDKClient, PermissionMode} ;
use cc_sdk:: token_tracker:: BudgetLimit;
use cc_sdk:: model_recommendation:: ModelRecommendation;
// 1. Choose cost-effective model
let recommender = ModelRecommendation:: default( ) ;
let model = recommender. suggest ( " simple" ) . unwrap ( ) ; // → Haiku (cheapest)
// Or use latest Sonnet 4.5 for balanced tasks
let latest = recommender. suggest ( " latest" ) . unwrap ( ) ; // → Sonnet 4.5
// 2. Configure for minimal token usage
let options = ClaudeCodeOptions:: builder( )
. model ( model)
. max_turns ( Some ( 3 ) ) // Limit conversation length
. max_output_tokens ( 2000 ) // Cap response size (NEW)
. allowed_tools ( vec! [ " Read" . to_string ( ) ] ) // Restrict tools
. permission_mode ( PermissionMode:: BypassPermissions)
. build ( ) ;
let mut client = ClaudeSDKClient:: new( options) ;
// 3. Set budget with alerts
client. set_budget_limit (
BudgetLimit:: with_cost( 5. 0 ) , // $5 max
Some ( | msg | eprintln! ( " ⚠️ {} " , msg) ) // Alert at 80%
) . await;
// ... run your queries ...
// 4. Monitor usage
let usage = client. get_usage_stats ( ) . await;
println! ( " Tokens: {} , Cost: ${:.2} " , usage. total_tokens ( ) , usage. total_cost_usd) ;
Key Features:
✅ max_output_tokens - Precise output control (1-32000, overrides env var)
✅ TokenUsageTracker - Real-time token and cost monitoring
✅ BudgetLimit - Set cost/token caps with 80% warning threshold
✅ ModelRecommendation - Smart model selection (Haiku/Sonnet/Opus)
✅ Automatic usage tracking from ResultMessage
Model Cost Comparison:
Haiku 3.5: 1x (baseline, cheapest)
Sonnet 4.5 (Latest): ~5x more expensive, best balance ⭐
Opus 4.1: ~15x more expensive, most capable
See Token Optimization Guide for complete strategies and examples.
Complete Feature Set
This Rust SDK provides comprehensive functionality for Claude Code interactions:
✅ Client methods : query ( ) , send_message ( ) , receive_response ( ) , interrupt ( )
✅ Interactive sessions : Full stateful conversation support
✅ Message streaming : Real-time async message handling
✅ Configuration options : System prompts, models, permissions, tools, etc.
✅ Message types : User, Assistant, System, Result messages
✅ Error handling : Comprehensive error types with detailed diagnostics
✅ Session management : Multi-session support with context isolation
✅ Type safety : Leveraging Rust's type system for reliable code
✅ Control Protocol : Permission callbacks, hook system, MCP servers (SDK type)
✅ CLI Compatibility : Configurable protocol format for maximum compatibility
✅ Account Information : Retrieve current account details programmatically
Installation
Add this to your Cargo.toml :
[ dependencies ]
cc-sdk = " 0.4.0"
tokio = { version = "1.0", features = [ " full" ] }
futures = " 0.3"
Automatic CLI Download (Default)
The SDK will automatically download Claude Code CLI if it's not found on your system:
let options = ClaudeCodeOptions:: builder( )
. auto_download_cli ( true ) // Enabled by default
. build ( ) ;
CLI is cached in platform-specific locations:
macOS : ~/Library/Caches/cc-sdk/cli/
Linux : ~/.cache/cc-sdk/cli/
Windows : % LOCALAPPDATA % \cc- sdk\cli\
To disable auto-download, use:
[ dependencies ]
cc-sdk = { version = "0.4.0", default-features = false }
Prerequisites
Claude Code CLI is automatically downloaded by the SDK if not found (v0.4.0+).
For manual installation:
npm install - g @anthropic-ai/claude-code
Environment Setup
For reliable SDK operation, set the ANTHROPIC_USER_EMAIL environment variable:
export ANTHROPIC_USER_EMAIL = " your-email@example.com"
Or create a . env file in your project:
# .env
ANTHROPIC_USER_EMAIL=your-email@example.com
CLAUDE_MODEL=claude-sonnet-4-5-20250929
See Environment Variables Guide for complete details.
Supported Models (2025)
The SDK supports the latest Claude models available in 2025:
Latest Models
Previous Generation
Claude 3.5 Sonnet - " claude-3-5-sonnet-20241022"
Claude 3.5 Haiku - " claude-3-5-haiku-20241022" (fastest)
Using Models in Code
use cc_sdk:: { query, ClaudeCodeOptions, Result } ;
// Using Opus 4.1 (recommended: use alias)
let options = ClaudeCodeOptions:: builder( )
. model ( " opus" ) // or "claude-opus-4-1-20250805" for specific version
. build ( ) ;
// Using Sonnet 4 (recommended: use alias)
let options = ClaudeCodeOptions:: builder( )
. model ( " sonnet" ) // or "claude-sonnet-4-20250514" for specific version
. build ( ) ;
let mut messages = query ( " Your prompt" , Some ( options) ) . await? ;
Quick Start
Simple Query (One-shot)
use cc_sdk:: { query, Result } ;
use futures:: StreamExt;
# [ tokio ::main ]
async fn main ( ) -> Result < ( ) > {
let mut messages = query ( " What is 2 + 2?" , None ) . await? ;
while let Some ( msg) = messages. next ( ) . await {
println! ( " {:?} " , msg? ) ;
}
Ok ( ( ) )
}
Interactive Client
use cc_sdk:: { InteractiveClient, ClaudeCodeOptions, Result } ;
# [ tokio ::main ]
async fn main ( ) -> Result < ( ) > {
let mut client = InteractiveClient:: new( ClaudeCodeOptions:: default( ) ) ? ;
client. connect ( ) . await? ;
// Send a message and receive response
let messages = client. send_and_receive (
" Help me write a Python web server" . to_string ( )
) . await? ;
// Process responses
for msg in & messages {
match msg {
cc_sdk:: Message:: Assistant { message } => {
println! ( " Claude: {:?} " , message) ;
}
_ => { }
}
}
// Send follow-up
let messages = client. send_and_receive (
" Make it use async/await" . to_string ( )
) . await? ;
client. disconnect ( ) . await? ;
Ok ( ( ) )
}
use cc_sdk:: { ClaudeSDKClient, ClaudeCodeOptions, Result } ;
# [ tokio ::main ]
async fn main ( ) -> Result < ( ) > {
let mut client = ClaudeSDKClient:: new( ClaudeCodeOptions:: default( ) ) ;
client. connect ( None ) . await? ;
// Get current account information
let account_info = client. get_account_info ( ) . await? ;
println! ( " Current account: {} " , account_info) ;
client. disconnect ( ) . await? ;
Ok ( ( ) )
}
Streaming Output (Since v0.1.8)
use cc_sdk:: { InteractiveClient, ClaudeCodeOptions, Result } ;
use futures:: StreamExt;
# [ tokio ::main ]
async fn main ( ) -> Result < ( ) > {
let mut client = InteractiveClient:: new( ClaudeCodeOptions:: default( ) ) ? ;
client. connect ( ) . await? ;
// Send a message
client. send_message ( " Explain quantum computing" . to_string ( ) ) . await? ;
// Receive messages as a stream
let mut stream = client. receive_messages_stream ( ) . await;
while let Some ( result) = stream. next ( ) . await {
match result {
Ok ( message) => {
println! ( " Received: {:?} " , message) ;
if matches! ( message, cc_sdk:: Message:: Result { .. } ) {
break ;
}
}
Err ( e) => eprintln! ( " Error: {} " , e) ,
}
}
// Or use the convenience method that stops at Result message
client. send_message ( " What's 2 + 2?" . to_string ( ) ) . await? ;
let mut stream = client. receive_response_stream ( ) . await;
while let Some ( result) = stream. next ( ) . await {
match result {
Ok ( message) => println! ( " Message: {:?} " , message) ,
Err ( e) => eprintln! ( " Error: {} " , e) ,
}
}
client. disconnect ( ) . await? ;
Ok ( ( ) )
}
Advanced Usage
use cc_sdk:: { InteractiveClient, ClaudeCodeOptions, Result } ;
# [ tokio ::main ]
async fn main ( ) -> Result < ( ) > {
let mut client = InteractiveClient:: new( ClaudeCodeOptions:: default( ) ) ? ;
client. connect ( ) . await? ;
// Send message without waiting for response
client. send_message ( " Calculate pi to 100 digits" . to_string ( ) ) . await? ;
// Do other work...
// Receive response when ready (stops at Result message)
let messages = client. receive_response ( ) . await? ;
// Cancel long-running operations
client. send_message ( " Write a 10,000 word essay" . to_string ( ) ) . await? ;
tokio:: time:: sleep( tokio:: time:: Duration:: from_secs( 1 ) ) . await;
client. interrupt ( ) . await? ;
client. disconnect ( ) . await? ;
Ok ( ( ) )
}
Configuration Options
use cc_sdk:: { ClaudeCodeOptions, PermissionMode, ControlProtocolFormat} ;
let options = ClaudeCodeOptions:: builder( )
. system_prompt ( " You are a helpful coding assistant" )
. model ( " claude-3-5-sonnet-20241022" )
. permission_mode ( PermissionMode:: AcceptEdits)
. max_turns ( 10 )
. max_thinking_tokens ( 10000 )
. allowed_tools ( vec! [ " read_file" . to_string ( ) , " write_file" . to_string ( ) ] )
. cwd ( " /path/to/project" )
// New in v0.1.6
. settings ( " claude-settings.json" ) // Use custom settings file
. add_dir ( " /path/to/related/project" ) // Add additional working directories
. add_dirs ( vec! [ PathBuf:: from( " /dir1" ) , PathBuf:: from( " /dir2" ) ] ) // Add multiple dirs
// New in v0.1.11: Control protocol format configuration
. control_protocol_format ( ControlProtocolFormat:: Legacy) // Default: maximum compatibility
. build ( ) ;
Control Protocol (v0.1.12+)
New request helpers and options aligned with the Python SDK:
Query:: set_permission_mode( " acceptEdits" | " default" | " plan" | " bypassPermissions" )
Query:: set_model( Some ( " sonnet" ) ) or set_model ( None ) to clear
ClaudeCodeOptions:: builder( ) . include_partial_messages ( true ) to include partial assistant chunks
Query:: stream_input( stream) automatically calls end_input when finished
Example:
use cc_sdk:: { Query, ClaudeCodeOptions} ;
use cc_sdk:: transport:: SubprocessTransport;
use std:: { collections:: HashMap, sync:: Arc} ;
use tokio:: sync:: Mutex;
# async fn demo ( ) -> cc_sdk:: Result < ( ) > {
let options = ClaudeCodeOptions:: builder( )
. model ( " sonnet" )
. include_partial_messages ( true )
. build ( ) ;
let transport: Box < dyn cc_sdk:: transport:: Transport + Send > =
Box :: new( SubprocessTransport:: new( options) ? ) ;
let transport = Arc:: new( Mutex:: new( transport) ) ;
let mut q = Query:: new( transport, true , None , None , HashMap:: new( ) ) ;
q. start ( ) . await? ; // start routing
q. set_permission_mode ( " acceptEdits" ) . await? ;
q. set_model ( Some ( " opus" . into ( ) ) ) . await? ;
// Stream input; end_input is called automatically when the stream completes
let inputs = vec! [ serde_json:: json! ( " Hello" ) , serde_json:: json! ( { " content" : " Ping" } ) ] ;
q. stream_input ( futures:: stream:: iter( inputs) ) . await? ;
# Ok ( ( ) ) }
Advanced flags mapped to CLI:
fork_session ( true ) → --fork-session
setting_sources ( vec! [ User, Project, Local] ) → --setting-sources user,project,local
agents ( map) → --agents '< json> '
Tools whitelist/blacklist: set allowed_tools / disallowed_tools in ClaudeCodeOptions .
Permission mode: PermissionMode:: { Default , AcceptEdits, Plan, BypassPermissions} .
Runtime approvals: implement CanUseTool and return PermissionResult:: { Allow, Deny} .
MCP servers: configure via options. mcp_servers (stdio/http/sse/sdk), SDK packs JSON for --mcp-config .
use cc_sdk:: { ClaudeCodeOptions, PermissionMode, CanUseTool, ToolPermissionContext, PermissionResult,
PermissionResultAllow, transport:: { Transport, SubprocessTransport} , Query} ;
use std:: { collections:: HashMap, sync:: Arc} ;
use tokio:: sync:: Mutex;
struct AllowRead ;
# [ async_trait ::async_trait ]
impl CanUseTool for AllowRead {
async fn can_use_tool ( & self , tool : & str , _input : & serde_json:: Value, _ctx : & ToolPermissionContext) -> PermissionResult {
if tool == " Read" { PermissionResult:: Allow( PermissionResultAllow{ updated_input: None , updated_permissions: None } ) }
else { cc_sdk:: PermissionResult:: Deny( cc_sdk:: PermissionResultDeny{ message: " Not allowed" . into ( ) , interrupt: false } ) }
}
}
# async fn demo ( ) -> cc_sdk:: Result < ( ) > {
let mut opts = ClaudeCodeOptions:: builder( )
. permission_mode ( PermissionMode:: AcceptEdits)
. include_partial_messages ( true )
. build ( ) ;
opts. allowed_tools = vec! [ " Read" . into ( ) ] ;
let mut mcp = HashMap:: new( ) ;
mcp. insert ( " filesystem" . into ( ) , cc_sdk:: McpServerConfig:: Stdio{ command: " npx" . into ( ) , args: Some ( vec! [ " -y" . into ( ) , " @modelcontextprotocol/server-filesystem" . into ( ) , " /allowed" . into ( ) ] ) , env: None } ) ;
opts. mcp_servers = mcp;
let transport: Box < dyn Transport + Send > = Box :: new( SubprocessTransport:: new( opts) ? ) ;
let transport = Arc:: new( Mutex:: new( transport) ) ;
let mut q = Query:: new( transport, true , Some ( Arc:: new( AllowRead) ) , None , HashMap:: new( ) ) ;
q. start ( ) . await? ;
# Ok ( ( ) ) }
Control Protocol Compatibility (v0.1.11+)
The SDK supports configurable control protocol formats for CLI compatibility:
Legacy (default): Uses sdk_control_request/ response format - works with all CLI versions
Control : Uses new type = control format - for newer CLI versions
Auto : Currently defaults to Legacy, will auto-negotiate in future
// Use environment variable to override (useful for testing)
// export CLAUDE_CODE_CONTROL_FORMAT=legacy # or "control"
// Or configure programmatically
let options = ClaudeCodeOptions:: builder( )
. control_protocol_format ( ControlProtocolFormat:: Legacy)
. build ( ) ;
See CONTROL_PROTOCOL_COMPATIBILITY.md for detailed information.
API Reference
query ( )
Simple, stateless query function for one-shot interactions.
pub async fn query (
prompt : impl Into < String > ,
options : Option < ClaudeCodeOptions>
) -> Result < impl Stream< Item = Result < Message> > >
InteractiveClient
Main client for stateful, interactive conversations.
Methods
new ( options: ClaudeCodeOptions) -> Result < Self > - Create a new client
connect ( ) -> Result < ( ) > - Connect to Claude CLI
send_and_receive ( prompt: String ) -> Result < Vec < Message> > - Send message and wait for complete response
send_message ( prompt: String ) -> Result < ( ) > - Send message without waiting
receive_response ( ) -> Result < Vec < Message> > - Receive messages until Result message
interrupt ( ) -> Result < ( ) > - Cancel ongoing operation
disconnect ( ) -> Result < ( ) > - Disconnect from Claude CLI
Message Types
UserMessage - User input messages
AssistantMessage - Claude's responses
SystemMessage - System notifications
ResultMessage - Operation results with timing and cost info
Error Handling
The SDK provides comprehensive error types:
CLINotFoundError - Claude Code CLI not installed
CLIConnectionError - Connection failures
ProcessError - CLI process errors
InvalidState - Invalid operation state
Examples
Check the examples/ directory for more usage examples:
interactive_demo.rs - Interactive conversation demo
query_simple.rs - Simple query example
file_operations.rs - File manipulation example
New Features (v0.1.6)
Test the latest features with these examples:
test_settings.rs - Using custom settings files
test_settings_safe.rs - Safe settings file handling with path detection
test_add_dirs.rs - Adding multiple working directories
test_combined_features.rs - Combining settings and add_dirs
test_new_options.rs - Testing the new builder methods
Example settings files are provided:
examples/ claude- settings. json - Basic settings configuration
examples/ custom- claude- settings. json - Advanced settings with MCP servers
Note : When running examples from the project root, use:
cargo run -- example test_settings
The settings files use relative paths from the project root (e.g., examples/ claude- settings. json )
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.