How to Steer Refactors With Coding Agents

A field guide for engineering students learning to keep agent-led refactors named, bounded, mapped, and proven.


A refactor usually becomes confusing before the code becomes difficult.

At first, the task sounds simple: clean this up, move this logic, replace this pattern, migrate this API, or make this feature easier to understand. Then you open the codebase. One file points to another. Similar names mean different things in different places. The old system still works, the new system is not real yet, and every possible next step feels either too small to matter or too large to trust.

Coding agents make this more intense. They can move quickly, edit many files, and sound confident while doing it. That speed is useful, but only if the human operator keeps the work pointed at the right change.

Your job is not to type every line of code yourself. Your job is to keep the refactor named, bounded, mapped, and proven.

The operator’s job

When you operate a coding agent, you are responsible for the shape of the work.

The agent can search, edit, test, and summarize. It can often find useful paths through a codebase faster than you can manually. But it does not automatically know what level of abstraction you are operating at. It may treat a naming cleanup like a system migration. It may treat a domain redesign like a local refactor. It may preserve compatibility when you meant to rebuild, or rip through old behavior when you needed parity.

Good operators make the invisible parts explicit:

  • What are we changing?
  • What must stay true?
  • What exact slice is in scope right now?
  • What path through the system are we trusting?
  • What pattern fits the migration?
  • What batch of work is safe next?
  • What proof will count as done?

That is the point of the vocabulary in this guide. These terms are not academic decorations. They are handles. They let you stop drift, recover direction, and tell the agent exactly what kind of thinking you need.

The refactor loop

Use this loop whenever a refactor starts to feel broad, fuzzy, or risky:

Target -> Invariant -> Slice -> Map -> Pattern -> Wave -> Proof -> Next

You do not need to say every word every time. The loop is a way to orient yourself.

Target

The target is the change from old shape to new shape.

Weak target:

Clean up the auth code.

Sharper target:

Move auth session validation out of route handlers and into a domain-owned service, while preserving the current HTTP behavior.

The second version gives the agent direction. It says what is moving, where it should go, and what must remain stable.

Invariant

An invariant is something that must remain true during the refactor.

Examples:

  • Existing public API responses must not change.
  • Existing database records must remain readable.
  • Existing login behavior must keep working.
  • Provider-specific payloads must not leak into the domain contract.

Invariants are how you prevent a refactor from becoming an accidental product change.

Slice

The slice is the exact unit in scope right now.

This may be one route, one workflow, one provider lane, one package boundary, or one data shape. A clear slice keeps the agent from touching everything that looks related.

Good operator instruction:

The active slice is only the password login path. Do not edit OAuth, signup, or invitation flows.

Map

The map is the real path through the system.

Before major edits, ask the agent to trace from the entry point to the leaf dependencies. This exposes hidden coupling and prevents imaginary architecture.

Good operator instruction:

Map the password login spine from HTTP route to service layer to database/provider calls. Do not edit yet. Mark confirmed vs inferred links.

Pattern

The pattern is the migration shape that fits the slice.

Some changes need a compatibility window. Some need a temporary adapter. Some need a clean cutover. Some need a new domain contract protected from legacy names.

If you do not name the pattern, the agent may choose one implicitly.

Wave

A wave is a dependency-aware batch of work.

It is bigger than a single edit, but smaller than “finish the whole migration.” A good wave has a clear exit gate.

Good operator instruction:

Propose the next safe wave only. It should be small enough to verify with focused tests before touching the next workflow.

Proof

Proof is concrete evidence that the wave is done.

Proof is not “looks good,” “should work,” or “the code is cleaner.” Proof is a typecheck, a test, a smoke run, a contract check, a screenshot, a log line, or a direct manual verification.

Good operator instruction:

Do not call this done until you can show the exact command or manual check that proves the old login behavior still works.

Next

Next is the next dependency-aware move after proof.

Do not let the agent jump from one wave to another just because it still has momentum. After each wave, ask what became safer, what remains risky, and what should be touched next.

Good prompts are control surfaces

When steering agents, prompts are not just requests. They are control surfaces.

A vague prompt gives the agent too much room to choose the wrong level of work:

Refactor the billing code and make it cleaner.

A sharper prompt controls scope, mode, and proof:

Read the billing invoice creation path first. Do not edit yet.

Bring back:
- the active slice
- the spine map from route to database and provider leaves
- hidden coupling
- invariants we must preserve
- the safest first wave
- the proof needed before edits continue

This does not make the agent less useful. It makes the agent useful in the right direction.

When to pause the agent

You should pause or redirect the agent when the work starts losing shape.

Common warning signs:

  • The agent edits before mapping the path.
  • The agent says “refactor” but cannot name the active slice.
  • The agent introduces an abstraction without explaining the migration pattern.
  • The agent touches adjacent workflows that were not in scope.
  • The agent preserves old naming even though the target is a new domain model.
  • The agent rewrites public contracts without naming the behavioral delta.
  • The agent says the work is done without proof.
  • The agent presents assumptions as confirmed facts.

Useful pause instruction:

Pause. Regroup before editing further.

State:
- the target
- the active slice
- the invariant
- the spine map
- confirmed vs inferred facts
- the blast radius
- the next safe wave
- the proof required before continuing

Reading agent summaries

Agent summaries often sound more complete than they are. Read them like engineering evidence.

When an agent says “updated the auth flow,” ask:

  • Which flow?
  • Which files?
  • Which entry point?
  • Which leaf dependencies?
  • What behavior stayed the same?
  • What behavior intentionally changed?
  • What was verified?
  • What is still assumed?

When an agent says “tests pass,” ask:

  • Which tests?
  • Were they focused or full-gate?
  • Did they cover the invariant?
  • Did they cover the changed contract?
  • Were any checks skipped?

The point is not to distrust the agent. The point is to keep truth status clear.

How to regroup when you feel lost

When the refactor feels fuzzy, do not ask the agent to “continue.” Ask it to regroup.

Use this script:

Pause and regroup. Do not edit yet.

Explain the current refactor state in these terms:

1. Target: what old shape is becoming what new shape?
2. Invariant: what must stay true while we migrate?
3. Active slice: what exact unit is in scope right now?
4. Spine map: what is the confirmed path from entry point to leaf dependencies?
5. Unstable naming: which concepts or terms are still overloaded?
6. Boundary risk: which public, internal, runtime, or data contracts could break?
7. Blast radius: what could fail if this change is wrong?
8. Next wave: what is the next dependency-aware batch of work?
9. Proof: what evidence is required before we call that wave done?

This script turns confusion into a map. It also forces the agent to reveal whether it actually understands the work.

Field glossary

Use this glossary as an operator tool. The most important column is not “Meaning.” The most important column is “When to use it with an agent.”

Orientation terms

TermMeaningWhen to use it with an agentExample agent instruction
TargetThe old shape becoming the new shape.Use when the task sounds like “clean this up” but the destination is unclear.State the target as old shape -> new shape before proposing edits.
InvariantSomething that must remain true during the migration.Use before edits that could accidentally change behavior.List the invariants we must preserve for this slice.
Active sliceThe exact unit currently in scope.Use when the agent is touching too much or the work feels blurry.Name the active slice and keep edits inside it.
Spine mapThe end-to-end trace from entry point to leaf dependencies.Use before edits when you need proof that the agent understands the path.Map the spine from route to database/provider. Do not edit yet.
Tracer bulletA narrow real implementation that proves the target shape.Use when the new architecture is unproven and you need one working path.Build one tracer bullet through the new shape before expanding.
WaveA dependency-aware batch of work with a clear exit gate.Use when the change is too large for one step.Propose the next safe wave and its exit gate.
ProofConcrete evidence, not confident wording.Use whenever the agent says something is done, clean, or working.Show the exact proof for this wave.
Blast radiusWhat could break if this change is wrong.Use before broad edits, public contract changes, or shared utility changes.Identify the blast radius before editing shared code.
ParityBehavior that should stay the same.Use when refactoring internals while preserving external behavior.Define the parity expectations for old and new behavior.

Scope and mapping terms

TermMeaningWhen to use it with an agentExample agent instruction
Entry pointWhere behavior starts from the outside world.Use when tracing a workflow from routes, jobs, commands, UI actions, or webhooks.Start the map at the actual entry point.
Exit pointWhere behavior leaves the system or returns a result.Use when responses, side effects, or emitted events matter.Include the exit point and returned shape in the map.
Leaf dependencyFinal edge dependency such as a database, queue, cache, or external API.Use when you need to know what the workflow ultimately depends on.Trace all leaf dependencies for this slice.
Control flowHow execution moves through the code.Use when the order of calls, branching, or orchestration matters.Separate control flow from data flow in the explanation.
Data flowHow data is transformed and passed.Use when schemas, DTOs, payloads, or domain models are changing.Trace how this payload changes from input to storage/provider call.
Call graphWho calls whom.Use when file structure hides runtime relationships.Build a small call graph for this workflow.
Hidden couplingA dependency or behavior tie not obvious from the file structure.Use when edits in one place unexpectedly affect another.Call out hidden coupling before proposing a wave.
Cross-cutting concernA concern that appears across many places, such as auth, logging, metrics, retries, errors, or transactions.Use when a change appears local but may affect many workflows.Identify cross-cutting concerns touched by this refactor.
Hot pathImportant or high-frequency runtime path.Use when performance, reliability, or user impact is high.Mark whether this slice is on a hot path.
Critical pathThe thing blocking the next move.Use when many tasks are possible but only one unblocks progress.Name the critical path before starting another lane.

Planning and execution terms

TermMeaningWhen to use it with an agentExample agent instruction
Thin sliceThe smallest meaningful unit of change.Use when the agent proposes a broad rewrite.Shrink this into a thin slice with focused proof.
Vertical sliceEnd-to-end path through the system for one capability.Use when you need a real workflow proven across layers.Take one vertical slice from HTTP entry to persistence/provider.
Walking skeletonThe smallest complete end-to-end version of the target system.Use when building a new architecture or replacement path.Create a walking skeleton before filling in all workflows.
LaneOne parallel stream of work.Use when multiple independent areas can move at once.Separate this into lanes and show dependencies between them.
WorkstreamA broader track like auth, billing, storage, or routing.Use for organizing a large migration at a higher level.Group the remaining work by workstream.
CheckpointA deliberate pause to re-evaluate.Use after a wave, before risky edits, or when assumptions changed.Stop at a checkpoint after this wave and report proof.
Exit gateThe condition required before calling a wave done.Use when you want explicit completion criteria.Define the exit gate before implementation starts.
Go / no-goExplicit decision to continue or hold.Use before cutovers, deploys, public contract changes, or large cleanup passes.Bring back a go/no-go recommendation with risks and proof.

Migration pattern terms

TermMeaningWhen to use it with an agentExample agent instruction
Strangler fig patternReplace the old system incrementally behind the same external surface.Use when the system must keep running while ownership moves to a new implementation.Use a strangler approach and keep the public surface stable.
Branch by abstractionAdd an abstraction first, then swap implementations behind it.Use when callers need stability while internals change.Introduce the abstraction only if it reduces real migration risk.
Parallel changeOld and new paths coexist for a while.Use when producers and consumers cannot change at the same time.Plan this as a parallel change with old and new shapes coexisting.
Expand and contractFirst widen compatibility, then remove the old shape later.Use when you need a safe compatibility window.Use expand-and-contract and name the later contraction step.
AdapterWrapper that lets one interface talk to another.Use when you need temporary compatibility between mismatched shapes.Add an adapter at the boundary, not throughout the domain.
FacadeA simpler or more stable surface over a messy subsystem.Use when callers need a clean surface while internals remain complex.Design a facade for callers, then keep messy details behind it.
Anti-corruption layerA boundary that protects the new model from legacy concepts.Use when old naming or provider payloads would pollute the new domain model.Put an anti-corruption layer between provider payloads and the domain contract.
BridgeTemporary connection between old and new systems.Use when two systems must talk during migration.Identify the bridge and when it can be removed.
Compatibility windowPeriod where both old and new shapes are supported.Use when clients, data, or deploys cannot all switch at once.Define the compatibility window and its removal condition.
CutoverMoment traffic or ownership moves to the new path.Use when switching runtime behavior from old to new.Do not cut over until the proof and rollback point are clear.
Rollback pointSafe point to retreat to if the new path fails.Use before risky runtime or deploy changes.Name the rollback point before making the cutover.

Domain-shaping terms

TermMeaningWhen to use it with an agentExample agent instruction
Domain taxonomyThe clean set of concepts and distinctions inside the domain.Use when naming is blurry or the model is being redesigned.Clean up the domain taxonomy before proposing implementation waves.
Overloaded conceptOne word or type being used for multiple responsibilities.Use when the same name means different things in different places.Find overloaded concepts and propose clearer names.
Canonical namingThe final agreed names for important concepts and surfaces.Use before wide renames or schema/API work.Lock canonical names before editing contracts.
Ubiquitous namingShared naming used consistently across the whole refactor.Use when different layers use competing terms for the same concept.Align the naming across route, service, schema, and provider layers.
Workflow boundaryExact start and end of one owned workflow.Use when a capability is bleeding into unrelated responsibilities.Define the workflow boundary before splitting files or services.
Gateway surfaceNarrow outbound interface for talking to an external system.Use when provider calls are scattered through domain code.Move provider calls behind a gateway surface.
Repository surfaceNarrow persistence-facing interface for stored data.Use when database access is mixed into orchestration or transport code.Keep persistence behind a repository surface for this domain.
Domain-owned contractContract defined by the domain’s needs, not by a provider payload.Use when external APIs are shaping internal models too strongly.Define the domain-owned contract first, then adapt provider payloads into it.
Provider-lane auditRead-only validation pass checking whether domain contracts fit real provider leaves.Use before committing to a provider abstraction or contract.Audit each provider lane against the proposed domain contract before editing.

Safety and verification terms

TermMeaningWhen to use it with an agentExample agent instruction
Behavioral deltaIntentional change from old behavior.Use when behavior changes may be mixed with refactoring.Separate intentional behavioral deltas from pure refactor changes.
Characterization testTest that captures current behavior before refactoring internals.Use when old behavior is important but poorly specified.Add a characterization test before changing this path.
Regression testTest proving a known break does not return.Use after fixing a bug or risky edge case.Add a regression test that fails on the old bug.
Contract testTest verifying the agreement between two components or systems.Use around APIs, provider boundaries, schemas, SDKs, or persistence contracts.Add or update contract tests for this boundary.
Golden masterSnapshot or output comparison used to detect unexpected change.Use when behavior is complex and exact output parity matters.Use a golden master if direct assertions would miss output drift.
Smoke testBasic alive check.Use after wiring, deploys, or broad runtime changes.Run a smoke test that proves the path is alive.
CanaryLimited rollout to detect issues before full rollout.Use when production risk is high and gradual rollout is possible.Plan a canary before full rollout.
Feature flagRuntime control over new behavior.Use when you need to enable, disable, or gradually expose a new path.Put the new behavior behind a feature flag if runtime rollback matters.
Shadow trafficMirrored traffic used to compare old and new paths.Use when validating a new path without serving its result yet.Consider shadow traffic to compare old and new outputs before cutover.

Architecture and boundary terms

TermMeaningWhen to use it with an agentExample agent instruction
BoundaryOwnership edge between systems, modules, or layers.Use when deciding where code or contracts should live.Name the boundary this change crosses.
Bounded contextArea where a domain model is coherent.Use when the same term should not mean the same thing everywhere.Identify the bounded context before standardizing names globally.
Composition rootPlace where dependencies are wired together.Use when dependency wiring is scattered or unclear.Keep dependency wiring in the composition root.
Public contractExternal interface other systems rely on.Use before API, SDK, webhook, schema, or CLI changes.Treat this as a public contract and preserve compatibility unless told otherwise.
Internal contractTeam-owned interface inside the system.Use when changing boundaries that are not externally exposed.Mark which contracts are internal and can change together.
Runtime boundaryProcess, service, network, or deployment edge.Use when behavior crosses services, workers, queues, or deployed systems.Call out every runtime boundary in this workflow.
CohesionRelated things staying together.Use when deciding whether to split or merge modules.Improve cohesion without creating a wider public surface.
CouplingHow tightly pieces depend on each other.Use when changes in one place force changes elsewhere.Identify the coupling this refactor reduces or increases.
LayeringSeparation between transport, domain, persistence, integration, and runtime concerns.Use when responsibilities are mixed together.Separate transport, domain, persistence, and provider concerns in the target shape.

Decision and status terms

TermMeaningWhen to use it with an agentExample agent instruction
ConfirmedDirectly verified.Use when you need evidence-backed statements.Mark only directly verified facts as confirmed.
InferredStrong conclusion but not directly proven.Use when the agent is reasoning from code shape but has not verified runtime behavior.Separate inferred facts from confirmed facts.
UnknownNot established yet.Use when missing information should not be hidden.List unknowns that could affect the implementation plan.
AssumptionTemporary working belief used to keep moving.Use when progress requires a guess.State assumptions explicitly and say how to verify them.
ConstraintRule the solution must obey.Use when scope, compatibility, performance, security, or product requirements limit choices.List constraints before choosing an approach.
RiskPlausible failure mode.Use before risky edits, deploys, migrations, or public contract changes.Name the top risks and how the wave reduces them.
TradeoffGain in one area at a cost in another.Use when there is no perfect option.Explain the tradeoff, not just the recommendation.
BlockerSomething that must be resolved before continuing.Use when the next step is unsafe or impossible without more information.Identify blockers separately from nice-to-have cleanup.
Out of scopeExplicit non-goal.Use when the agent keeps expanding the task.State what is out of scope for this wave.
Decision ownerPerson who must choose when ambiguity remains.Use when technical exploration cannot resolve product or risk ambiguity.If this requires a product decision, identify the decision owner and options.

The short version

If you remember only one thing, remember this:

Do not let the agent continue a fuzzy refactor.

Ask for the target, invariant, active slice, spine map, next wave, and proof.

Those six things will rescue most drifting refactors.