# How the Circuit Breaker Protects Against Runaway Agents in Munder-Difflin

> Discover how Munder-Difflin's Circuit Breaker prevents runaway agents. Learn how it monitors cost, token velocity, and tool use to automatically stop problematic agent behavior.

- Repository: [Chaitanya Giri/munder-difflin](https://github.com/chaitanyagiri/munder-difflin)
- Tags: deep-dive
- Published: 2026-08-27

---

**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`](https://github.com/chaitanyagiri/munder-difflin/blob/main/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`](https://github.com/chaitanyagiri/munder-difflin/blob/main/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`](https://github.com/chaitanyagiri/munder-difflin/blob/main/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`](https://github.com/chaitanyagiri/munder-difflin/blob/main/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`](https://github.com/chaitanyagiri/munder-difflin/blob/main/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`](https://github.com/chaitanyagiri/munder-difflin/blob/main/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`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/index.ts) with a lazy configuration getter to ensure dynamic threshold updates:

```typescript
// 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:

```typescript
// 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:

```typescript
// 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`](https://github.com/chaitanyagiri/munder-difflin/blob/main/config.json):

```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`](https://github.com/chaitanyagiri/munder-difflin/blob/main/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`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/config.ts), with the system integrated through [`src/main/index.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/index.ts), [`src/main/hooks.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/hooks.ts), and [`src/main/telemetry.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/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`](https://github.com/chaitanyagiri/munder-difflin/blob/main/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`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/breaker.ts), which defines the `CircuitBreaker` class and its `tick()` evaluation method. Integration occurs in [`src/main/index.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/index.ts) (heartbeat orchestration), [`src/main/hooks.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/hooks.ts) (tool and error tracking), [`src/main/telemetry.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/telemetry.ts) (usage sampling), and [`src/main/config.ts`](https://github.com/chaitanyagiri/munder-difflin/blob/main/src/main/config.ts) (configuration definitions).