A living document, ordered by what blocks adoption rather than by what is interesting to build. It came out of an audit that went looking for the gap between "CI is green" and "a company can depend on this" — and found the gap was elsewhere, and larger than the test suite could see.
Where this came from#
CI was green: four modules, -race, coverage above every floor, a clean linter,
a fuzzer surviving millions of executions. Three things dominated everything
else, and only one of them was visible from inside the test suite.
| Finding | Status |
|---|---|
| skyl could not be installed — no tags, and submodules required the root at v0.0.0 behind replace directives Go ignores | Fixed |
| The Go 1.26 floor was not justified by the code — nothing outside tests used anything newer than 1.22 | Fixed |
| Some documented rules were not met — §6.5 (honour ProviderOptions), §6.1 (never silently drop data), §8.3 (runnable examples) | Fixed |
Phase 0 — Defects ✅#
Nine bugs with specific failure modes, each fixed with a regression test that failed before the fix. The ones worth knowing about because they changed behaviour:
| Defect | Failure mode |
|---|---|
| Anthropic ignored ProviderOptions | The only escape hatch to cache_control, top_k and beta features was unreachable there — with no workaround at all. |
| TotalTokens double-counted cache reads | Cost dashboards over-reported by up to ~2× on a well-cached agent loop. |
| Content arrays silently dropped | vLLM and some Azure/OpenRouter upstreams yielded a successful response with empty text. |
| Retry-After clamped to maxDelay | A standard Retry-After: 60 was truncated to 30s, so the retry landed inside the still-open window and was rejected again. |
| Transport errors lost their cause | errors.Is(err, context.DeadlineExceeded) was false after a timeout, and a permanent TLS misconfiguration was retried as transient. |
| Anthropic tool schemas rebuilt lossily | $defs, $ref and oneOf were dropped, so the same skyl.Tool behaved differently across providers — undercutting the one feature the library is named for. |
| Gemini ignored Request.Thinking | &Thinking{Enabled: false} could not disable reasoning, so a real cost control silently did nothing. |
| Truncated streams looked complete | A connection dropped mid-generation returned a partial answer with a nil error. |
| Refusals reported as success | ErrRefusal was never produced by any adapter, and the gateway's 422 branch was unreachable. |
Phase 1 — Prove correctness without credentials ✅#
The sandbox: a local server speaking all four wire protocols, with fault models
for statuses, truncation and mid-stream errors. Plus runnable Example
functions, benchmarks on the per-token paths, and internal/cassette for
recorded replay.
The benchmark caught tool-argument accumulation being quadratic — 2.2 MB allocated to assemble a few kilobytes. The fix brought it to 34 KB, and the benchmark stays as the guard.
Phase 2 — Make it installable ✅#
Tags, the replace-directive removal, go.work for local development, and a CI
check that refuses a tag whose modules still carry a replace or a v0.0.0
require. Either one publishes a module nobody can install, and the proxy will
serve it forever.
Phase 3 — What an enterprise review asks for ✅#
Supply chain (govulncheck, CodeQL, Scorecard, Dependabot, SBOM, signed
provenance, digest-pinned actions, DCO), governance (NOTICE, per-module
licences, CODEOWNERS, MAINTAINERS.md, code of conduct, issue templates), and
the gateway hardening: /readyz, /metrics, graceful drain, concurrency
limits, rotatable labelled tokens, CORS, SSE keep-alives, and env vars for every
skyl.Option.
Plus skyl/otel as a fourth module, and
data-handling and
threat-model documents.
Phase 4 — Documentation that survives an evaluation#
In progress. The feature matrix, the silently-ignored list, and this site.
The one thing that still blocks adoption#
This is the gap, stated plainly. It is closable by one contributor with a key — either by running the integration suite, or by recording a cassette, which improves the suite for everyone permanently.
Deferred, deliberately#
- A generated model registry — context windows, pricing, modality — refreshed from live endpoints by CI. Generated, never hand-typed, so it cannot silently rot.
- Cross-provider fallback. A product decision, not a library one. See Choosing a Provider.
- An
Agentinterface. Possibly a v2. The Copilot agent runtime is a real, interesting capability — it just needs a different shape thanCompleter.
What this is not#
Not a promise of dates. It is an ordered list of what blocks adoption, and it changes when the answer to that question changes.