A README change was building a multi-arch Docker image. Both workflows now
ignore markdown, docs/, demo/, .gitignore and LICENSE. providers/*.json is
deliberately not ignored: CI fails if one stops parsing, which is the one data
change that can break a running gateway.
arm64 is cross-built under QEMU and dominates the Docker job, so it is now only
built for tagged releases; main and PRs build native amd64 only. QEMU setup is
skipped entirely when it is not needed.
Anchors would have kept the paths-ignore lists DRY, but Actions has been
unreliable with them and a broken workflow costs more than five duplicated
lines.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The dashboard now answers "where did my tokens go" without opening the log:
totals, per-provider and per-model breakdown, and cache hits shown as the
requests that cost nothing. Each log row expands to the actual prompt and
response, truncated to keep the ring buffer flat.
CI's Docker smoke step supplied no virtual keys, so the container correctly
refused to bind 0.0.0.0 and the job failed. The failsafe was right and the
workflow was wrong; it now supplies keys and additionally asserts that an
unauthenticated call gets 401 and an inference key gets 403 on /api, so an
image that lost its auth boundaries cannot be published green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
One endpoint in front of every free LLM tier, with automatic failover and no
provider key ever leaving the box.
Providers are data, not code: adding one is a JSON file plus an env var, never
a TypeScript change. Ships 12 providers pre-written; `verify-provider --apply`
derives the live model list from your own key.
- core: registry, bucketed quota meter (rolling + UTC-calendar windows),
key-pool store, 6-step model router with diagnostic rejection reasons
- gateway: node:http, failover that commits to a stream only after 200 headers,
SSE passthrough with usage sniffing, virtual keys with admin/inference roles
- context engine: sqlite sessions and a 5-rung refit ladder, so a 128k thread
keeps working when it fails over to an 8k model
- cache: exact (sha256, safe-by-default) + opt-in semantic (flat Float32Array)
- guard: inbound limits, quota forecasting, limit calibration from upstream
headers, key health, secret/PII/injection scanning
- dashboard: one self-contained HTML file, live SSE request log, token usage
- sdk: zero-dep typed client, drop-in for the OpenAI SDK
Zero runtime dependencies. 326 tests, 27-check smoke suite against a scripted
mock upstream so routing is testable without spending quota.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>