One decorator composes circuit breaker, retry, timeout, fallback, and idempotency, and a built-in console shows every breaker live. Zero-config to start; add Redis and workers share state. Django, FastAPI, Flask, Celery. Apache-2.0 core. tenacity and pybreaker give you the patterns. Baldur also answers what happens when retries run out, who notices a breaker is open, and how you replay a call that failed for good.
Hi PH - author here.
Baldur started with a question I couldn't answer in a side project. I was building a Django shopping app and asked myself: "what happens if this payment call fails?" I hand-rolled a circuit breaker before finding out pybreaker and tenacity existed - and that is when I noticed the actual gap. The patterns exist as libraries. What didn't exist was the layer that composes them and makes them operable.
So Baldur is one decorator: you name the operation, switch on retry, timeout, fallback and an idempotency key, and it composes them into one ordered pipeline. The second image shows the real thing.
Then there is running it: a built-in console showing every breaker's live state with runtime on/off controls, health checks that tell your load balancer the truth, and Prometheus/OpenTelemetry metrics.
Zero config runs entirely in-memory - no Redis, no Docker, no env vars. Add Redis when you grow to multiple workers and the same call sites share breaker state across the fleet. Django, FastAPI, Flask and Celery adapters wire it at startup. Sync and async both work.
Who it's for - it's about stakes, not traffic. If losing a single operation costs real money (a payment, an invoice, a webhook), this matters at 10 requests a day. If you're already running a service mesh with an SRE team, you likely don't need me.
Upfront: the core is Apache-2.0 and stays that way. There's a paid PRO tier for fleet-level machinery (durable DLQ with batch replay, audit trail, unified notifications, emergency mode) - flat price, one person, no VC.
I'd genuinely appreciate feedback on the API shape, and on what your team does today when a dependency dies mid-request.