pub struct ClaudeBuilder { /* private fields */ }Expand description
Implementations§
Source§impl ClaudeBuilder
impl ClaudeBuilder
Sourcepub fn binary(self, path: impl Into<PathBuf>) -> Self
pub fn binary(self, path: impl Into<PathBuf>) -> Self
Set the path to the claude binary.
If not set, the binary is resolved from PATH using which.
Sourcepub fn working_dir(self, path: impl Into<PathBuf>) -> Self
pub fn working_dir(self, path: impl Into<PathBuf>) -> Self
Set the working directory for all commands.
The spawned process will use this as its current directory.
Sourcepub fn env(self, key: impl Into<String>, value: impl Into<String>) -> Self
pub fn env(self, key: impl Into<String>, value: impl Into<String>) -> Self
Add an environment variable to pass to all commands.
Sourcepub fn envs(
self,
vars: impl IntoIterator<Item = (impl Into<String>, impl Into<String>)>,
) -> Self
pub fn envs( self, vars: impl IntoIterator<Item = (impl Into<String>, impl Into<String>)>, ) -> Self
Add multiple environment variables.
Sourcepub fn clear_env(self) -> Self
pub fn clear_env(self) -> Self
Clear the inherited environment of every spawned Claude CLI child.
By default, children inherit the parent process environment and
env / envs add or replace entries. With
this option enabled, the inherited environment is cleared first and
only explicitly configured entries are applied. The order in which
clear_env, env, and envs are called does not affect the result.
Callers normally need to rebuild a minimal environment including
PATH, locale settings, the Claude config directory, and the intended
authentication selector.
This controls only the direct child process environment. It is not an operating-system sandbox and does not prevent a same-UID child from reading accessible files or inspecting other processes where the OS permits it.
§Example
use claude_wrapper::Claude;
let claude = Claude::builder()
.clear_env()
.env("PATH", "/usr/local/bin:/usr/bin:/bin")
.env("CLAUDE_CONFIG_DIR", "/srv/claude/config")
.build()?;Sourcepub fn timeout_secs(self, seconds: u64) -> Self
pub fn timeout_secs(self, seconds: u64) -> Self
Set a default timeout for all commands (in seconds).
Sourcepub fn arg(self, arg: impl Into<String>) -> Self
pub fn arg(self, arg: impl Into<String>) -> Self
Add a global argument applied to all commands.
This is an escape hatch for flags not yet covered by the API.
Sourcepub fn retry(self, policy: RetryPolicy) -> Self
pub fn retry(self, policy: RetryPolicy) -> Self
Set a default retry policy for all commands.
Individual commands can override this via their own retry settings.
§Example
use claude_wrapper::{Claude, RetryPolicy};
use std::time::Duration;
let claude = Claude::builder()
.retry(RetryPolicy::new()
.max_attempts(3)
.initial_backoff(Duration::from_secs(2))
.exponential()
.retry_on_timeout(true))
.build()?;Sourcepub fn tested_cli_version_range(self, min: CliVersion, max: CliVersion) -> Self
pub fn tested_cli_version_range(self, min: CliVersion, max: CliVersion) -> Self
Declare the inclusive [min, max] range of claude CLI
versions this client has been tested against.
The wrapper does not enforce the range – nothing errors when
it’s set wrong. Use Claude::cli_version_status (or its
sync mirror) at startup to classify the actually-installed CLI
against this declaration; that call returns a typed
CliVersionStatus AND emits a tracing::warn! when
outside the range. Hosts (claude-server, application code)
can additionally surface the status to operators.
§Why this exists
CLI semantics drift across minor / patch releases (e.g.
claude agents was repurposed in 2.1.143). The min floor
lets us say “we know it’s broken below this”; the max ceiling
lets us say “we haven’t verified above this – proceed but
expect surprises.”
§You usually do not need this
The crate declares its own range in
TESTED_CLI_VERSION_MIN / TESTED_CLI_VERSION_MAX, and
version checks use it by default, because only the crate knows
what it was built and tested against. Set this only when a host
has verified a different range itself.
§Example
use claude_wrapper::{Claude, CliVersion};
let claude = Claude::builder()
.tested_cli_version_range(CliVersion::new(2, 1, 0), CliVersion::new(2, 1, 999))
.build()?;
// Run once at startup to log a warning if the CLI is out of range.
let _status = claude.cli_version_status().await?;Sourcepub fn process_group(self, enabled: bool) -> Self
pub fn process_group(self, enabled: bool) -> Self
Control whether spawned claude children are placed in their
own process group on Unix. Defaults to true.
Own group (the default): cancellation and timeouts kill the child’s whole process tree, but the child no longer shares the host terminal’s process group, so terminal-generated signals (Ctrl-C) do not reach it; terminating a run is the wrapper’s job via drop, timeout, or explicit kill. This is the right contract for supervisors (daemons, MCP servers, worker queues).
Shared group (false): the child stays in the host’s process
group, so a terminal Ctrl-C reaches the whole run directly, but
a wrapper-side kill only reaches the direct child and any
subprocesses it spawned for tool use survive it. This is the
right contract for terminal-attached hosts that shell out
synchronously and rely on the terminal as the supervisor.
No effect on non-Unix targets.
Sourcepub fn kill_grace(self, grace: Duration) -> Self
pub fn kill_grace(self, grace: Duration) -> Self
Grace period between SIGTERM and SIGKILL when a run is killed by a timeout or a duplex shutdown overrun (Unix). Default: none; kills are immediate SIGKILL.
With a grace set, the child’s whole process group gets SIGTERM
first so claude can flush its transcript and session state,
and SIGKILL follows once the grace elapses. The full grace is
waited before the timeout error returns, so keep it short
(500ms to 2s). Dropping a future cannot wait, so drop-path
cancellation stays immediate SIGKILL, and the grace applies
only while the child is in its own process group (see
process_group).
Sourcepub fn on_spawn(self, observer: SpawnObserver) -> Self
pub fn on_spawn(self, observer: SpawnObserver) -> Self
Observe every child this client spawns, at spawn time.
The observer receives a SpawnInfo before the run produces output,
which is what makes it useful to a supervisor: recording the pid only
once a run finishes leaves nothing to reconcile after a crash
mid-run. Fires for one-shot runs, streaming runs, and duplex sessions
alike, and on retry it fires once per attempt, since each attempt is a
distinct process.
The observer runs inline on the spawning thread, so it must not block. Write a pidfile or push to a channel; do not do I/O that can stall.
§Why a callback rather than a return value
The crash case needs the pid to be durable before the run can be orphaned. A pid on the result type arrives too late for exactly the scenario that motivates recording it.
§Example
use std::sync::Arc;
use claude_wrapper::Claude;
let claude = Claude::builder()
.on_spawn(Arc::new(|info| {
eprintln!("spawned pid {} (group {:?})", info.pid, info.pgid);
}))
.build()?;Sourcepub fn die_with_parent(self, enabled: bool) -> Self
pub fn die_with_parent(self, enabled: bool) -> Self
Ask the kernel to kill spawned children when this process dies.
Linux only. Check die_with_parent_supported
rather than assuming; elsewhere this is accepted and does nothing.
§The problem it addresses
Every other cleanup path in this crate is a destructor: kill_on_drop,
and the process-group kill on drop, timeout, or stream error. None of
them run when this process is SIGKILLed. The child is then reparented
to init, and because it leads its own process group (see
process_group) terminal signals cannot reach it
either. It keeps running, keeps billing, and keeps appending to the
session transcript, so a restarted supervisor that resumes the same
session id can find itself interleaving with an orphan still writing.
On Linux PR_SET_PDEATHSIG closes that: the kernel delivers SIGKILL to
the child the moment its parent dies, with no cooperation from either
side.
§What it does not cover
- Non-Linux targets. macOS has no equivalent. A supervisor that
needs the guarantee there has to poll and kill by pid; recording the
pid is what
on_spawnis for. - Re-parenting. The signal fires when the immediate parent dies. If the crate’s caller is itself an intermediate process that exits normally, the child dies then, which is usually what you want but is worth knowing if you daemonize between building the client and spawning.
- The fork/prctl window. Handled: the hook re-checks
getppid()after arming and exits if the parent already changed. Without that check a parent dying in that window leaves exactly the orphan this option exists to prevent.
Off by default, because killing children on parent exit is the right default for a supervisor and the wrong one for a CLI that deliberately backgrounds work.