The Mode Controller¶
Failure-driven transitions between tool configurations. Specified rules, not trained judgment.
The problem¶
The agent starts with a tool configuration and keeps it for the entire task. If it’s wrong — too many tools, wrong tools, missing tools — the agent grinds through with what it has. The Harness doesn’t notice. The human notices after the budget is spent.
The pattern¶
A controller that watches the tool call stream and switches modes when failure patterns indicate the current configuration isn’t working.
What modes look like¶
Mode |
Available tools |
Read scope |
Write scope |
When to use |
|---|---|---|---|---|
Debug |
Read, Search, Glob, RunTests |
Everything |
Nothing |
Diagnosing failures |
Implement |
Read, Edit, Write, RunTests |
Everything |
src/ only |
Fixing code |
Test-dev |
Read, Edit(tests/), Write(tests/) |
Everything |
tests/ only |
Writing tests |
Review |
Read, Search, Glob |
Everything |
Nothing |
Assessing code |
Transition triggers¶
Mode transitions are driven by failure patterns — specified thresholds over specified counters. No trained judgment in the transition logic.
if consecutive_edit_failures > 3:
switch_to("debug") # stop editing, start diagnosing
if turns_without_progress > 10:
switch_to("debug") # agent is spinning, force re-assessment
if tests_passing and edits_complete:
switch_to("review") # implementation done, verify
if test_coverage_gap_detected:
switch_to("test-dev") # need tests before more implementation
The test boundary¶
In implementation mode, tests are read-only. In test-dev mode, source is read-only. At no point does the agent have simultaneous write access to both. This prevents the agent from resolving a failing test by changing the test — a natural optimization target that produces correct-looking but incorrect systems.
The grade analysis¶
The mode controller is System 3 in Beer’s Viable System Model — operational control. It monitors performance and reallocates resources. It’s specified: the transition rules are readable, auditable, enumerable. No trained judgment in the controller itself.
The controller changes W (what tools are available) and therefore d_reachable (what paths the agent can take). But it changes them in response to observed patterns, not in advance. It’s reactive, not predictive.
Connection to the experiments¶
We didn’t implement a mode controller in our experiments. But the data shows where it would help:
Haiku/A (40% pass): The agent wastes turns editing before understanding. A controller that forces debug mode for the first 10 turns would prevent this — matching what the Strategy Instruction achieves through prompting.
Opus/I (85% pass): The agent over-analyzes. A controller that switches from debug to implement after 10 turns of read-only activity would prevent the turn-cap timeout.
Sonnet/E (100%, cheapest): The agent self-selects efficiently. The controller would rarely intervene — confirming that Sonnet doesn’t need external control for this task.
Implementation¶
Detailed in Ratchet Fuel post 4 (blog/fuel/04-the-failure-driven-controller.md). The controller uses counters (consecutive failures, turns without progress, success rate) with specified thresholds for transitions.
Integration points:
blq: The mode controller monitors blq’s event stream for build/test failures
jetsam: Mode transitions trigger jetsam workflow state changes (save, sync, finish)
Fledgling: Different Fledgling tool publications per mode (Code Navigation kit in debug, full kit in implement)
The anti-pattern: LLM-backed mode selection¶
Using a language model to decide when to switch modes puts System 4 (trained intelligence) where System 3 (specified control) should be. The mode controller’s decisions must be readable, predictable, and auditable. If you need an LLM to decide whether to switch modes, your mode definitions are wrong — make the modes clearer so specified rules suffice.