skald/vendor/clawdforge/src/lib.rs
Sulkta a291f44a10 forge: always --effort max + multi-chapter batch (cap 20)
forge.rs threads Effort::Max on gen + cleanup. Audit + summarize stay
default — they're structured-output / tool-shaped tasks where extended
thinking doesn't help. Bumps subprocess timeout from 600s to 1800s so
max-effort prose-craft has the wall clock it needs.

continue_story::run takes a chapter_count param; loops gen+cleanup per
chapter with each iteration's just-written prose appended to context.
Audit fires once at end against the combined batch vs parent canon.
Cap is 20 (~5h wall clock, ~$600 at max effort — beyond that is
operationally absurd).

CLI: 'skald continue --chapters N'. Web: numeric field on both new-
story and continue forms, 1..=20, defaults to 1.

Vendored clawdforge SDK refreshed for the Effort enum.
2026-05-13 14:26:53 -07:00

58 lines
1.8 KiB
Rust

//! Async Rust client for the [clawdforge] HTTP service.
//!
//! clawdforge is a small LAN-only service that wraps `claude -p` subprocess
//! calls behind a bearer-token-gated REST API. This crate is a thin,
//! ergonomic Rust SDK for it.
//!
//! # Quickstart
//!
//! ```no_run
//! use clawdforge::{Client, RunRequest};
//!
//! # async fn run() -> Result<(), Box<dyn std::error::Error>> {
//! let client = Client::builder()
//! .base_url("http://localhost:8800")
//! .token("cf_xxxxxxxxxxxxxxxx")
//! .build()?;
//!
//! let h = client.healthz().await?;
//! println!("claude present: {}", h.claude_present);
//!
//! let r = client.run(RunRequest {
//! prompt: "Reply with JSON: {\"hello\":\"world\"}".into(),
//! model: Some("sonnet".into()),
//! ..Default::default()
//! }).await?;
//!
//! #[derive(serde::Deserialize)]
//! struct Hello { hello: String }
//! let typed: Hello = r.as_json()?;
//! println!("{}", typed.hello);
//! # Ok(()) }
//! ```
//!
//! [clawdforge]: https://git.sulkta.com/Sulkta-OSS/clawdforge
//!
//! # Field naming
//!
//! The clawdforge wire format is snake_case end-to-end (Python / Pydantic
//! conventions), so structs in [`crate::types`] do **not** carry
//! `#[serde(rename_all = "camelCase")]`. If a future endpoint exposes
//! camelCase, prefer per-field `#[serde(rename = "...")]` over a blanket
//! container attribute.
#![deny(rust_2018_idioms)]
#![deny(missing_docs)]
mod client;
mod error;
pub mod session;
pub mod types;
pub use client::{Client, ClientBuilder};
pub use error::Error;
pub use session::{Session, SessionList, SessionOptions, SessionState, TurnEvent, TurnResult};
pub use types::{
AppToken, AppTokenInfo, Effort, FileToken, Healthz, RunFailure, RunRequest, RunResult,
SystemMode, TokenCreateRequest, TokenList,
};