forge_sdk/lib.rs
1//! # forge-sdk
2//!
3//! A peer reference implementation in Rust of a client for Anthropic's
4//! `claude` CLI. Spawns the binary as a subprocess and speaks
5//! stream-json over stdio. Wire compatibility with the CLI is the only
6//! hard external invariant; API shape is whatever serves
7//! [`forge-agent`](https://github.com/busytools/forge/tree/main/crates/forge-agent)
8//! (and through it the views) best.
9//!
10//! ## Design
11//!
12//! The SDK is a thin wrapper around the `claude` binary. All agentic
13//! work - tool dispatch, conversation history, session persistence -
14//! happens inside the CLI itself. This crate is responsible for:
15//!
16//! - Spawning the subprocess with the right flags.
17//! - Parsing the stream-json output into typed Rust values.
18//! - Serialising user messages into stream-json input.
19//! - Bridging the `can_use_tool` callback (when enabled) across the wire.
20//! - Hosting in-process MCP tool servers that the `claude` binary can call.
21//!
22//! [`Client`] is `Clone`-able; all commands take `&self`. Internally
23//! a reader task owns the subprocess after init, decodes lines,
24//! dispatches inbound `control_request`s on detached tasks, and
25//! routes outbound `control_response`s to per-request waiters.
26//!
27//! ## Minimal example
28//!
29//! ```no_run
30//! # async fn example() -> anyhow::Result<()> {
31//! use forge_sdk::{Client, OptionsBuilder};
32//!
33//! let options = OptionsBuilder::new().build();
34//! let (client, mut events) = Client::spawn(options).await?;
35//! client.send_user_message("hello").await?;
36//! while let Some(item) = events.recv().await {
37//! let event = item?;
38//! println!("{event:?}");
39//! }
40//! client.disconnect().await?;
41//! # Ok(()) }
42//! ```
43
44#![forbid(unsafe_code)]
45
46pub mod argv;
47mod client;
48pub mod control;
49mod error;
50pub mod hooks;
51pub(crate) mod logging;
52pub mod mcp;
53mod options;
54pub mod paths;
55pub(crate) mod permissions;
56pub mod request_id;
57pub mod subagents;
58pub mod transport;
59
60pub use crate::mcp::macros::__private;
61pub use client::{Client, ClientEvents, INIT_HANDSHAKE_TIMEOUT};
62pub use error::Error;
63pub use hooks::{
64 BaseHookInput, HookCallback, HookContext, HookDecision, HookKind, Hooks, HooksBuilder,
65 NotificationInput, PermissionRequestInput, PostToolUseFailureInput, PostToolUseInput,
66 PreCompactInput, PreToolUseHookSpecificOutput, PreToolUseInput, StopInput, SubagentContext,
67 SubagentStartInput, SubagentStopInput, UserPromptSubmitHookSpecificOutput,
68 UserPromptSubmitInput,
69};
70pub use options::{Options, OptionsBuilder, PermissionMode, SdkPluginConfig, SystemPromptKind};
71pub use paths::{app_support_dir, config_dir_hash, config_dir_store_key, projects_dir_for};
72pub use permissions::CanUseToolCallback;
73pub use transport::process::CLOSE_WAIT_TIMEOUT;
74
75/// Convenient alias for `Result<T, forge_sdk::Error>`.
76pub type Result<T, E = Error> = core::result::Result<T, E>;