How the Circuit Breaker Protects Against Runaway Agents in Munder-Difflin
The Circuit Breaker in Munder-Difflin is a stateless policy module that guards against runaway agents by monitoring cost, token velocity, and tool-use patterns, automatically escalating from steering messages to hard stops when agents exhibit looping behavior or resource spikes.
The chaitanyagiri/munder-difflin repository implements this protection as a pure policy module in src/main/breaker.ts, ensuring the Circuit Breaker protects against runaway agents through continuous heartbeat evaluation. It aggregates telemetry signals to detect token-velocity spikes, repeated tool loops, and budget violations, maintaining system stability while remaining stateless aside from per-agent bookkeeping.
Signal Sources and Monitoring Architecture
The Circuit Breaker aggregates three distinct signal types during each heartbeat cycle to assess agent health comprehensively.
UsageProvider Telemetry
The UsageProvider (src/main/telemetry.ts) feeds cumulative usage snapshots containing tokens in/out, USD cost, and timestamps. The breaker uses this data to detect token-velocity spikes, enforce floor-wide cost and token caps, and apply per-agent token limits. This signal ensures financial and computational budgets remain within configured boundaries.
Hook Events
The HookServer (src/main/hooks.ts) reports granular execution metadata including repeated identical tool calls, API-error storms, and compaction events. These hooks enable the breaker to identify loop detection (repeated tool patterns) and error-storm detection (unproductive retry loops), while providing exemptions during compaction phases.
File Modification Progress
The system tracks file-mtime progress via a beat flag that checks whether an agent has recently updated a coordination file. This detects no-progress situations where an agent generates tokens without coordinating work, indicating a potential runaway generation loop.
The Four-State Escalation Ladder
In src/main/breaker.ts, the CircuitBreaker.tick() method evaluates incoming signals and escalates agent states along a severity ladder. Only one level changes per beat, ensuring gradual escalation and symmetrical de-escalation when signals clear.
The four states are:
- healthy — Normal operation with no restrictions.
- steering — The breaker emits a
"Circuit breaker: steer"message directing the agent to summarize and pause. - constrained — A
"Circuit breaker: constrain"message forces stricter pauses and token-budget tightening. - stopped — (Optional) A hard stop that kills the agent when the
hardStopflag is enabled.
Escalation actions are exposed through the BreakerAction enum (steer, constrain, stop) and enforced by the heartbeat runner in src/main/index.ts.
Protection Mechanisms and Trigger Conditions
The Circuit Breaker activates specific protection mechanisms based on configurable thresholds defined in CircuitBreakerConfig (src/main/config.ts).
Repeated Identical Tool Calls
- Trigger:
repeatCountexceedsrepeatedToolLimit(default 8). - Action: Escalate to
steer, assuming the agent is stuck in a tool loop.
API-Error Storms
- Trigger:
errorCountreacheserrorStormLimit(default 5). - Action:
steerto break unproductive retry loops.
Per-Agent Token Caps
- Trigger: Agent tokens exceed
agentTokenCaps[agentId]. - Action:
steerto cap individual agent consumption.
Floor-Wide Cost Caps
- Trigger: Total USD cost exceeds
costCapUsdand the agent is the top spender. - Action:
steerto isolate the highest spender.
Floor-Wide Token Caps
- Trigger: Total tokens exceed
costCapTokensand the agent is the top consumer. - Action:
steerto throttle the primary resource user.
Token-Velocity Spikes
- Trigger: Output tokens per minute exceed
tokenVelocityPerMin(default 60,000). - Action:
steerto intercept suspicious output bursts.
No-Progress Detection
- Trigger: No file-mtime change and no distinct tool call within 5 minutes for
NO_PROGRESS_BEATSconsecutive beats (default 2). - Action:
steerwhen agents generate tokens without coordinating.
Hard Stop
- Trigger:
hardStopflag enabled in configuration. - Action: Direct escalation to
stoppedstate, terminating the agent.
Implementation and Integration
Instantiating the Circuit Breaker
The breaker is instantiated in src/main/index.ts with a lazy configuration getter to ensure dynamic threshold updates:
// src/main/index.ts
const breaker = new CircuitBreaker(() => {
const c = readConfig();
return {
...(c.circuitBreaker ?? {}),
costCapUsd: c.costCapUsd,
costCapTokens: c.costCapTokens,
agentTokenCaps: c.agentTokenCaps,
};
});
This pattern ensures configuration changes take effect on the next heartbeat without restarting the service.
Feeding Activity Signals
The HookServer and telemetry system feed real-time data into the breaker:
// HookServer records tool use and errors
breaker.recordToolUse(agentId, toolName, toolInput);
breaker.recordError(agentId);
// Telemetry feeds cost-cap and error-storm signals
telemetry.onApiError(agentId => breaker.recordError(agentId));
The Evaluation Loop
Each heartbeat tick evaluates accumulated signals and returns intervention decisions:
// Heartbeat (called once per beat)
const decisions = breaker.tick(breakerInputs, Date.now());
decisions.forEach(d => {
if (d.changed) {
// Send corrective message to the agent
hive.send({
to: d.state.agentId,
act: 'request',
subject: `Circuit breaker: ${d.action}`
});
}
});
Intervention only occurs when action is non-none, preventing unnecessary system chatter.
Configuring Thresholds
Thresholds are customizable via config.json:
{
"circuitBreaker": {
"enabled": true,
"hardStop": false,
"repeatedToolLimit": 8,
"errorStormLimit": 5,
"tokenVelocityPerMin": 60000
},
"costCapUsd": 100,
"costCapTokens": 500000,
"agentTokenCaps": {
"agent-xyz": 250000
}
}
Summary
- The Circuit Breaker in
chaitanyagiri/munder-difflinis implemented insrc/main/breaker.tsas a stateless policy module that evaluates agent health on every heartbeat. - It monitors three signal types: UsageProvider telemetry, HookServer events, and file-mtime progress to detect runaway behavior.
- Agents escalate through four states—healthy, steering, constrained, and stopped—with only one level change per beat to ensure stability.
- Protection triggers include repeated tool calls (≥8), error storms (≥5), token-velocity spikes (>60,000/min), and no-progress conditions (2 consecutive beats).
- All thresholds are configurable via
CircuitBreakerConfiginsrc/main/config.ts, with the system integrated throughsrc/main/index.ts,src/main/hooks.ts, andsrc/main/telemetry.ts.
Frequently Asked Questions
What triggers the Circuit Breaker to stop an agent?
The Circuit Breaker stops an agent only when the hardStop configuration flag is enabled and the agent reaches the stopped escalation state. By default, the system uses steering and constraining actions to redirect agents rather than terminate them, escalating gradually through the state ladder as violations persist.
How does the Circuit Breaker handle gradual escalation?
The CircuitBreaker.tick() method enforces single-level escalation per beat, meaning an agent moves from healthy → steering → constrained → stopped sequentially. This prevents abrupt interruptions while allowing the system to de-escalate symmetrically when violation signals clear, maintaining stability during transient spikes.
Can the Circuit Breaker thresholds be customized?
Yes, all protection thresholds are configurable through CircuitBreakerConfig in src/main/config.ts. Users can adjust repeatedToolLimit, errorStormLimit, tokenVelocityPerMin, costCapUsd, costCapTokens, and per-agent caps via the configuration object passed to the breaker constructor, with changes taking effect on the next heartbeat cycle.
Where is the Circuit Breaker logic implemented in the codebase?
The core logic resides in src/main/breaker.ts, which defines the CircuitBreaker class and its tick() evaluation method. Integration occurs in src/main/index.ts (heartbeat orchestration), src/main/hooks.ts (tool and error tracking), src/main/telemetry.ts (usage sampling), and src/main/config.ts (configuration definitions).
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →