docs: public README + generic CI workflow

This commit is contained in:
Sulkta 2026-06-28 13:12:32 -07:00
parent 5b8ff3c5f1
commit d32db8800e
2 changed files with 131 additions and 27 deletions

29
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,29 @@
name: ci
on:
push:
branches: [main]
pull_request:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: install rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: fmt
run: cargo fmt --all --check
- name: clippy
run: cargo clippy --all-targets -- -D warnings
- name: build
run: cargo build --all-targets
- name: test
run: cargo test

129
README.md
View file

@ -4,22 +4,35 @@ 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). Python [`claude-agent-sdk`](https://github.com/anthropics/claude-agent-sdk-python).
This crate wraps the `claude` CLI as a subprocess and exposes its This crate wraps the `claude` CLI as a subprocess and exposes its
newline-delimited JSON stream as ergonomic Rust types. The Python SDK's newline-delimited JSON stream as ergonomic, strongly-typed Rust values. The
two entry points map directly: Python SDK's two entry points map directly:
- `query()` for fire-and-forget one-shot prompts. - `query()` for fire-and-forget one-shot prompts.
- `ClaudeSDKClient``claude_agent_sdk::Client` for bidirectional - `ClaudeSDKClient``claude_agent_sdk::Client` for bidirectional,
multi-turn sessions. multi-turn sessions.
It is an independent, community-maintained port and is not affiliated with or
endorsed by Anthropic.
## Status ## Status
**v0.0.1** — initial port. Core feature parity for the subprocess wire **v0.0.1** — initial port. Core feature parity for the subprocess wire
protocol; advanced features (control protocol, hooks, in-process MCP servers, protocol; advanced features (control protocol, hooks, in-process MCP servers,
session_store, sandbox, plugins, agents) are deferred to v0.2. See session store, sandbox, plugins, agents) are deferred. See
[v0.1 scope](#v01-scope-and-known-limitations) below. [scope and known limitations](#scope-and-known-limitations) below.
## Requirements
- Rust 1.85 or newer (the crate uses the 2024 edition).
- The `claude` CLI available on `PATH` (or supplied explicitly via
`ClaudeAgentOptions::with_cli_path()`), and an authenticated Claude
session. **The SDK does not bundle the CLI binary** — it shells out to
whatever `claude` it finds.
## Install ## Install
The crate is distributed as a git dependency:
```toml ```toml
[dependencies] [dependencies]
claude-agent-sdk = { git = "https://git.sulkta.com/Sulkta-OSS/claude-agent-sdk-rust" } claude-agent-sdk = { git = "https://git.sulkta.com/Sulkta-OSS/claude-agent-sdk-rust" }
@ -27,9 +40,8 @@ tokio = { version = "1", features = ["full"] }
tokio-stream = "0.1" tokio-stream = "0.1"
``` ```
Prerequisites: the `claude` CLI on `PATH` (or supply Pin to a tag or commit (`rev = "..."` / `tag = "..."`) for reproducible
`ClaudeAgentOptions::with_cli_path()`), and an authenticated Claude builds.
session. The SDK does not bundle the CLI binary.
## Quick start ## Quick start
@ -67,6 +79,9 @@ async fn main() -> claude_agent_sdk::Result<()> {
} }
``` ```
`query()` returns a stream that ends when the CLI emits its terminal `result`
message, automatically tearing down the subprocess.
## Multi-turn sessions ## Multi-turn sessions
```rust ```rust
@ -83,7 +98,7 @@ async fn main() -> claude_agent_sdk::Result<()> {
// ...consume messages until a Result frame, then ask a follow-up... // ...consume messages until a Result frame, then ask a follow-up...
client.send("And of Germany?").await?; client.send("And of Germany?").await?;
// Drain until next Result, then disconnect. // Drain until the next Result, then disconnect.
while let Some(msg) = messages.next().await { while let Some(msg) = messages.next().await {
if let Message::Result(_) = msg? { if let Message::Result(_) = msg? {
break; break;
@ -94,7 +109,49 @@ async fn main() -> claude_agent_sdk::Result<()> {
} }
``` ```
See the `examples/` directory for runnable variants. `Client` keeps a single CLI subprocess alive across turns, so follow-up
prompts don't pay the cold-start cost again.
## Configuration
Both entry points are configured with `ClaudeAgentOptions`, a builder you
chain `.with_*()` methods on:
```rust
use claude_agent_sdk::{ClaudeAgentOptions, PermissionMode};
let opts = ClaudeAgentOptions::new()
.with_model("claude-sonnet-4-5")
.with_permission_mode(PermissionMode::AcceptEdits)
.with_allowed_tool("Read")
.with_allowed_tool("Bash")
.with_cwd("/tmp/my-project")
.with_max_turns(5);
```
See the `ClaudeAgentOptions` API docs for the full list of supported fields.
## Examples
Runnable examples live in [`examples/`](examples/). With the `claude` CLI on
`PATH` and authenticated:
```sh
cargo run --example basic # minimal one-shot query()
cargo run --example with_options # query() with a configured options builder
cargo run --example interactive # multi-turn Client session
```
## Building and testing
```sh
cargo build
cargo test # unit + end-to-end tests. A fake CLI fixture stands in
# for the real `claude` binary, so the suite needs no
# network access or authenticated session to run.
cargo clippy --all-targets
cargo fmt --check
```
## Mapping the Python SDK ## Mapping the Python SDK
@ -114,31 +171,49 @@ See the `examples/` directory for runnable variants.
| `CLIJSONDecodeError` | `Error::JsonDecode { .. }` | | `CLIJSONDecodeError` | `Error::JsonDecode { .. }` |
| `MessageParseError` | `Error::MessageParse { .. }` | | `MessageParseError` | `Error::MessageParse { .. }` |
## v0.1 scope and known limitations ## Scope and known limitations
The v0.1 port covers the core path. The following are deferred: This release covers the core path of the Python SDK:
- **Control protocol**`interrupt()`, `set_permission_mode()`, - Subprocess transport with newline-delimited JSON framing.
`set_model()`, `get_mcp_status()`, etc. The Python SDK sends a JSON-RPC - All message and content-block types parsed faithfully.
`initialize` request before the first user message and handles control - `query()` + `Client` for one-shot and bidirectional use.
requests/responses over the same stdio pair. The Rust `Client` currently - The `ClaudeAgentOptions` flag surface relevant to subprocess arguments.
speaks only the bare user / assistant / result frames. Adding the
control protocol unlocks the rest of the API. The following are deferred — see the upstream Python README for the current
shape of these features:
- **Control protocol over JSON-RPC**`interrupt()`, `set_permission_mode()`,
`set_model()`, `get_mcp_status()`, etc. 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. - **`can_use_tool` permission callback** — requires the control protocol.
- **In-process MCP servers (`@tool` / `create_sdk_mcp_server`)** — the - **In-process MCP servers (`@tool` / `create_sdk_mcp_server`)** — needs a
Python decorator wraps a `mcp.server.Server` instance. The Rust shape Rust trait/derive-macro shape that isn't drafted yet.
for this (likely a derive macro on a `Tool` trait + a runtime that - **`HookMatcher`** — the wire format is supported on the CLI side, but the
multiplexes over the control protocol) is not yet drafted. Rust callback surface is not designed.
- **`HookMatcher`** — wire format is supported on the CLI side but the Rust
callback surface is not designed.
- **`SessionStore`** mirroring adapter. - **`SessionStore`** mirroring adapter.
- **`Sandbox` settings**, **plugins**, **agents** dataclass. - **`Sandbox` settings**, **plugins**, **agents** dataclass.
Each of these degrades gracefully — a v0.1 caller using a newer CLI sees Each of these degrades gracefully — a caller using a newer CLI sees fewer
fewer features, not breakage. features, not breakage.
## Contributing
Contributions are welcome. A good change:
- keeps the wire protocol faithful to the upstream Python SDK (cite the
behavior you're matching where it isn't obvious);
- comes with a test — the end-to-end suite drives a fake CLI over the real
framing, so most behavior can be covered without a live `claude` binary;
- passes `cargo fmt --check`, `cargo clippy --all-targets`, and `cargo test`.
Open an issue to discuss larger features (especially anything from the
deferred list above) before sending a big patch.
## License ## License
MIT. See [`LICENSE`](LICENSE). MIT. See [`LICENSE`](LICENSE).
This is an independent port; the upstream Python SDK is © Anthropic, PBC. This is an independent port; the upstream Python SDK is © Anthropic, PBC, and
the bundled `LICENSE` preserves that notice alongside this port's copyright.