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 hardStop flag 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: repeatCount exceeds repeatedToolLimit (default 8).
  • Action: Escalate to steer, assuming the agent is stuck in a tool loop.

API-Error Storms

  • Trigger: errorCount reaches errorStormLimit (default 5).
  • Action: steer to break unproductive retry loops.

Per-Agent Token Caps

  • Trigger: Agent tokens exceed agentTokenCaps[agentId].
  • Action: steer to cap individual agent consumption.

Floor-Wide Cost Caps

  • Trigger: Total USD cost exceeds costCapUsd and the agent is the top spender.
  • Action: steer to isolate the highest spender.

Floor-Wide Token Caps

  • Trigger: Total tokens exceed costCapTokens and the agent is the top consumer.
  • Action: steer to throttle the primary resource user.

Token-Velocity Spikes

  • Trigger: Output tokens per minute exceed tokenVelocityPerMin (default 60,000).
  • Action: steer to intercept suspicious output bursts.

No-Progress Detection

  • Trigger: No file-mtime change and no distinct tool call within 5 minutes for NO_PROGRESS_BEATS consecutive beats (default 2).
  • Action: steer when agents generate tokens without coordinating.

Hard Stop

  • Trigger: hardStop flag enabled in configuration.
  • Action: Direct escalation to stopped state, 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-difflin is implemented in src/main/breaker.ts as 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 CircuitBreakerConfig in src/main/config.ts, with the system integrated through src/main/index.ts, src/main/hooks.ts, and src/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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →