Designing an Agent You Can Redirect Mid-Run

Twelve files into forty, you realize the approach is wrong. Let it finish or kill it — both bad, and the third option had to be designed in before the run started.

A refactor agent is twelve files into a forty-file migration when you realize the approach is wrong — it should be using the adapter pattern, not threading the new parameter through every call site.

Two options present themselves. Let it finish and throw away forty files of work, or kill it and throw away twelve. Both are bad, and the third option isn't available at that moment. It's a design decision made before the run started.

Stopping and steering are different mechanisms

A kill switch answers stop safely. Steering answers change what you're doing without discarding what you've done. They share one thing — a check between steps — and diverge everywhere else.

Stopping needs a flag and a graceful halt. Steering needs the run to have a mutable goal, durable completed work, and a defined policy for what happens to work that no longer fits the new goal.

The four properties that make a run steerable

1. A mailbox checked at item boundaries. The loop polls for pending instructions in the same place it checks the stop flag — between work items, never mid-item.

2. Work modelled as items with states. Steering is only meaningful if "finish the current one and stop" and "keep the done ones" mean something concrete.

3. The goal held in loop state, not in the transcript. The current objective is regenerated into context each turn from a mutable structure. ⚠️ If the goal lives only in the conversation history, a redirect competes with the original instruction still sitting there, and the original usually wins — the model reads a clear early statement of intent and a later correction buried among tool results.

4. Committed, idempotent work per item. Each finished item durable on its own, so redirection never costs you the completed ones.

The three redirects, and why they differ

They arrive looking similar and have completely different consequences for work already done.

Amend"also update the tests for each file you touch." The goal grows. Pending items get the new requirement; completed items are now incomplete against the new goal. Policy needed: reprocess the done ones, or apply the addition only from here on and report the gap.

Narrow"only the billing module." The goal shrinks. Drop the pending items outside the new scope; completed items outside it are already done and harmless. Simplest case, and the one that needs the least policy.

Replace the approach"use the adapter pattern instead." → The dangerous one. Pending items are straightforward; the twelve completed files were done the old way, and the run now has two incompatible styles in one changeset.

This needs an explicit decision, requested from the human rather than guessed:

redirect(type="replace_approach",
         instruction="use the adapter pattern",
         completed_policy="revert" | "keep" | "redo")
  • revert — undo the twelve, restart with the new approach. Clean, and discards real work.
  • keep — leave them, accept a mixed codebase, flag it. Sometimes right if the twelve are independently correct.
  • redo — reprocess the twelve with the new approach, leaving the rest.

Without that field the agent picks one silently, and half-and-half changesets are the result.

In the loop

for item in ledger.pending():
    if msg := mailbox.poll():          # boundary only
        ledger.apply_redirect(msg)      # mutates goal + item states
        log_redirect(msg)
        continue                        # re-evaluate what's pending

    result = process(item, goal=ledger.goal)   # goal from state, not history
    if verify(result):
        ledger.complete(item, commit(result))
    else:
        ledger.quarantine(item, reason)

Two details carry the design. poll() sits before the work, so a redirect never lands mid-item. goal=ledger.goal is regenerated each iteration, so the current objective is always the one in state.

⚠️ Where this goes wrong

Redirecting mid-item. Half a file transformed, in a state neither approach expects. Boundaries only, always.

Letting the transcript carry the old goal. The most common failure and the least obvious. If prior turns still contain the original instruction verbatim, the agent drifts back toward it — rebuild context from state rather than appending the correction.

No policy on completed work. Covered above, and it's the one that produces the worst artifact.

Unbounded redirects. Each one re-plans and re-reads. Cap them per run, and treat a run that's been redirected four times as a signal the task wasn't ready to start.

🔍 What to log

Every redirect: the timestamp, the type, the instruction, which items were dropped or requeued, and the completed-work policy applied. A changeset that mixes two approaches is very hard to explain afterwards without that record — and the record is also how you notice that a particular kind of task keeps getting redirected, which is a specification problem rather than a steering one.

✅ When not to build this

The machinery has a real cost, and it's wasted on:

  • Runs under a minute. Cancel and restart.
  • Runs with no durable intermediate work. Nothing to preserve, so stopping is sufficient.
  • Single-item tasks. There are no boundaries to redirect at.

It earns its place for long multi-item runs where the work is expensive and a human is watching — migrations, batch processing, long investigations.

The takeaway

Steering is not a bigger kill switch. It needs a mutable goal in loop state, work modelled as items with durable completions, a mailbox polled only at item boundaries, and an explicit policy for what happens to work done under the old goal. Amend, narrow, and replace-approach have different consequences and the third one must ask rather than assume — otherwise the run's output is a changeset built two different ways, and nobody can tell which half to trust.

Keep reading

Similar posts

Matched on shared tags and category — the more bars, the stronger the overlap with what you just read.