← Blog

Busbar 1.3: your code on the request path

Hooks put your logic on the normalized request path across all six protocols. Auth becomes a pluggable chain you can compile out. And the admin API v1 is frozen: the surface tools get to build on.

Busbar 1.3 is the API release. 1.0 froze the data plane: the six wire protocols your apps speak. 1.3 freezes the two surfaces everything else builds on. Hooks, the sanctioned attachment points for your own code on the request path, and admin API v1, the management contract that will only ever grow.

Hooks: write it once, it runs on everything

A hook is your own code. A compiled binary on a local Unix socket (~8µs a call) or an HTTPS sidecar in any language, running on Busbar’s normalized IR: the canonical form every request takes after lossless translation from whatever dialect the caller spoke. That placement is the whole point. Write a PII screen, a smart router, or a context compressor once and it runs against all six protocols and every fronted provider, with failover and circuit breaking underneath it.

Two kinds, one rule. A tap watches: audit, metering, SIEM. It can never delay a request. A gate decides: reject the request, restrict which pool members may serve it, re-order the failover walk, or rewrite the body before it ships. Rewrite is the one I’m most excited about; compression and redaction on the wire, with token accounting on the rewritten body, so the savings are real and measured. The rule is enforced structurally, not by convention: a hook can steer, observe, or rewrite, but it can never break the request path. Slow, crashed, or wrong degrades to a safe default. Every time.

Hooks are also live infrastructure now. Register and remove them at runtime over the admin API; push settings to a running hook, committed only when the hook acknowledges; read back the schema the hook describes for itself. And a hook reports its own operational state: GET /api/v1/admin/hooks/{name}/status is the control-plane read — it live-queries the hook and returns the settings it is actually running against Busbar’s desired copy, with a drift verdict, plus the hook’s self-reported metrics. A dashboard built on Busbar sees what every plug is doing, over the same API. No per-plugin dashboards.

Auth is a chain, and you can compile it out

Authentication is no longer a mode. It’s a chain of modules, PAM-style: the first module to identify the caller admits them, a reject stops everything, and modules that don’t recognize the credential defer down the chain. Today’s token auth is now just the first link, and it’s architecturally identical to anything you’d write yourself.

Every built-in lives in its own crate behind a default-on feature. Want to see how tokens work? Read auth/tokens/; it’s about 70 lines against the same contract external modules use. Need to prove your deployment contains no token-auth code at all? Build without it. The module, its comparison fold, and the allowlist are absent from the binary. Compliance by compilation, checkable from the symbols. Identity maps to authority in config (group_map:), never asserted by a module, and admin principals carry scopes: read-only sees, hooks-register can attach hooks but can’t mint keys, full does everything.

Admin API v1: frozen, so you can build on it

/api/v1/admin/* is now a stable contract, additive-only from here. Pools, keys, usage, hooks, config: reads for dashboards, mutations with optimistic concurrency, per-principal mutation rate limits, and a tamper-evident audit log that attributes every attempt, including the denied ones. The whole surface is discoverable from the binary itself (openapi.json), with the required scope stamped on every operation.

What makes it a contract and not just a pile of endpoints is that every edge is consistent. One error envelope everywhere, and you branch on a frozen code, never on the human message, with a deliberate split baked into the taxonomy: a retryable version_conflict (your If-Match is stale, re-read and retry) versus a terminal conflict (server state a retry can’t fix), alongside unauthorized, method_not_allowed, and the rest. One list envelope, {items, next_cursor}, with opaque cursors. One concurrency mechanism, RFC-7232 If-Match/ETag, on every mutable resource, no body-level twin to keep in sync. And an Idempotency-Key on the secret-minting POSTs, so a retried key mint returns the first response verbatim instead of double-minting. I put the whole wire through several independent contract-audit rounds and fixed every finding before the freeze.

Metering is built on the same principle: expose the inputs of cost, not just a number. GET /api/v1/admin/usage reports per-model and per-key consumption as the raw token split, input, output, cache-read, cache-creation, each of which prices differently, with a spend_micros derived at read time from your configured prices. A consumer with its own negotiated pricing reconstructs cost exactly from the split.

Config management got the same treatment. Validate a candidate config without applying it. Apply one atomically: in-flight requests finish on the old snapshot, new ones see the new one, and surviving lanes keep their learned health. Breakers, cooldowns, latency profiles, all carried by model identity across the swap. Reload from disk with one call. Roll back to a retained version. And because learned health now persists across restarts, the recovery story for a truly broken config is the honest one: fix it and restart. Sub-second, and Busbar comes back remembering which lanes were misbehaving.

Still one binary

Everything above ships in the same single static Rust binary. We roughly doubled the surface (hooks, auth chains, the whole config plane) and the FROM scratch Docker image is still a handful of megabytes, compressed. The default path, with no hooks and no chains configured, is byte-identical to 1.2; the zero-cost floor is a design rule, not an accident. Over 2,000 tests, the full suite green with every plugin compiled out, on Linux, macOS, and Windows.

What’s next

Hooks make Busbar the place your middleware runs; the frozen admin API makes it the thing your tooling manages. Next is filling both ecosystems in, starting with a context-compression hook we’ll have more to say about very soon.

Get it at getbusbar.com. If you’re running multi-provider LLM traffic in production, I’d love to talk.

Comments

Comments live in GitHub Discussions, so the conversation stays next to the code.

Join the discussion on GitHub