Expand description
A type-safe Claude Code CLI wrapper for Rust.
claude-wrapper provides a builder-pattern interface for invoking the
claude CLI programmatically. Each subcommand is a typed builder that
produces typed output. The design follows the same shape as
docker-wrapper and
terraform-wrapper.
§Feature flags
| Feature | Default | Purpose |
|---|---|---|
async | yes | tokio-backed async API. Disabling drops tokio from the runtime dep tree. |
json | yes | JSON output parsing (QueryCommand::execute_json, streaming::StreamEvent, session::Session, streaming::stream_query). |
tempfile | yes | TempMcpConfig for one-shot MCP config files. |
sync | no | Blocking API: *_sync methods on exec, retry, every command builder, and Claude. |
Sync-only (tokio-free) build:
claude-wrapper = { version = "0.6", default-features = false, features = ["json", "sync"] }§Quick start (async)
use claude_wrapper::{Claude, ClaudeCommand, QueryCommand};
let claude = Claude::builder().build()?;
let output = QueryCommand::new("explain this error: file not found")
.model("sonnet")
.execute(&claude)
.await?;
println!("{}", output.stdout);§Quick start (sync)
Enable the sync feature and bring ClaudeCommandSyncExt into scope:
use claude_wrapper::{Claude, ClaudeCommandSyncExt, QueryCommand};
let claude = Claude::builder().build()?;
let output = QueryCommand::new("explain this error")
.execute_sync(&claude)?;
println!("{}", output.stdout);§Two-layer builder
The Claude client holds shared config (binary path, env, timeout,
default retry policy). Command builders hold per-invocation options
and call execute(&claude) (or execute_sync).
use claude_wrapper::{Claude, ClaudeCommand, Effort, PermissionMode, QueryCommand};
let claude = Claude::builder()
.env("AWS_REGION", "us-west-2")
.timeout_secs(300)
.build()?;
let output = QueryCommand::new("review src/main.rs")
.model("opus")
.system_prompt("You are a senior Rust developer")
.permission_mode(PermissionMode::Plan)
.effort(Effort::High)
.max_turns(5)
.no_session_persistence()
.execute(&claude)
.await?;§JSON output
use claude_wrapper::{Claude, QueryCommand};
let claude = Claude::builder().build()?;
let result = QueryCommand::new("what is 2+2?")
.execute_json(&claude)
.await?;
println!("answer: {}", result.result);
println!("cost: ${:.4}", result.cost_usd.unwrap_or(0.0));§Session management
For multi-turn conversations use session::Session. It threads the
CLI session_id across turns, tracks cumulative cost + history, and
supports streaming. See the session module docs for the
full API.
use std::sync::Arc;
use claude_wrapper::Claude;
use claude_wrapper::session::Session;
let claude = Arc::new(Claude::builder().build()?);
let mut session = Session::new(claude);
let _first = session.send("what's 2 + 2?").await?;
let _second = session.send("and squared?").await?;
println!("cost: ${:.4}", session.total_cost_usd());§Budget tracking
Attach a BudgetTracker to a session (or share one across several
sessions) to enforce a cumulative USD ceiling. Callbacks fire
exactly once when thresholds are crossed; pre-turn checks
short-circuit with Error::BudgetExceeded
once the ceiling is hit.
use std::sync::Arc;
use claude_wrapper::{BudgetTracker, Claude};
use claude_wrapper::session::Session;
let budget = BudgetTracker::builder()
.max_usd(5.00)
.warn_at_usd(4.00)
.on_warning(|t| eprintln!("warning: ${t:.2}"))
.on_exceeded(|t| eprintln!("budget hit: ${t:.2}"))
.build();
let claude = Arc::new(Claude::builder().build()?);
let mut session = Session::new(claude).with_budget(budget.clone());
session.send("hello").await?;
println!("spent: ${:.4}", budget.total_usd());§Tool permissions
Use ToolPattern for typed --allowed-tools / --disallowed-tools
entries. Typed constructors always produce valid patterns; loose
From<&str> keeps bare strings working for back-compat.
use claude_wrapper::{QueryCommand, ToolPattern};
let cmd = QueryCommand::new("review")
.allowed_tool(ToolPattern::tool("Read"))
.allowed_tool(ToolPattern::tool_with_args("Bash", "git log:*"))
.allowed_tool(ToolPattern::all("Write"))
.allowed_tool(ToolPattern::mcp("my-server", "*"))
.disallowed_tool(ToolPattern::tool_with_args("Bash", "rm*"));§Streaming
Process NDJSON events in real time with streaming::stream_query
(async) or streaming::stream_query_sync (blocking; non-Send
handler supported).
use claude_wrapper::{Claude, OutputFormat, QueryCommand};
use claude_wrapper::streaming::{StreamEvent, stream_query};
let claude = Claude::builder().build()?;
let cmd = QueryCommand::new("explain quicksort")
.output_format(OutputFormat::StreamJson);
stream_query(&claude, &cmd, |event: StreamEvent| {
if event.is_result() {
println!("result: {}", event.result_text().unwrap_or(""));
}
}).await?;§MCP config generation
Generate .mcp.json files for --mcp-config:
use claude_wrapper::{Claude, ClaudeCommand, McpConfigBuilder, QueryCommand};
McpConfigBuilder::new()
.http_server("hub", "http://127.0.0.1:9090")
.stdio_server("tool", "npx", ["my-server"])
.write_to("/tmp/my-project/.mcp.json")?;
let claude = Claude::builder().build()?;
QueryCommand::new("list tools")
.mcp_config("/tmp/my-project/.mcp.json")
.execute(&claude)
.await?;§Dangerous: bypass mode
--permission-mode bypassPermissions is isolated behind
dangerous::DangerousClient, which requires an env-var
acknowledgement (dangerous::ALLOW_ENV = "1") at process start.
See the dangerous module docs for details.
§Escape hatch
For subcommands not yet wrapped, use RawCommand:
use claude_wrapper::{Claude, ClaudeCommand, RawCommand};
let claude = Claude::builder().build()?;
let output = RawCommand::new("some-future-command")
.arg("--new-flag")
.arg("value")
.execute(&claude)
.await?;Re-exports§
pub use budget::BudgetBuilder;pub use budget::BudgetTracker;pub use command::ClaudeCommand;pub use command::ClaudeCommandSyncExt;pub use command::agents::AgentsCommand;pub use command::auth::AuthLoginCommand;pub use command::auth::AuthLogoutCommand;pub use command::auth::AuthStatusCommand;pub use command::auth::SetupTokenCommand;pub use command::auto_mode::AutoModeConfigCommand;pub use command::auto_mode::AutoModeCritiqueCommand;pub use command::auto_mode::AutoModeDefaultsCommand;pub use command::doctor::DoctorCommand;pub use command::install::InstallCommand;pub use command::marketplace::MarketplaceAddCommand;pub use command::marketplace::MarketplaceListCommand;pub use command::marketplace::MarketplaceRemoveCommand;pub use command::marketplace::MarketplaceUpdateCommand;pub use command::mcp::McpAddCommand;pub use command::mcp::McpAddFromDesktopCommand;pub use command::mcp::McpAddJsonCommand;pub use command::mcp::McpGetCommand;pub use command::mcp::McpListCommand;pub use command::mcp::McpRemoveCommand;pub use command::mcp::McpResetProjectChoicesCommand;pub use command::mcp::McpServeCommand;pub use command::plugin::PluginDisableCommand;pub use command::plugin::PluginEnableCommand;pub use command::plugin::PluginInstallCommand;pub use command::plugin::PluginListCommand;pub use command::plugin::PluginTagCommand;pub use command::plugin::PluginUninstallCommand;pub use command::plugin::PluginUpdateCommand;pub use command::plugin::PluginValidateCommand;pub use command::query::QueryCommand;pub use command::raw::RawCommand;pub use command::update::UpdateCommand;pub use command::version::VersionCommand;pub use error::Error;pub use error::Result;pub use exec::CommandOutput;pub use mcp_config::TempMcpConfig;pub use mcp_config::McpConfigBuilder;pub use mcp_config::McpServerConfig;pub use retry::BackoffStrategy;pub use retry::RetryPolicy;pub use session::Session;pub use tool_pattern::PatternError;pub use tool_pattern::ToolPattern;pub use version::CliVersion;pub use version::VersionParseError;pub use types::*;
Modules§
- budget
- Cumulative USD budget tracking for Claude sessions.
- command
- dangerous
- Opt-in dangerous operations. Currently: bypass permissions.
- error
- exec
- mcp_
config - retry
- session
- Multi-turn session management.
- streaming
- tool_
pattern - Tool permission patterns for
--allowed-tools/--disallowed-tools. - types
- version
Structs§
- Claude
- The Claude CLI client. Holds shared configuration applied to all commands.
- Claude
Builder - Builder for creating a
Claudeclient.