Runnable demos for the Rusty Claw SDK. Start with simple_query and work your way up.
Before running any example, make sure you have:
-
Claude Code CLI v2.0.0+ — the SDK spawns this as a subprocess
claude --version # should print 2.x.x or higherIf this fails, install the CLI first.
-
Anthropic API key — the CLI needs this to talk to Claude
export ANTHROPIC_API_KEY=sk-ant-... -
Verify the CLI works on its own before trying the SDK:
claude -p 'say hello in one word'If this doesn't produce a response, fix the CLI setup first — the SDK won't work either.
All examples run from the repository root:
cargo run -p examples --example simple_queryYou can pass a custom prompt as an argument to any example:
cargo run -p examples --example simple_query -- "what is 2+2?"If something goes wrong and the example exits silently, enable debug logging to see what the CLI wrote to stderr:
RUST_LOG=debug cargo run -p examples --example simple_queryEach example connects to the Claude CLI, sends a prompt, and prints streamed responses to stdout. They're non-interactive — just run and watch.
Start here. This is the minimal "hello world" for the SDK.
cargo run -p examples --example simple_query
cargo run -p examples --example simple_query -- "explain Rust lifetimes in one sentence"What it does: Sends a prompt to Claude using the query() function and prints each streamed message as it arrives.
What you'll see:
Prompt: "List the files in the current directory"
Connecting to Claude CLI...
Connected. Streaming response:
[session: sess_abc123...]
I'll list the files in the current directory.
[tool: Bash]
Here are the files:
- Cargo.toml
- README.md
- src/
...
---
Duration: 2340ms
Cost: $0.0031
What to read in the code:
ClaudeAgentOptions::builder()— how to configure max turns, permission mode, model- The
while let Some(result) = stream.next().awaitloop — how to pattern-match onMessagevariants (System,Assistant,Result) ContentBlockmatching — how text, tool calls, tool results, and thinking tokens each arrive as separate blocks
Next step. Shows the persistent session API for when you need more than a single prompt.
cargo run -p examples --example interactive_client
cargo run -p examples --example interactive_client -- "what Rust edition are we using?"What it does: Creates a ClaudeClient, connects to the CLI subprocess, sends a prompt, streams the response, then closes the session gracefully.
What you'll see:
Creating client...
Connecting to Claude CLI...
Connected.
Sending: "What is the current working directory?"
Streaming response:
I'll check the current working directory for you.
[calling tool: Bash with {"command":"pwd"}]
The current working directory is /path/to/rusty_claw
--- Done: Identified the current working directory
Session closed.
What to read in the code:
ClaudeClient::new(options)+connect()— how to set up a persistent sessionclient.send_message(...)— sends a user message and returns aResponseStreamclient.close()— graceful shutdown (closes stdin, waits for the CLI to exit)- The difference from
simple_query:ClaudeClientkeeps the CLI process alive between messages, so you could send follow-up prompts in a real app
Advanced. Shows how to expose your own Rust functions as tools that Claude can call.
cargo run -p examples --example custom_toolWhat it does: Defines two tools using the #[claw_tool] macro (word_count and repeat), registers them with an MCP server, then asks Claude to use them.
What you'll see:
Registering custom tools...
- word_count(text: String)
- repeat(message: String, times: Option<i32>)
Connecting to Claude CLI...
Connected.
Sending: "Use the word_count tool on 'hello world foo bar'..."
Streaming response:
[calling tool: word_count]
The word count for "hello world foo bar" is 4 words.
[calling tool: repeat]
hi
hi
hi
Done.
What to read in the code:
#[claw_tool(name = "...", description = "...")]— the macro generates a handler struct and a builder function from a plainasync fnOption<i32>parameters — become optional in the generated JSON Schema (not listed in"required")SdkMcpServerImpl+SdkMcpServerRegistry— how to build the server and register itclient.register_mcp_message_handler(Arc::new(registry))— wires the server into the client so incoming MCP calls get routed to your Rust functions
After the three core examples above, explore these based on what you need:
| Example | What you'll learn |
|---|---|
system_prompts |
Custom, preset, and appended system prompts |
agent_environment |
Working directory, env vars, CLI path |
advanced_config |
Settings sources, output format, beta features |
partial_messages |
Stream incremental content blocks for real-time UX |
| Example | What you'll learn |
|---|---|
tool_permissions |
Static allow/deny lists, DefaultPermissionHandler, custom CanUseToolHandler |
hook_callbacks |
HookCallback trait, HookInput, HookContext, HookResponse builders |
hooks_guardrails |
HookHandler for validation, logging, and rate limiting |
| Example | What you'll learn |
|---|---|
advanced_tools |
Vec<T>, bool params, doc comments, name inference in #[claw_tool] |
image_tool_results |
ToolContent::text(), ToolContent::image(), multi-content results |
external_mcp |
External MCP server config (documents intended API — McpServerConfig is a stub) |
| Example | What you'll learn |
|---|---|
session_resume |
Resume, fork, and name sessions |
file_checkpointing |
File snapshots, rewind_files() |
interrupt_and_status |
interrupt(), mcp_status() |
| Example | What you'll learn |
|---|---|
transport_layer |
CliDiscovery, SubprocessCLITransport, Transport trait |
rate_limit_handling |
Message::RateLimitEvent, ClawError variant matching |
subagent_usage |
AgentDefinition, subagent hooks |
These examples only inspect types and configuration — they don't connect to Claude:
image_tool_results— builds and serializesToolContentandToolResulthook_callbacks— testsHookCallbackimplementations locallytool_permissions— testsDefaultPermissionHandlerdecisions locallytransport_layer— discovers the CLI binary (no connection)
The CLI started but exited without producing any JSON output. This usually means it wrote an error to stderr and quit. Run with logging to see what happened:
RUST_LOG=debug cargo run -p examples --example simple_queryCommon causes:
ANTHROPIC_API_KEYnot set or invalid- CLI not authenticated (
claude auth login) - Network issues reaching api.anthropic.com
- CLI version too old for
--output-format=stream-json
ClawError::CliNotFound — The SDK can't find claude on your PATH. Make sure claude --version works.
ClawError::InvalidCliVersion — Your CLI is too old. Update to v2.0.0+.
cargo run can't find the example — Run from the repo root with -p examples:
# correct (from repo root)
cargo run -p examples --example simple_query
# wrong (from examples/ directory)
cargo run --example simple_query