Crate claude_code_agent_sdk

Crate claude_code_agent_sdk 

Source
Expand description

§Claude Agent SDK for Rust

Rust SDK for interacting with Claude Code CLI, enabling programmatic access to Claude’s capabilities with full bidirectional streaming support and 100% feature parity with the official Python SDK.

§Features

  • Simple Query API: One-shot queries with both collecting ([query]) and streaming (query_stream) modes
  • Bidirectional Streaming: Real-time streaming communication with ClaudeClient
  • Dynamic Control: Interrupt, change permissions, switch models mid-execution
  • Hooks System: Intercept and control Claude’s behavior at runtime with 6 hook types
  • Custom Tools: In-process MCP servers with ergonomic tool! macro
  • Plugin System: Load custom plugins to extend Claude’s capabilities
  • Permission Management: Fine-grained control over tool execution
  • Cost Control: Budget limits and fallback models for production reliability
  • Extended Thinking: Configure maximum thinking tokens for complex reasoning
  • Session Management: Resume, fork, and manage conversation sessions
  • Multimodal Input: Send images alongside text using base64 or URLs

§Quick Start

§Simple Query

use claude_agent_sdk_rs::{query, Message, ContentBlock};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // One-shot query that collects all messages
    let messages = query("What is 2 + 2?", None).await?;

    for message in messages {
        if let Message::Assistant(msg) = message {
            for block in &msg.message.content {
                if let ContentBlock::Text(text) = block {
                    println!("Claude: {}", text.text);
                }
            }
        }
    }

    Ok(())
}

§Streaming Query

use claude_agent_sdk_rs::{query_stream, Message, ContentBlock};
use futures::StreamExt;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Streaming query for memory-efficient processing
    let mut stream = query_stream("Explain Rust ownership", None).await?;

    while let Some(result) = stream.next().await {
        let message = result?;
        if let Message::Assistant(msg) = message {
            for block in &msg.message.content {
                if let ContentBlock::Text(text) = block {
                    println!("Claude: {}", text.text);
                }
            }
        }
    }

    Ok(())
}

§Bidirectional Client

use claude_agent_sdk_rs::{ClaudeClient, ClaudeAgentOptions, Message, PermissionMode};
use futures::StreamExt;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let options = ClaudeAgentOptions::builder()
        .permission_mode(PermissionMode::BypassPermissions)
        .max_turns(5)
        .build();

    let mut client = ClaudeClient::new(options);
    client.connect().await?;

    // Send query
    client.query("What is Rust?").await?;

    // Receive responses
    {
        let mut stream = client.receive_response();
        while let Some(result) = stream.next().await {
            match result? {
                Message::Assistant(msg) => {
                    println!("Got assistant message");
                }
                Message::Result(_) => break,
                _ => {}
            }
        }
    } // stream is dropped here

    client.disconnect().await?;
    Ok(())
}

§Multimodal Input (Images)

The SDK supports sending images alongside text in your prompts using structured content blocks. Both base64-encoded images and URL references are supported.

§Supported Formats

  • JPEG (image/jpeg)
  • PNG (image/png)
  • GIF (image/gif)
  • WebP (image/webp)

§Size Limits

  • Maximum base64 data size: 15MB (results in ~20MB decoded)
  • Large images may timeout or fail - resize before encoding

§Example: Query with Image

use claude_agent_sdk_rs::{query_with_content, UserContentBlock, Message, ContentBlock};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // For real usage, load and base64-encode an image file
    // This example uses a pre-encoded 1x1 red PNG pixel
    let base64_data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==";

    // Query with text and image
    let messages = query_with_content(vec![
        UserContentBlock::text("What color is this image?"),
        UserContentBlock::image_base64("image/png", base64_data)?,
    ], None).await?;

    for message in messages {
        if let Message::Assistant(msg) = message {
            for block in &msg.message.content {
                if let ContentBlock::Text(text) = block {
                    println!("Claude: {}", text.text);
                }
            }
        }
    }

    Ok(())
}

§Example: Using Image URLs

use claude_agent_sdk_rs::{query_with_content, UserContentBlock};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let messages = query_with_content(vec![
        UserContentBlock::text("Describe this architecture diagram"),
        UserContentBlock::image_url("https://example.com/diagram.png"),
    ], None).await?;

    Ok(())
}

§Example: Streaming with Images

use claude_agent_sdk_rs::{query_stream_with_content, UserContentBlock, Message, ContentBlock};
use futures::StreamExt;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Minimal 1x1 PNG for example purposes
    let png_base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";

    let mut stream = query_stream_with_content(vec![
        UserContentBlock::image_base64("image/png", png_base64)?,
        UserContentBlock::text("What's in this image?"),
    ], None).await?;

    while let Some(result) = stream.next().await {
        let message = result?;
        if let Message::Assistant(msg) = message {
            for block in &msg.message.content {
                if let ContentBlock::Text(text) = block {
                    print!("{}", text.text);
                }
            }
        }
    }

    Ok(())
}

§Configuration

The SDK provides extensive configuration through ClaudeAgentOptions:

use claude_agent_sdk_rs::{ClaudeAgentOptions, PermissionMode, SdkPluginConfig};

let options = ClaudeAgentOptions::builder()
    .model("claude-opus-4")
    .fallback_model("claude-sonnet-4")
    .max_budget_usd(10.0)
    .max_thinking_tokens(2000)
    .max_turns(10)
    .permission_mode(PermissionMode::Default)
    .plugins(vec![SdkPluginConfig::local("./my-plugin")])
    .build();

§Examples

The SDK includes 22 comprehensive examples covering all features. See the examples directory for detailed usage patterns.

§Documentation

§Tracing Support

This SDK uses the tracing crate for instrumentation. All major operations are automatically traced using #[instrument] attributes, making it easy to monitor and debug your application.

§Basic Usage (Console Logging)

use claude_agent_sdk_rs::query;
use tracing_subscriber;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Initialize tracing subscriber for console output
    tracing_subscriber::fmt::init();

    // Use SDK - traces are automatically logged to console
    let messages = query("What is 2 + 2?", None).await?;

    Ok(())
}

§OpenTelemetry Integration

To export traces to OpenTelemetry-compatible backends (Jaeger, OTel, etc.):

use claude_agent_sdk_rs::query;
use tracing_subscriber::{Registry, prelude::*};
use tracing_opentelemetry::OpenTelemetryLayer;
use opentelemetry_otlp;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Initialize OpenTelemetry with OTLP exporter
    let tracer = opentelemetry_otlp::new_pipeline()
        .tracing()
        .with_exporter(opentelemetry_otlp::new_exporter().tonic())
        .install_simple()?;

    let otel_layer = OpenTelemetryLayer::new(tracer);

    // Combine with fmt layer for console output too
    Registry::default()
        .with(otel_layer)
        .with(tracing_subscriber::fmt::layer())
        .init();

    // Use SDK - traces are exported to OTLP
    let messages = query("What is 2 + 2?", None).await?;

    // Shutdown telemetry
    opentelemetry_sdk::global::shutdown_tracer_provider();
    Ok(())
}

§Available Spans

The SDK creates the following spans for comprehensive tracing:

  • claude.query - Top-level one-shot query operation
  • claude.query_stream - Streaming query operation
  • claude.query_with_content - Query with structured content (images)
  • claude.query_stream_with_content - Streaming query with content
  • claude.client.connect - Client connection establishment
  • claude.client.query - Client query send
  • claude.client.disconnect - Client disconnection
  • claude.transport.connect - Transport layer connection (subprocess spawn)
  • claude.transport.write - Writing to transport stdin
  • claude.query_full.start - Background message reader start
  • claude.query_full.initialize - Query initialization with hooks
  • claude.internal.execute - Internal client execution

Each span includes relevant fields:

  • prompt_length - Length of the user prompt
  • has_options - Whether custom options were provided
  • content_block_count - Number of content blocks (for content queries)
  • session_id - Session identifier (for client queries)
  • model - Model name being used
  • has_can_use_tool - Whether permission callback is set
  • has_hooks - Whether hooks are configured
  • cli_path - Path to Claude CLI executable
  • data_length - Length of data being written

§Environment Variables

Control tracing behavior using standard RUST_LOG environment variable:

# Show all SDK logs
RUST_LOG=claude_agent_sdk_rs=debug cargo run

# Show only errors
RUST_LOG=claude_agent_sdk_rs=error cargo run

# Combine with other crates
RUST_LOG=claude_agent_sdk_rs=info,tokio=warn cargo run

Re-exports§

pub use errors::ClaudeError;
pub use errors::ImageValidationError;
pub use errors::Result;
pub use types::mcp::ACP_TOOL_PREFIX;
pub use types::mcp::McpServerConfig;
pub use types::mcp::McpServers;
pub use types::mcp::SdkMcpServer;
pub use types::mcp::SdkMcpTool;
pub use types::mcp::ToolDefinition;
pub use types::mcp::ToolHandler;
pub use types::mcp::ToolResult;
pub use types::mcp::ToolResultContent as McpToolResultContent;
pub use types::mcp::acp_tool_name;
pub use types::mcp::create_sdk_mcp_server;
pub use types::mcp::is_acp_tool;
pub use types::mcp::strip_acp_prefix;
pub use client::ClaudeClient;
pub use query::query;
pub use query::query_stream;
pub use query::query_stream_with_content;
pub use query::query_with_content;
pub use types::config::*;
pub use types::hooks::*;
pub use types::messages::*;
pub use types::permissions::*;
pub use types::plugin::*;

Modules§

client
ClaudeClient for bidirectional streaming interactions with hook support
errors
Error types for the Claude Agent SDK
query
Simple query function for one-shot interactions
types
Type definitions for the Claude Agent SDK
version
Version information for the Claude Agent SDK

Macros§

tool
Macro to create a tool