- Rust 94.7%
- Nix 5.3%
| .forgejo/workflows | ||
| examples | ||
| nix | ||
| src | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| clippy.toml | ||
| flake.lock | ||
| flake.nix | ||
| LICENSE | ||
| README.md | ||
hive-claude
A small, reusable async driver for headless claude --print (Claude Code
CLI) sessions. It spawns the CLI, streams and classifies the stream-json
output, and reports the result. It knows only about the Claude Code CLI —
no application types, hard-coded watermarks, or logging. Compaction,
retry, and reset policy belong to the caller.
When to use it
Reach for this crate whenever you need to run the claude CLI from Rust and
react to how a turn ended, without reimplementing subprocess plumbing,
stream-json classification, or session bookkeeping yourself.
Installation
[dependencies]
hive-claude = "0.1"
Or cargo add hive-claude. The crate drives the Claude Code
CLI as a subprocess, so that
binary is a runtime requirement. It need not be on PATH — point Config at
it directly:
Config {
program: Some("/nix/store/…/bin/claude".into()),
..Default::default()
}
Shape
Two layers — reach for the high-level one:
InfiniteSession { name, store, policy }— a durable session that keeps itself alive across the context window..run(&config, prompt, &sink)→Result<Progress, Error>does resume-or-create, compacts reactively on overflow (compact + retry once), and proactively after a clean turn when the policy says so (optional checkpoint turn, then compact)..compact(…)forces one.Progress { created, compacted, telemetry }reports what happened — including the turn's parsedTelemetry, finalised at theresultevent.Claude::run(&config, &attach, prompt, &sink)→Result<(), Error>— the low-level driver: one turn, oneAttachtarget (Resume/Create/Continue/OneOff). A clean turn isOk(()); every other state is anErrorvariant.
Supporting pieces:
CompactionPolicy— decides when to compact.PercentPolicy(percent,default_window,checkpoint_prompt) compacts at a percent of the model window;NeverCompactnever does.Config— the invocation (model, effort, cwd, prompt/MCP files, tools, extra args, andprogram— which binary to spawn, defaulting toclaudeonPATH).Sink— a trait with no-op defaults; implement what you care about to observe stream events, non-JSON stdout, and stderr.NoopSinkignores all.SessionStore— locate and archive on-disk sessions by title.Telemetry(context,cost,context_window,model) — everything the driver parses from a turn's stream, returned inProgress.Usageis the minimal slice (context_tokens,context_window) the policy sees.
Error unifies the two things that can stop a turn: recognized sentinels
(PromptTooLong, RateLimited, AuthFailed, SessionNotFound) and hard
failures (Spawn, Stdin, Wait, Exit, Io). Sentinels are expected
control-flow, not crashes — the caller compacts, parks, re-auths, or creates a
session in response.
use hive_claude::{Attach, Claude, Config, Error, NoopSink};
# async fn ex() {
let config = Config { model: Some("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}"),
}
# }
License
Apache-2.0 — see LICENSE.
AI use disclosure
This crate's code, tests, and documentation were written by an AI coding agent, with human direction and review.