{"slug": "building-an-autonomy-error-budget-gateway-with-signoz-and-opentelemetry", "title": "Building an Autonomy Error Budget Gateway with SigNoz and OpenTelemetry", "summary": "A developer built LEASH, an error budget gateway for AI agents that dynamically adjusts permissions based on real-time telemetry from SigNoz and OpenTelemetry. The system demotes an agent's access tier when failures exceed a threshold, preventing autonomous agents from causing damage during hallucinations or tool failures. The project was completed in about a day for the Agents of SigNoz hackathon.", "body_md": "I built an AI agent that's allowed to run database migrations and clean up staging tables on its own. Then I built a second system whose only job is to take that permission away the moment things start going wrong. That second system is LEASH, and this is the story of building it in about a day for the Agents of SigNoz hackathon.\n\nEveryone talks about AI agents \"acting autonomously\" like it's a settled, safe thing. It isn't. If you give an agent write access to a database and it hallucinates, or one of its tools starts failing silently, nothing stops it from doing that ten more times before a human even notices.\n\nThe usual fix people reach for is \"human in the loop.\" Sounds responsible. In practice it doesn't scale. Nobody is reviewing every single tool call an agent makes at 3am. You either become a rubber stamp clicking approve without reading, or the whole pipeline grinds to a halt waiting on you.\n\nSo I asked a dumber, more mechanical question instead: what if the agent's permissions weren't fixed, and instead moved up and down based on whether its recent actions were actually working?\n\nThat's basically an error budget. SRE teams have used this idea for years for deployments, if a service is burning through its error budget, you freeze releases. I just pointed the same idea at an AI agent's tool calls instead of at deploys.\n\nLEASH sits between an agent and the tools it's allowed to call. The agent doesn't get to decide for itself if it's trustworthy right now, SigNoz decides, based on real telemetry, and LEASH enforces it.\n\nThere are three tiers:\n\nThe agent starts at T3 by default. It stays there as long as its tool calls keep succeeding. The moment failures pile up past a threshold in a 5 minute window, SigNoz's alert fires, hits a webhook on my broker, and the agent gets demoted before it can do anything else destructive.\n\nI split this into four small services instead of one big one, mostly because I wanted the \"agent\" and the \"thing enforcing policy on the agent\" to be genuinely separate processes, not just two functions in the same file pretending to be separate.\n\n`agent-runner`\n\n- the fake release agent. Calls tools like `read_release_notes`\n\n, `apply_migration`\n\n, `delete_staging_table`\n\n.`leash-broker`\n\n- the actual gateway. Every tool call from the agent goes through here first. It checks the current tier, decides allow or deny, and exposes the webhook endpoint SigNoz hits.`migration-tool`\n\nand `resource-tool`\n\n- dumb downstream services doing the actual work, with a flag I can flip to make them start failing on demand.Every one of these is instrumented with the OpenTelemetry Python SDK, shipping spans, metrics and logs straight to SigNoz over OTLP.\n\nThe part I actually spent the most time getting right wasn't the policy logic, it was making sure the span names and attributes told a story on their own. `leash.policy.decision`\n\ncarries the current tier, the required tier, and the verdict. `leash.tool.execute`\n\ncarries the actual call. If you open a trace in SigNoz without reading any of my code, you should be able to tell exactly why a call was allowed or denied just from the span attributes. That's the whole point of doing this with SigNoz instead of just writing decisions to a log file somewhere, the trace itself becomes the evidence.\n\nThis is the one piece where I think a lot of hackathon projects fake it, so I want to be specific about what's real here.\n\nI set up a metric alert on `leash_tool_calls_total`\n\n, filtered to `tool_name = apply_migration`\n\nand `outcome = error`\n\n, aggregated with sum, threshold >= 3, over a 5 minute window. Nothing fancy. When it fires, SigNoz POSTs straight to `http://<host>:18001/webhooks/signoz/demote`\n\nwith a token header I check on my end, and a payload with the agent id and target tier.\n\nGetting the webhook payload shape right on the first try didn't happen. I had to actually trigger a real failure in my migration tool, watch the alert fire in the SigNoz UI, and look at what actually landed on my endpoint before I could write the handler properly. Reading the docs told me alerts could call webhooks. It did not tell me exactly what json I'd get on the other end for my specific alert type. That's the kind of detail you only get by doing it.\n\nOnce the failure budget is burned, the agent tries to call `delete_staging_table`\n\n, which needs T3. LEASH intercepts it and sends back a 403 with a body like this:\n\n```\n{\n  \"error\": \"AUTONOMY_TIER_DENIED\",\n  \"agent_id\": \"release-agent-01\",\n  \"current_tier\": \"T1\",\n  \"required_tier\": \"T3\",\n  \"reason\": \"migration_error_budget_exhausted\",\n  \"trace_id\": \"de4b97f1896593b813ca4cac9e280584\"\n}\n```\n\nThat trace_id isn't decoration. You can take it, paste it into SigNoz, and pull up the exact three failed migration spans that caused the demotion. The agent isn't refused because a prompt told it to behave. It's refused because there's a paper trail of real failures sitting in SigNoz that says it shouldn't be trusted right now.\n\nIf you're instrumenting something similar, don't skip emitting your own decision as a span. It was tempting to just log allow/deny to stdout and move on. But once `leash.policy.decision`\n\nbecame a proper span with its own attributes, I could actually see the whole tier history of an agent run just by looking at one trace waterfall in SigNoz. That single choice made debugging my own policy logic about five times faster, because I wasn't guessing why a call got denied, I was reading it off the span.\n\nAlso, test your alert threshold with real failing calls before you trust it. I originally set my window to 60 seconds and it fired way too eagerly during normal jitter. Bumping it to 5 minutes and requiring 3 consecutive failures instead of 1 made the difference between an alert that's actually meaningful and one that's just noisy.\n\nRight now the tiers are hardcoded per tool. In a real deployment you'd want the risk classification of a tool call to be configurable without redeploying the broker. I also only wired up one alert rule for one failure mode (migration errors). The interesting next step is generalizing this so any metric crossing any threshold can demote any agent, not just this one hardcoded path.\n\nPrompt instructions telling an agent \"don't do destructive things if errors happen\" are not enforcement, they're a suggestion the model can ignore, misread, or get talked out of. What actually enforces something is a system outside the model's control, reading real telemetry, and physically blocking the call. That's what SigNoz's alerts and OpenTelemetry's traces gave me here that a prompt never could.\n\nCode's here if you want to poke at it: [github.com/Vaibhav13Shukla/LEASH](https://github.com/Vaibhav13Shukla/LEASH)\n\nBuilt for the Agents of SigNoz hackathon, Track 1.", "url": "https://wpnews.pro/news/building-an-autonomy-error-budget-gateway-with-signoz-and-opentelemetry", "canonical_source": "https://dev.to/vaibhav_shukla_20/building-an-autonomy-error-budget-gateway-with-signoz-and-opentelemetry-4ia3", "published_at": "2026-07-26 05:38:53+00:00", "updated_at": "2026-07-26 05:59:38.079267+00:00", "lang": "en", "topics": ["ai-agents", "ai-safety", "ai-infrastructure", "developer-tools"], "entities": ["SigNoz", "OpenTelemetry", "LEASH"], "alternates": {"html": "https://wpnews.pro/news/building-an-autonomy-error-budget-gateway-with-signoz-and-opentelemetry", "markdown": "https://wpnews.pro/news/building-an-autonomy-error-budget-gateway-with-signoz-and-opentelemetry.md", "text": "https://wpnews.pro/news/building-an-autonomy-error-budget-gateway-with-signoz-and-opentelemetry.txt", "jsonld": "https://wpnews.pro/news/building-an-autonomy-error-budget-gateway-with-signoz-and-opentelemetry.jsonld"}}