claude-code 0.1.1

A Rust library for executing Claude Code CLI
Documentation

claude-code

Crates.io docs.rs CI License: MIT

Unofficial — This library is not affiliated with or endorsed by Anthropic. "Claude" is a trademark of Anthropic.

A Rust library for executing Claude Code CLI (claude --print) as a subprocess and handling results in a type-safe way.

Supports both single-shot JSON responses and real-time streaming via --output-format stream-json.

Installation

Add to your Cargo.toml:

[dependencies]
claude-code = "0.1"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

Prerequisites

The claude CLI must be installed and available in your PATH. See the Claude Code documentation for installation instructions.

Usage

Simple (single-shot)

#[tokio::main]
async fn main() {
    let client = claude_code::ClaudeClient::new(claude_code::ClaudeConfig::default());
    match client.ask("Say hello").await {
        Ok(resp) => println!("{}", resp.result),
        Err(e) => eprintln!("Error: {e}"),
    }
}

Streaming

use claude_code::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = claude_code::ClaudeConfig::builder()
        .max_turns(1)
        .include_partial_messages(true)
        .build();
    let client = claude_code::ClaudeClient::new(config);
    let mut stream = client.ask_stream("Say hello").await?;
    while let Some(event) = stream.next().await {
        match event {
            Ok(claude_code::StreamEvent::Text(text)) => print!("{text}"),
            Ok(claude_code::StreamEvent::Result(resp)) => {
                println!("\nCost: ${:.6}", resp.total_cost_usd);
            }
            Ok(_) => {}
            Err(e) => eprintln!("Error: {e}"),
        }
    }
    Ok(())
}

Multi-turn conversation

Use resume to continue a conversation across multiple turns by passing the session ID from a previous response:

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Turn 1
    let config = claude_code::ClaudeConfig::builder()
        .model("haiku")
        .no_session_persistence(false)
        .max_turns(1)
        .build();
    let client = claude_code::ClaudeClient::new(config);
    let resp1 = client.ask("What is 2+2?").await?;

    // Turn 2: resume with session ID
    let config2 = claude_code::ClaudeConfig::builder()
        .model("haiku")
        .no_session_persistence(false)
        .max_turns(1)
        .resume(&resp1.session_id)
        .build();
    let client2 = claude_code::ClaudeClient::new(config2);
    let resp2 = client2.ask("What was my previous question?").await?;
    println!("{}", resp2.result);

    Ok(())
}

Conversation API

The Conversation API manages session_id automatically across turns:

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = claude_code::ClaudeConfig::builder()
        .model("haiku")
        .no_session_persistence(false) // required for multi-turn
        .max_turns(1)
        .build();
    let client = claude_code::ClaudeClient::new(config);

    let mut conv = client.conversation();
    let r1 = conv.ask("What is 2+2?").await?;
    println!("Turn 1: {}", r1.result);

    let r2 = conv.ask("What was my previous question?").await?;
    println!("Turn 2: {}", r2.result);

    Ok(())
}

Per-turn config overrides are supported via ask_with:

conv.ask_with("complex question", |b| b.max_turns(5).effort("high")).await?;

Structured Output

Use generate_schema and ask_structured to get typed responses:

use schemars::JsonSchema;
use serde::Deserialize;

#[derive(Debug, Deserialize, JsonSchema)]
struct CityInfo {
    name: String,
    country: String,
    population: u64,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let schema = claude_code::generate_schema::<CityInfo>()?;
    let config = claude_code::ClaudeConfig::builder()
        .model("haiku")
        .max_turns(1)
        .json_schema(&schema)
        .build();
    let client = claude_code::ClaudeClient::new(config);

    let city: CityInfo = client.ask_structured("Tell me about Tokyo").await?;
    println!("{}: population {}", city.name, city.population);

    Ok(())
}

Requires the structured feature. Add it to your dependencies:

[dependencies]
claude-code = { version = "0.1", features = ["structured"] }
schemars = "1"

Feature Flags

Feature Default Description
stream Yes Enables ask_stream, StreamEvent, and Conversation stream methods. Adds tokio-stream and async-stream dependencies.
structured No Enables generate_schema helper for JSON Schema generation. Adds schemars dependency.
tracing Yes Enables debug/error/info logging via tracing. Adds tracing dependency.

To use a minimal configuration (only ask()):

[dependencies]
claude-code = { version = "0.1", default-features = false }

Context Minimization Defaults

By default, claude-code applies a minimal configuration to reduce unnecessary context sent to the CLI. This keeps costs down and avoids side effects from user-level settings:

Default CLI Flag Effect
No session persistence --no-session-persistence Sessions are not saved to disk
No settings loaded --setting-sources "" Ignores all user/project settings files
Strict MCP config --strict-mcp-config Only uses explicitly provided MCP servers
Empty MCP config --mcp-config '{"mcpServers":{}}' No MCP servers enabled
No built-in tools --tools "" Disables all built-in tools
No slash commands --disable-slash-commands Disables all skills/slash commands
Empty system prompt --system-prompt "" No default system prompt

All of these can be overridden via ClaudeConfigBuilder. For example, to re-enable session persistence:

let config = claude_code::ClaudeConfig::builder()
    .no_session_persistence(false)
    .build();

Documentation

Compatibility

Tested against Claude Code CLI v2.1.92. Older or newer versions may work but have not been verified.

Not all CLI options have dedicated ClaudeConfigBuilder methods. Options not yet supported can be passed via extra_args:

let config = claude_code::ClaudeConfig::builder()
    .extra_args(vec!["--agent".into(), "reviewer".into()])
    .build();

See docs/claude-cli.md for the full option support status.

Minimum Supported Rust Version

Rust 1.93+ (edition 2024).

License

MIT