Agent Engineering
Module 04 · Fundamentals/Lesson 4.5/3 min

Feedback loops

The single biggest multiplier: give the agent a way to find out it is wrong without asking you.

An agent that can run your checks operates in a loop: write, verify, correct, repeat — without a round trip through you. An agent that cannot hands you unverified code and makes you the test runner. The difference in throughput is not marginal.

The three tiers

TierSpeedCatches
Types / compilerSecondsInvented APIs, wrong shapes, missed cases. The best return on effort by a wide margin.
Lint / formatSecondsConvention drift — encoded once, enforced forever, with no context cost.
TestsSeconds to minutesBehaviour. The only tier that catches "it compiles and is wrong".

Make the loop explicit

Do not assume the agent will verify. Say it, every time, until it is in your standing instructions:

prompt
Implement it, then run 'npm run check'. If it fails, fix it and run again.
Repeat until clean. Only then report back, and include the final output.
If you cannot get it clean after three attempts, stop and tell me what is
failing rather than working around it.

That last sentence matters more than it looks. Without it, an agent stuck on a failing check will start doing damage to make the check pass: widening a type, deleting an assertion, adding an ignore comment. The instruction gives it a legitimate exit.

Make failures readable

Agent-facing output should be short and precise. Long stack traces are context-expensive (Lesson 2.7) and bury the signal.

  • Fail fast — stop at the first failure rather than reporting forty.
  • Suppress progress bars, colour codes, and passing-test noise.
  • Prefer error messages that name the fix. A custom assertion saying "expected a Money object, got a number — use Money.from()" is worth more than a generic type error.

Loops for things without tests

Not everything has a test tier. Build cheap proxies:

  • UI: have the agent take a screenshot and look at it, if your harness supports it; otherwise a snapshot test of the rendered markup.
  • Scripts: a dry-run flag that prints what would happen.
  • Data work: assertions on row counts and invariants, run against a sample.
  • Performance: a benchmark with a threshold, so "faster" is checkable rather than claimed.

Watch out

A loop the agent can satisfy dishonestly is worse than no loop, because it produces confident green output. Watch specifically for deleted assertions, skipped tests, widened types, and new ignore comments — put all of them in the danger-grep from Lesson 3.3.

Try it

Time your check command. If it is over sixty seconds, build a faster subset that covers the files being changed. Then run a task with the fast loop and watch how many times the agent runs it unprompted. That count is the number of round trips you no longer have to make.

Takeaways

  • Types and lint are the cheapest, fastest tiers; invest there first.
  • Always give the agent an explicit exit when checks will not go green.
  • Watch for loops satisfied dishonestly — skipped tests, widened types, ignore comments.
Why include "stop and tell me rather than working around it"?

Because the agent’s objective is a passing check, and if the honest path is blocked it will find a dishonest one: a skip, an ignore, a weakened type. An explicit escape hatch makes reporting failure an acceptable outcome, which is what you actually want.

A course by Pieter Zandbergen