# claude-agent-sdk (Rust) Async Rust SDK for the Claude Agent CLI — a faithful port of the official Python [`claude-agent-sdk`](https://github.com/anthropics/claude-agent-sdk-python). 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. - `ClaudeSDKClient` → `claude_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](#v01-scope-and-known-limitations) below. ## Install ```toml [dependencies] claude-agent-sdk = { git = "https://gitea.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 ```rust 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 ```rust 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 protocol** — `interrupt()`, `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`](LICENSE). This is an independent port; the upstream Python SDK is © Anthropic, PBC.