Skip to main content
Version: MVP

ADR 0002 · Provider transport and mode families

2 min readAcceptedRecorded 2026-05-01

What this ADR decides

That Craik separates provider families from transport. Provider adapters own payload shape, streaming, errors, and result normalization. Transports own delivery and chunk parsing. OpenAI Responses, Anthropic Messages, and OpenAI-compatible Chat Completions are three distinct provider families.

Status: Accepted.

A single generic HTTP provider would hide tool, streaming, usage, and retry differences. Splitting transport from family keeps each axis testable and lets fixture transports cover provider tests offline.

Context

Craik needs one provider path that can run fixtures, local OpenAI-compatible servers, and hosted OpenAI and Anthropic APIs. The OpenAI Responses API, Anthropic Messages API, and Chat Completions–compatible servers are related but not interchangeable wire formats. Treating them as one adapter would hide tool, streaming, usage, and retry differences.

Decision

Provider adapters

Own payload construction · streaming normalization · error classification · result normalization.

Transports

Own delivery and chunk parsing. FixtureTransport keeps tests offline; HTTPTransport uses stdlib urllib for live JSON and SSE.

Three distinct provider families:

OpenAI Responses

Anthropic Messages

Chat Completions (OAI-compatible)

Covers Ollama · vLLM · LM Studio · OpenRouter-shaped endpoints.

Consequences

Provider tests can exercise adapters without network access. Live transport hardening can evolve without rewriting provider-specific schemas. The cost is a small amount of family-specific normalization code and certification coverage for each supported family.

Alternatives considered

Alternative
Disposition
Why rejected
Single generic HTTP provider
rejected
Would push schema branches into callers and receipts.
SDK dependencies
rejected for MVP
Stdlib HTTP keeps package release and CI behavior simpler.

Retraction: none active.

Retract this ADR if Craik moves provider execution into an external provider gateway with its own typed transport contract.

What's next