Install fascicle, wire a sequence of plain functions, and run it as a value. Then add a model call when you need one.
Provider SDKs are optional peers — each is loaded lazily on first generate against that provider. Install only the ones you call.
A flow is a tree of plain Step values. sequence threads each output into the next input.
model_call is the only sanctioned bridge between composition and the engine. It threads abort, trajectory, and streaming for you.
The mental model behind fascicle. Read this once — the rest of the docs assume it.
fascicle ships two independently useful layers from a single src/ tree, glued by exactly one value — model_call.
Every composable unit is a Step<i, o>. Every composer takes one and returns one — the type never widens.
run(flow, input) executes to completion. run.stream(...) returns { events, result } — purely observational over the same graph.
When two non-adjacent steps must agree on a value, bind it by name instead of rewiring the whole chain.
Every composer takes a Step<i, o> and returns one. Click any primitive to expand its signature and an example.
Configure the engine with create_engine(config). Only providers is required; everything else has a default.
defaults pre-fills per-call options so your generate sites stay terse. Per-call options win via nullish coalesce; provider_options shallow-merges per provider key.
Retries apply only to provider-side failures — 429s, 5xx, and network errors. Backoff is exponential with jitter; Retry-After always wins.
Construct once per process. dispose() is idempotent; after it, every generate throws engine_disposed_error. Subprocess providers abort in-flight children on dispose.
Eight adapters ship with the engine layer. Seven wrap Vercel's AI SDK; the eighth, claude_cli, spawns the claude binary. Each SDK is an optional peer.
{{ active.note }}
effort: 'none' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' is a provider-neutral knob, translated per provider.
ollama · lmstudio · claude_cli drop effort and record effort_ignored on the trajectory.
Typed errors live in fascicle and bubble out of run(...) as normal promise rejections. Composition errors carry a .path of step ids.