Skip to content

Commit 3e4066c

Browse files
committed
init
Signed-off-by: eric-epsilla <[email protected]>
1 parent 462de56 commit 3e4066c

File tree

13 files changed

+1510
-0
lines changed

13 files changed

+1510
-0
lines changed

Cargo.toml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
[package]
2+
name = "claude-code-sdk"
3+
version = "0.0.1"
4+
edition = "2021"
5+
description = "Rust SDK for Claude Code"
6+
readme = "README.md"
7+
license = "MIT"
8+
authors = ["eric <[email protected]>"]
9+
keywords = ["claude", "ai", "sdk", "anthropic"]
10+
categories = ["api-bindings", "development-tools"]
11+
repository = "https://github.com/epsilla-cloud/claude-code-sdk-rust"
12+
homepage = "https://github.com/epsilla-cloud/claude-code-sdk-rust"
13+
documentation = "https://docs.anthropic.com/en/docs/claude-code/sdk"
14+
15+
[dependencies]
16+
tokio = { version = "1.0", features = ["full"] }
17+
tokio-stream = { version = "0.1", features = ["io-util"] }
18+
futures = "0.3"
19+
serde = { version = "1.0", features = ["derive"] }
20+
serde_json = "1.0"
21+
thiserror = "1.0"
22+
which = "6.0"
23+
home = "0.5"
24+
async-trait = "0.1"
25+
26+
[dev-dependencies]
27+
tokio-test = "0.4"
28+
29+
[lib]
30+
name = "claude_code_sdk"
31+
path = "src/lib.rs"
32+
33+
[[example]]
34+
name = "quick_start"
35+
path = "examples/quick_start.rs"

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Epsilla
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Claude Code SDK for Rust
2+
3+
Rust SDK for Claude Code. See the [Claude Code SDK documentation](https://docs.anthropic.com/en/docs/claude-code/sdk) for more information.
4+
5+
## Installation
6+
7+
Add this to your `Cargo.toml`:
8+
9+
```toml
10+
[dependencies]
11+
claude-code-sdk = "0.0.10"
12+
tokio = { version = "1.0", features = ["full"] }
13+
```
14+
15+
**Prerequisites:**
16+
- Rust 1.70+
17+
- Node.js
18+
- Claude Code: `npm install -g @anthropic-ai/claude-code`
19+
20+
## Quick Start
21+
22+
```rust
23+
use claude_code_sdk::query;
24+
use tokio_stream::StreamExt;
25+
26+
#[tokio::main]
27+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
28+
let mut stream = query("What is 2 + 2?", None).await?;
29+
30+
while let Some(message) = stream.next().await {
31+
println!("{:?}", message);
32+
}
33+
34+
Ok(())
35+
}
36+
```
37+
38+
## Usage
39+
40+
### Basic Query
41+
42+
```rust
43+
use claude_code_sdk::{query, ClaudeCodeOptions, Message};
44+
use tokio_stream::StreamExt;
45+
46+
// Simple query
47+
let mut stream = query("Hello Claude", None).await?;
48+
while let Some(message) = stream.next().await {
49+
match message {
50+
Message::Assistant(msg) => {
51+
for block in &msg.content {
52+
if let ContentBlock::Text(text_block) = block {
53+
println!("Claude: {}", text_block.text);
54+
}
55+
}
56+
}
57+
_ => {}
58+
}
59+
}
60+
61+
// With options
62+
let options = ClaudeCodeOptions {
63+
system_prompt: Some("You are a helpful assistant".to_string()),
64+
max_turns: Some(1),
65+
..Default::default()
66+
};
67+
68+
let mut stream = query("Tell me a joke", Some(options)).await?;
69+
while let Some(message) = stream.next().await {
70+
println!("{:?}", message);
71+
}
72+
```
73+
74+
### Using Tools
75+
76+
```rust
77+
let options = ClaudeCodeOptions {
78+
allowed_tools: vec!["Read".to_string(), "Write".to_string()],
79+
permission_mode: Some(PermissionMode::AcceptEdits),
80+
..Default::default()
81+
};
82+
83+
let mut stream = query("Create a hello.rs file", Some(options)).await?;
84+
while let Some(message) = stream.next().await {
85+
// Process tool use and results
86+
}
87+
```
88+
89+
### Working Directory
90+
91+
```rust
92+
use std::path::PathBuf;
93+
94+
let options = ClaudeCodeOptions {
95+
cwd: Some(PathBuf::from("/path/to/project")),
96+
..Default::default()
97+
};
98+
```
99+
100+
## API Reference
101+
102+
### `query(prompt: &str, options: Option<ClaudeCodeOptions>)`
103+
104+
Main async function for querying Claude.
105+
106+
**Parameters:**
107+
- `prompt`: The prompt to send to Claude
108+
- `options`: Optional configuration
109+
110+
**Returns:** `Result<Pin<Box<dyn Stream<Item = Message>>>, ClaudeSDKError>`
111+
112+
### Types
113+
114+
See [src/types.rs](src/types.rs) for complete type definitions:
115+
- `ClaudeCodeOptions` - Configuration options
116+
- `Message` variants - `Assistant`, `User`, `System`, `Result`
117+
- `ContentBlock` variants - `Text`, `ToolUse`, `ToolResult`
118+
119+
## Error Handling
120+
121+
```rust
122+
use claude_code_sdk::{
123+
ClaudeSDKError, // Base error
124+
CLINotFoundError, // Claude Code not installed
125+
CLIConnectionError, // Connection issues
126+
ProcessError, // Process failed
127+
CLIJSONDecodeError, // JSON parsing issues
128+
};
129+
130+
match query("Hello", None).await {
131+
Ok(mut stream) => {
132+
// Process messages
133+
}
134+
Err(ClaudeSDKError::CLINotFound(e)) => {
135+
println!("Please install Claude Code: {}", e);
136+
}
137+
Err(ClaudeSDKError::Process(e)) => {
138+
println!("Process failed with exit code: {:?}", e.exit_code);
139+
}
140+
Err(e) => {
141+
println!("Error: {}", e);
142+
}
143+
}
144+
```
145+
146+
## Available Tools
147+
148+
See the [Claude Code documentation](https://docs.anthropic.com/en/docs/claude-code/security#tools-available-to-claude) for a complete list of available tools.
149+
150+
## Examples
151+
152+
See [examples/quick_start.rs](examples/quick_start.rs) for a complete working example.
153+
154+
## License
155+
156+
MIT

examples/quick_start.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//! Quick start example for Claude Code SDK.
2+
3+
use claude_code_sdk::{
4+
query, AssistantMessage, ClaudeCodeOptions, ContentBlock, Message, PermissionMode,
5+
ResultMessage, TextBlock,
6+
};
7+
use tokio_stream::StreamExt;
8+
9+
/// Basic example - simple question
10+
async fn basic_example() -> Result<(), Box<dyn std::error::Error>> {
11+
println!("=== Basic Example ===");
12+
13+
let mut stream = query("What is 2 + 2?", None).await?;
14+
15+
while let Some(message) = stream.next().await {
16+
if let Message::Assistant(AssistantMessage { content }) = message {
17+
for block in content {
18+
if let ContentBlock::Text(TextBlock { text }) = block {
19+
println!("Claude: {}", text);
20+
}
21+
}
22+
}
23+
}
24+
println!();
25+
Ok(())
26+
}
27+
28+
/// Example with custom options
29+
async fn with_options_example() -> Result<(), Box<dyn std::error::Error>> {
30+
println!("=== With Options Example ===");
31+
32+
let options = ClaudeCodeOptions {
33+
system_prompt: Some("You are a helpful assistant that explains things simply.".to_string()),
34+
max_turns: Some(1),
35+
..Default::default()
36+
};
37+
38+
let mut stream = query("Explain what Rust is in one sentence.", Some(options)).await?;
39+
40+
while let Some(message) = stream.next().await {
41+
if let Message::Assistant(AssistantMessage { content }) = message {
42+
for block in content {
43+
if let ContentBlock::Text(TextBlock { text }) = block {
44+
println!("Claude: {}", text);
45+
}
46+
}
47+
}
48+
}
49+
println!();
50+
Ok(())
51+
}
52+
53+
/// Example using tools
54+
async fn with_tools_example() -> Result<(), Box<dyn std::error::Error>> {
55+
println!("=== With Tools Example ===");
56+
57+
let options = ClaudeCodeOptions {
58+
allowed_tools: vec!["Read".to_string(), "Write".to_string()],
59+
system_prompt: Some("You are a helpful file assistant.".to_string()),
60+
permission_mode: Some(PermissionMode::AcceptEdits),
61+
..Default::default()
62+
};
63+
64+
let mut stream = query(
65+
"Create a file called hello.txt with 'Hello, World!' in it",
66+
Some(options),
67+
)
68+
.await?;
69+
70+
while let Some(message) = stream.next().await {
71+
match message {
72+
Message::Assistant(AssistantMessage { content }) => {
73+
for block in content {
74+
if let ContentBlock::Text(TextBlock { text }) = block {
75+
println!("Claude: {}", text);
76+
}
77+
}
78+
}
79+
Message::Result(ResultMessage {
80+
total_cost_usd: Some(cost),
81+
..
82+
}) if cost > 0.0 => {
83+
println!("\nCost: ${:.4}", cost);
84+
}
85+
_ => {}
86+
}
87+
}
88+
println!();
89+
Ok(())
90+
}
91+
92+
/// Run all examples
93+
#[tokio::main]
94+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
95+
basic_example().await?;
96+
with_options_example().await?;
97+
with_tools_example().await?;
98+
Ok(())
99+
}

0 commit comments

Comments
 (0)