scaffold the crate

Initial layout for an async Rust port of the Python claude-agent-sdk. Sets
up Cargo.toml on 2024 edition, MIT LICENSE matching the upstream Python SDK's
text with the Sulkta Coop copyright appended, a workspace .gitignore, and a
README laying out the v0.1 scope and the Python -> Rust mapping table.

No source modules yet — those land in the following commits.
This commit is contained in:
Kayos 2026-05-14 08:03:11 -07:00
commit 6af8273f98
4 changed files with 206 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

39
Cargo.toml Normal file
View file

@ -0,0 +1,39 @@
[package]
name = "claude-agent-sdk"
version = "0.0.1"
edition = "2024"
license = "MIT"
description = "Async Rust SDK for the Claude Agent CLI (subprocess-based, mirrors the Python claude-agent-sdk)."
repository = "https://gitea.sulkta.com/Sulkta-Coop/claude-agent-sdk-rust"
readme = "README.md"
keywords = ["claude", "anthropic", "agent", "sdk", "async"]
categories = ["api-bindings", "asynchronous"]
rust-version = "1.85"
[dependencies]
tokio = { version = "1", features = ["full"] }
tokio-stream = "0.1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
thiserror = "2"
tracing = "0.1"
futures-core = "0.3"
async-stream = "0.3"
[dev-dependencies]
anyhow = "1"
tokio = { version = "1", features = ["macros", "rt-multi-thread", "test-util"] }
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
futures-util = "0.3"
[[example]]
name = "basic"
path = "examples/basic.rs"
[[example]]
name = "with_options"
path = "examples/with_options.rs"
[[example]]
name = "interactive"
path = "examples/interactive.rs"

22
LICENSE Normal file
View file

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2025 Anthropic, PBC
Copyright (c) 2026 Sulkta Cooperative
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

144
README.md Normal file
View file

@ -0,0 +1,144 @@
# 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.