//! `hive-claude` — a small, reusable async driver for headless //! `claude --print` (Claude Code CLI) sessions. //! //! It spawns the CLI, streams and classifies its `stream-json` output, and //! reports the result as a `Result<(), Error>`: a clean turn is `Ok(())`, and //! every non-completion state — both recognized sentinels (rate-limit, //! prompt-too-long, …) and hard failures (spawn, non-zero exit) — is a variant //! of the single [`Error`] enum, so callers branch with one `match`. The crate //! also locates and archives on-disk sessions by title ([`SessionStore`]). It //! knows only about the Claude Code CLI — no application types, hard-coded //! watermarks, or logging. Callers wire streaming output through a [`Sink`]. //! //! Two layers: //! //! - [`Claude::run`] — the low-level driver: one turn, one [`Attach`] target. //! - [`InfiniteSession`] — a durable session (name + [`SessionStore`] + //! [`CompactionPolicy`]) that keeps itself alive across the context window by //! compacting reactively (on overflow) and proactively (per policy — e.g. //! [`PercentPolicy`]). This is the one you usually want. //! //! # `thiserror` here, `anyhow` in the apps //! //! This is a **library**, so it exposes a concrete, matchable error enum built //! with [`thiserror`](https://docs.rs/thiserror): a caller can distinguish //! `Error::Exit { status, .. }` from `Error::Spawn { .. }` and branch on it. //! A library should never force its callers to reach into `anyhow`'s //! type-erased error to find out what went wrong. //! //! The **applications** in this workspace (the `hive-*` binaries) use //! [`anyhow`](https://docs.rs/anyhow) instead. At the top level you usually //! only want to attach context and log or bubble a failure up — not match on //! it — and `anyhow::Result` + `?` + `.context()` is the ergonomic fit. //! `anyhow::Error` implements `From` for any `std::error::Error`, so a //! `hive_claude::Error` converts into an `anyhow::Error` for free at the `?` //! boundary. Rule of thumb: **libraries return `thiserror` enums, binaries //! consume them with `anyhow`.** //! //! # Example //! //! ```no_run //! # async fn ex() { //! use hive_claude::{Attach, Claude, Config, Error, NoopSink}; //! //! let config = Config { //! model: "haiku".into(), //! ..Default::default() //! }; //! match Claude::run(&config, &Attach::Resume("my-session".into()), "hello", &NoopSink).await { //! Ok(()) => {} //! Err(Error::PromptTooLong) => { /* caller compacts + retries */ } //! Err(Error::RateLimited) => { /* caller parks + retries */ } //! Err(other) => eprintln!("claude: {other}"), //! } //! # } //! ``` // The crate-level `//!` overview above is the rustdoc entry point — it belongs // in source, not docs/, so the comment-block length lint should not flag it. // lint:allow-long-comment mod classify; mod config; mod driver; mod error; mod policy; mod session; mod sink; mod store; mod telemetry; pub use config::{Attach, Config}; pub use driver::Claude; pub use error::{Error, Result}; pub use policy::{CompactionPolicy, NeverCompact, PercentPolicy}; pub use session::{InfiniteSession, Progress}; pub use sink::{NoopSink, Sink}; pub use store::SessionStore; pub use telemetry::{Telemetry, TokenUsage, Usage};