Is Caduceus production-ready at 1.0.0?
Yes. 159 tests pass under Vitest 4 with 94% coverage; TypeScript 6 maximum strict mode is clean; Biome 2.5
lint is clean; publint and @arethetypeswrong/cli are clean across all eleven
subpaths. The suite and the distribution smoke test are run on the Node 20, 22, and 24 matrix. Every
published release carries SLSA provenance produced by GitHub Actions.
Why not just call one provider directly?
Because no single provider is always up, always cheapest, or always best; different providers lead on
programming, mathematics, security, and long context, and any of them can rate-limit or go down. Caduceus
routes to the best available model by your strategy and fails over automatically when one is down, so a
single hard-coded provider is never a single point of failure.
Why not write your own provider glue?
You can, and many do. The cost is per-provider request, stream, and tool-call code that you rewrite on
every swap, and failover, breakers, budgets, and a trace you must build yourself. Caduceus normalizes the
shapes, orders the pool by a strategy, and builds the cost forecast, the budget ceiling, the circuit
breakers, and the auditable trace in, so the transport is one library instead of glue per provider.
Does Caduceus call any model itself?
No. The core is routing logic over an injectable dispatch. You provide the transport, the bundled fetch
dispatch, a Vercel AI SDK call, an OpenAI-style chat function, or a deterministic mock, and the router
drives it. That keeps the package provider-agnostic, dependency-free, and testable with no network, and it
means your provider keys live in your dispatch, never in Caduceus.
Does this work in Cloudflare Workers, Vercel Edge, Bun, or Deno?
Yes. The core is node-free; the trace seal uses the Web Crypto API, not node:crypto. Import
@takk/caduceus or @takk/caduceus/edge on any runtime with Web Crypto, and pair it
with a dispatch built on the runtime's own fetch. Only @takk/caduceus/node, the bundled fetch
dispatch and the JSON loaders, requires the Node standard library.
How does Caduceus handle my data?
Caduceus holds the provider and model descriptors you register, the request you pass, and the route
results it builds, nothing else. It makes no outbound network calls of its own; the only model calls are
the ones your injected dispatch makes to your chosen providers. With the file loaders, only the roster,
request, or trace files you point it at are read from disk, and no provider credentials are ever held by
Caduceus.
What does the routing strategy actually decide?
Per request, the strategy orders the candidate models by cost, quality, or latency; the router then tries
them in that order, skipping models whose circuit breaker is open and failing over on error. The 1.0
strategies are transparent and deterministic. You can pick a strategy per request, restrict the candidate
models, or read the recorded attempts to see exactly which models were tried and why one won.
Is the trace seal a digital signature?
No, and the docs are explicit about it. The seal is a SHA-256 digest of the trace's canonical form, so any
later edit makes verifyTraceSeal return false. It is an integrity seal, not a signature: it
does not prove who produced the trace. Signed and timestamped seals for stronger third-party evidence are
on the roadmap.
Which providers does it support?
The codec normalizes OpenAI, Anthropic, and Gemini natively, and an OpenAI-compatible shape covers any
other gateway (Ollama, vLLM, Together, Groq, OpenRouter, and the rest). Because you inject the dispatch,
you can also route to a local model or a mock. Adapters are included for an OpenAI-style chat function and
the Vercel AI SDK, so wrapping your existing call is two lines.
Where does the state live?
In-process memory by default: the registered provider and model pool and the per-model circuit-breaker
counters. For disk-backed input, load a provider roster, a model roster, a request, or a saved trace from
JSON with @takk/caduceus/node. A route trace is a plain object you can serialize to your own
store whenever you want.
How does it keep cost under control?
Each model carries a cost profile. Caduceus forecasts the dollar cost of each candidate before any call,
and a budget tracker refuses any call that would breach the per-request ceiling you set, raising a typed
BUDGET_EXCEEDED. A cost-first or sequential-cascade strategy further tries the cheapest model
first and escalates only on failure.
How do I verify a published version's provenance?
Every release is published with npm publish --provenance. Check the attestations with
npm view @takk/caduceus@<version> --json | jq .dist.attestations. The attestation
links the tarball you installed to the GitHub Actions workflow that built it from a specific source commit.
What is the policy on breaking changes?
Strict SemVer 2.0.0, starting from 1.0.0. The binding stability surface is documented in SPEC.md section
5. Major bumps require a deprecation cycle; security fixes follow the disclosure flow in SECURITY.md.