Rust port of anthropics/claude-agent-sdk-python.
Find a file
Cobb Hayes 2aa3cd07b7 Public-flip audit: URL refresh + minor scrubs
Repository URLs, version strings, and example creds normalized for the
public git.sulkta.com endpoint. No code-behavior change.

Audit-applied by the public-flip rolling-audit pass — see
kayos/openclaw-workspace memory/2026-05-27 logs for the campaign
context.
2026-05-27 10:59:57 -07:00
examples add examples, end-to-end tests, and Cargo.lock 2026-05-14 08:04:04 -07:00
src fix rustdoc warnings on transport links 2026-05-14 08:06:10 -07:00
tests add examples, end-to-end tests, and Cargo.lock 2026-05-14 08:04:04 -07:00
.gitignore scaffold the crate 2026-05-14 08:03:11 -07:00
Cargo.lock add examples, end-to-end tests, and Cargo.lock 2026-05-14 08:04:04 -07:00
Cargo.toml Public-flip audit: URL refresh + minor scrubs 2026-05-27 10:59:57 -07:00
LICENSE Public-flip audit: URL refresh + minor scrubs 2026-05-27 10:59:57 -07:00
README.md Public-flip audit: URL refresh + minor scrubs 2026-05-27 10:59:57 -07:00

claude-agent-sdk (Rust)

Async Rust SDK for the Claude Agent CLI — a faithful port of the official Python claude-agent-sdk.

This crate wraps the claude CLI as a subprocess and exposes its newline-delimited JSON stream as ergonomic Rust types. The Python SDK's two entry points map directly:

  • query() for fire-and-forget one-shot prompts.
  • ClaudeSDKClientclaude_agent_sdk::Client for bidirectional multi-turn sessions.

Status

v0.0.1 — initial port. Core feature parity for the subprocess wire protocol; advanced features (control protocol, hooks, in-process MCP servers, session_store, sandbox, plugins, agents) are deferred to v0.2. See v0.1 scope below.

Install

[dependencies]
claude-agent-sdk = { git = "https://git.sulkta.com/Sulkta-Coop/claude-agent-sdk-rust" }
tokio = { version = "1", features = ["full"] }
tokio-stream = "0.1"

Prerequisites: the claude CLI on PATH (or supply ClaudeAgentOptions::with_cli_path()), and an authenticated Claude session. The SDK does not bundle the CLI binary.

Quick start

use claude_agent_sdk::{query, ClaudeAgentOptions, Message, ContentBlock};
use tokio_stream::StreamExt;

#[tokio::main]
async fn main() -> claude_agent_sdk::Result<()> {
    let opts = ClaudeAgentOptions::new()
        .with_system_prompt("You are a helpful assistant.")
        .with_max_turns(1);

    let mut stream = query("What is 2 + 2?", opts).await?;

    while let Some(msg) = stream.next().await {
        match msg? {
            Message::Assistant(a) => {
                for block in a.message.content {
                    if let ContentBlock::Text(t) = block {
                        println!("Claude: {}", t.text);
                    }
                }
            }
            Message::Result(r) => {
                if let Some(usd) = r.total_cost_usd {
                    println!("Cost: ${:.4}", usd);
                }
                break;
            }
            _ => {}
        }
    }
    Ok(())
}

Multi-turn sessions

use claude_agent_sdk::{Client, ClaudeAgentOptions, Message, ContentBlock};
use tokio_stream::StreamExt;

#[tokio::main]
async fn main() -> claude_agent_sdk::Result<()> {
    let mut client = Client::new(ClaudeAgentOptions::new()).await?;
    client.connect().await?;
    let mut messages = client.messages();

    client.send("What's the capital of France?").await?;
    // ...consume messages until a Result frame, then ask a follow-up...
    client.send("And of Germany?").await?;

    // Drain until next Result, then disconnect.
    while let Some(msg) = messages.next().await {
        if let Message::Result(_) = msg? {
            break;
        }
    }
    client.disconnect().await?;
    Ok(())
}

See the examples/ directory for runnable variants.

Mapping the Python SDK

Python Rust
query(prompt=...) query(prompt, opts).await?
ClaudeSDKClient Client
ClaudeAgentOptions ClaudeAgentOptions
AssistantMessage Message::Assistant(_)
UserMessage Message::User(_)
SystemMessage Message::System(_)
ResultMessage Message::Result(_)
TextBlock / ToolUseBlock ContentBlock::Text/ToolUse(_)
CLINotFoundError Error::CliNotFound
CLIConnectionError Error::CliConnection
ProcessError Error::Process { .. }
CLIJSONDecodeError Error::JsonDecode { .. }
MessageParseError Error::MessageParse { .. }

v0.1 scope and known limitations

The v0.1 port covers the core path. The following are deferred:

  • Control protocolinterrupt(), set_permission_mode(), set_model(), get_mcp_status(), etc. The Python SDK sends a JSON-RPC initialize request before the first user message and handles control requests/responses over the same stdio pair. The Rust Client currently speaks only the bare user / assistant / result frames. Adding the control protocol unlocks the rest of the API.
  • can_use_tool permission callback — requires the control protocol.
  • In-process MCP servers (@tool / create_sdk_mcp_server) — the Python decorator wraps a mcp.server.Server instance. The Rust shape for this (likely a derive macro on a Tool trait + a runtime that multiplexes over the control protocol) is not yet drafted.
  • HookMatcher — wire format is supported on the CLI side but the Rust callback surface is not designed.
  • SessionStore mirroring adapter.
  • Sandbox settings, plugins, agents dataclass.

Each of these degrades gracefully — a v0.1 caller using a newer CLI sees fewer features, not breakage.

License

MIT. See LICENSE.

This is an independent port; the upstream Python SDK is © Anthropic, PBC.