A downstream service is degraded. Retrying every call keeps the upstream pinned and prevents recovery. Worse, the agent burns tokens on retries that would have failed.
When a tool depends on a single external service that has well-understood failure modes and a viable fallback (a secondary provider, a graceful 'service unavailable' message).
When there is no fallback and the service is critical to the agent's output. Better to surface the failure than to fake a result.
Drop this into an app.yaml. Adjust the credential refs and module names to fit your existing setup.
1schema_version: 223app:4 app_id: circuit-breaker5 name: "Circuit breaker"6 version: "1.0.0"78runtime:9 mode: conversation10 entry_agent: helper11 hooks:12 - id: trip_circuit13 "on": tool_start14 condition:15 type: all_of16 conditions:17 - { type: tool_name, match: "web.fetch" }18 - { type: expression, expr: "session.consecutive_failures.web_fetch >= 3" }19 action:20 type: gate21 reason: "Circuit open for web.fetch: the service failed 3 times in a row. Wait before retrying."2223modules:24 web: {}2526agents:27 - id: helper28 modules: [{web: [fetch]}]29 brain: { provider: anthropic, model: claude-haiku-4-5, credential: { ref: anthropic_main, scope: per_user, provider: anthropic } }30 system_prompt: |31 If a tool call is gated for a circuit being open, do not retry. Tell32 the user the live data is temporarily unavailable.Walking through the YAML one block at a time so the design is clear, not memorised.
The runtime exposes session.consecutive_failures.{tool_name}, tracked natively - no extra module needed to count them.
The condition checks that count before the call is even attempted. Once it reaches three, the gate action blocks the next attempt outright.
The gate's reason string tells the model exactly why the call was blocked, so it can explain the situation to the user instead of retrying blindly.
A successful web.fetch resets the consecutive-failure count to zero, so the circuit closes itself as soon as the service recovers - no manual reset needed.
The pattern above is not the only answer. Here is when something else is the right call.
Classic CB pattern: after the cooldown, allow one request through. If it succeeds, close the circuit; if it fails, reopen for another cycle. Slightly more logic, much smoother under intermittent failures.
Simpler. Costs more in degraded scenarios because every call still tries.
Engineering notes from the Digitorn team. No marketing, no launch announcements, no "10 prompts that will change your life". Just the things we write that we'd want to read.