See which axis is throttling you.
Every dashboard can tell you a request was denied. Lens tells you why: which of rate, concurrency, or cost bound it, live and per key. A built-in, zero-dependency terminal dashboard that ships inside the server.
When you govern rate, concurrency, and cost at once, a denial could be any of them: a key over its request rate, the backend at its in-flight ceiling, or a tenant out of token budget. Every other limiter dashboard shows you a denial count and leaves you to guess which one. Guess wrong and you tune the wrong knob.
Lens reads the binding axis straight off the decision the limiter already made (no extra store reads, no second code path), so for every denial it can name the axis that bound it. It taps the same in-process telemetry synchronously, exception-swallowing, O(1): a throwing observer can never break admission, and the gRPC decisions are byte-for-byte unchanged whether Lens is watching or not.
rate ████████████░░░░░ 1,204
concurrency ███░░░░░░░░░░░░░░ 318
cost ██████░░░░░░░░░░░ 642
TOP DENIED KEY tenant:42 → cost (budget spent)
The same signal exports over OpenTelemetry as throttlekit.denies_by_axis{lane} for shops that live in Grafana.
Attribution + throughput.
The binding-axis hero, allow/deny throughput, and the top denied keys, the at-a-glance health of every policy.
Per-policy admit cost.
Avg / p50 / p99 / max over a rolling sample ring (nearest-rank); a policy with no samples says so honestly.
Token budgets, live.
The cost axis: per-key token spend against budget, the LLM-gateway view for tokenBudget / fleetBudget.
Tenant shares.
For weighted-fair escrow, per-tenant guaranteed share vs used vs borrowed: green within guarantee, yellow on borrowed surplus.
Non-consuming forecast.
For the hottest key: how many requests are spendable now, when +1 returns, and when it's fully replenished.
Concurrency headroom.
Each guard's inflight vs its enforced ceiling, who's draining over their slice, and the live self-fence feed.
What-if, on live traffic.
A deterministic shadow of each leaf policy's arrivals; press r to read how many requests a candidate config would flip. Replay →
Diff before you deploy.
Press P to diff a candidate config against the running one over the capture shadow: a terraform plan for limits. Policy Plans →
A dashboard you can only see on one box isn't an ops tool. So the same state Lens renders is readable remotely, three ways:
Read it from any language.
A read-only throttlekit.v1.Monitor service: GetSnapshot for the typed board, Watch for a live policy-filtered denial stream. Loopback-only until --monitor-secret (the snapshot carries traffic keys = PII).
/metrics + /healthz.
--metrics-port serves per-policy allow/deny, the per-axis throttlekit_denied_by_axis_total, observed ceiling, and p50/p99 in exposition format. Aggregate + PII-free, so it needs no auth.
Probes that just work.
The standard grpc.health.v1.Health on the same port, always on, no auth. Kubernetes liveness/readiness probes and service meshes work out of the box.
- Opt-in, terminal-native. Lens is
--tui, not on by default, and wants an interactive TTY; a non-TTY warns and serves the gRPC door without it. no browser, no build step, no port to expose - Never on the decision path. The telemetry tap is a post-decision, O(1), exception-swallowing tail; it can't change, delay, or break an admission. the gRPC decisions are byte-identical with Lens off or on
- PII is gated. The snapshot carries traffic keys, so the Monitor door is loopback-only until you set a secret; the Prometheus endpoint is aggregate-only and PII-free. --monitor-secret / loopback default
- Bounded under a flood. The live denial
Watchis rate-capped and backpressured server-side, so a slow reader drops events; the feed never grows server memory. the control path is never perturbed