throttlekit
·

Introducing ThrottleKit Lens — which axis throttled me?

A built-in, zero-dependency terminal dashboard that shows, live and per key, which of rate, concurrency, or cost bound each denial — the one view no other rate-limiter dashboard can render.

Every rate-limiter dashboard can tell you that a request was denied. None of them can tell you why: which of the axes you’re governing actually bound it. When you limit on rate, concurrency, and cost at once, “denied” is three different problems wearing the same colour, and you debug the wrong one.

ThrottleKit Lens answers the question directly. It’s a built-in, zero-dependency terminal dashboard that ships inside throttlekit-server:

throttlekit-server --config ./throttlekit.yaml --tui

The hero view: binding-axis attribution

The headline panel is binding-axis attribution. For every denial, it shows which axis bound it: rate, concurrency, or cost (or the joint-LP policy lane). It reads straight off the same in-process telemetry the limiter already computes, so it adds no hot-path store reads and never changes a decision. A throwing observer can’t break admission; the tap is synchronous, exception-swallowing, and O(1).

Around it are eight tabbed views: throughput and top denied keys, per-policy latency (avg / p50 / p99), the Cost Room for token budgets, weighted-fair-escrow tenant shares, non-consuming capacity forecasts, concurrency-guard health, and a live denial feed with exact per-axis numbers. Press 18 or Tab to switch; p pauses, q quits.

Why the terminal

Lens started as a browser dashboard and we pulled it back to the terminal on purpose. A TUI has no build step, no port to expose, no auth surface, and no dependency to audit. It runs where your server already runs. It’s opt-in via --tui and wants an interactive TTY; a non-TTY just warns and serves the gRPC door without it.

Reading it remotely

A dashboard you can only see on one box isn’t an ops tool. So the same state is readable from anywhere:

  • the Monitor door: a read-only gRPC service (GetSnapshot / a live filtered denial Watch) you can call from any language, loopback-only until you set --monitor-secret;
  • Prometheus: --metrics-port serves /metrics (per-policy allow/deny, the per-axis throttlekit_denied_by_axis_total, observed ceiling, p50/p99) and a /healthz probe;
  • gRPC health: the standard grpc.health.v1.Health service on the same port, so Kubernetes probes and service meshes work out of the box.

For fully headless shops, the binding-axis signal also exports over OpenTelemetry as throttlekit.denies_by_axis{lane} straight into Grafana.

Lens is part of throttlekit-server. Point it at a config, add --tui, and watch which axis is actually throttling you.