claude_code_sdk/lib.rs
1//! Claude SDK for Rust
2//!
3//! Rust SDK for interacting with Claude Code.
4//!
5//! This SDK provides structured logging through the `tracing` crate.
6//! To enable logging, initialize a tracing subscriber before using the SDK:
7//!
8//! ```rust,no_run
9//! use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
10//!
11//! tracing_subscriber::registry()
12//! .with(tracing_subscriber::EnvFilter::new("claude_code_sdk=debug"))
13//! .with(tracing_subscriber::fmt::layer())
14//! .init();
15//! ```
16
17use std::pin::Pin;
18use futures::Stream;
19use tracing::{debug, info, instrument};
20
21pub mod types;
22pub mod errors;
23pub mod config;
24mod client;
25pub mod transport;
26
27pub use types::*;
28pub use errors::*;
29pub use config::*;
30
31use client::InternalClient;
32
33/// Query Claude Code.
34///
35/// Rust SDK for interacting with Claude Code.
36///
37/// # Arguments
38///
39/// * `prompt` - The prompt to send to Claude
40/// * `options` - Optional configuration (defaults to ClaudeCodeOptions::default() if None).
41/// Set options.permission_mode to control tool execution:
42/// - `Default`: CLI prompts for dangerous tools
43/// - `AcceptEdits`: Auto-accept file edits
44/// - `BypassPermissions`: Allow all tools (use with caution)
45/// Set options.cwd for working directory.
46///
47/// # Returns
48///
49/// A stream of messages from the conversation
50///
51/// # Example
52///
53/// ```rust,no_run
54/// use claude_code_sdk::{query, ClaudeCodeOptions};
55/// use tokio_stream::StreamExt;
56///
57/// #[tokio::main]
58/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
59/// // Simple usage
60/// let mut stream = query("Hello", None).await?;
61/// while let Some(message) = stream.next().await {
62/// println!("{:?}", message);
63/// }
64///
65/// // With options
66/// let options = ClaudeCodeOptions {
67/// system_prompt: Some("You are helpful".to_string()),
68/// cwd: Some("/home/user".into()),
69/// ..Default::default()
70/// };
71///
72/// let mut stream = query("Hello", Some(options)).await?;
73/// while let Some(message) = stream.next().await {
74/// println!("{:?}", message);
75/// }
76///
77/// Ok(())
78/// }
79/// ```
80#[instrument(
81 level = "info",
82 skip(options),
83 fields(
84 prompt_length = prompt.len(),
85 has_options = options.is_some(),
86 system_prompt = options.as_ref().and_then(|o| o.system_prompt.as_deref()),
87 allowed_tools = options.as_ref().map(|o| o.allowed_tools.len()),
88 permission_mode = ?options.as_ref().and_then(|o| o.permission_mode.as_ref()),
89 cwd = ?options.as_ref().and_then(|o| o.cwd.as_ref()),
90 )
91)]
92pub async fn query(
93 prompt: &str,
94 options: Option<ClaudeCodeOptions>,
95) -> Result<Pin<Box<dyn Stream<Item = Message> + Send>>, ClaudeSDKError> {
96 info!("Starting Claude Code query");
97
98 let options = options.unwrap_or_default();
99 debug!(?options, "Using query options");
100
101 // Set environment variable
102 std::env::set_var("CLAUDE_CODE_ENTRYPOINT", "sdk-rust");
103 debug!("Set CLAUDE_CODE_ENTRYPOINT environment variable");
104
105 let client = InternalClient::new();
106 info!("Created internal client");
107
108 let stream = client.process_query(prompt, options).await?;
109 info!("Successfully created message stream");
110
111 Ok(Box::pin(stream))
112}
113
114/// Initialize default tracing subscriber for development and testing.
115///
116/// This is a convenience function that sets up a basic tracing subscriber
117/// with environment filter support. For production use, you may want to
118/// configure logging more specifically.
119///
120/// # Example
121///
122/// ```rust,no_run
123/// claude_code_sdk::init_tracing();
124/// ```
125pub fn init_tracing() {
126 use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
127
128 let env_filter = tracing_subscriber::EnvFilter::try_from_default_env()
129 .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("claude_code_sdk=info"));
130
131 tracing_subscriber::registry()
132 .with(env_filter)
133 .with(tracing_subscriber::fmt::layer().with_target(true))
134 .init();
135}