Field note: hand the agent a failing test as the target, not a prose spec

Field note: hand the agent a failing test as the target, not a prose spec

After a lot of background-agent and agent-mode runs, the single biggest lever on “did it actually do the thing” for me hasn’t been a better prompt — it’s been what I hand it as the definition of done.

Prose specs (“add validation so empty names are rejected”) leave the finish line fuzzy. The agent writes something, it looks plausible, and I’m the one who has to figure out whether it’s right. When I instead write (or ask it to write first) a failing test that encodes the requirement, the whole run tightens up:

  • The target is now executable. “Done” = the test goes green, not “the diff looks reasonable.”
  • The agent can self-check in the loop instead of handing me a guess to verify.
  • Scope stays bounded — it changes what it needs to make the test pass, and I notice fast when it starts editing unrelated files to force a green.

The workflow that’s been reliable:

  1. Red first. Either write the failing test myself, or ask the agent for just the test and confirm it fails for the right reason before it touches implementation. (A test that passes immediately is testing nothing — or the behavior already exists.)
  2. Then implementation, test as the target. “Make this test pass without weakening it” is a far crisper instruction than the prose version.
  3. Guard the cheat. Agents will sometimes “pass” by editing the assertion or adding an early return that special-cases the fixture. I keep the test file out of the editable set for the implementation step, or diff it explicitly at the end.

Two failure modes I watch for:

  • Over-fitting to the one case. One example test → an implementation that only handles that literal input. A second test with a different shape usually forces the general solution.
  • The test that can’t fail. If I can’t get it to go red first, I don’t trust the green — it’s asserting nothing useful.

None of this is novel TDD, but agent mode makes the payoff sharper: an executable target is something the model can close the loop on itself, which is exactly the part you don’t want to be doing by hand on every run.

Anyone leaning on background agents — do you front-load a failing test, or drive from prose and review after? Curious what’s holding up for longer/multi-file tasks.