AI

Evals before vibes: a tiny benchmark for my agent

Thirty hand-written tasks, chance-corrected scoring, and one rule: no feature ships until the number moves.

L Lagom •Aug 30, 2026 •3 min read •★ 154 likes

For months I "improved" my coding agent the way everyone does: change a prompt, run it on the thing I happened to be doing, and nod sagely if the output felt better. This is not evaluation. This is astrology with extra steps. The output always feels better right after you've changed something, because you are the person who changed it.

So I made a rule: no feature ships until a number moves. Which meant I first needed a number. This post is about building the smallest benchmark that could possibly earn my trust.

Thirty tasks, all mine

Public benchmarks measure public things. My agent fails on my things: my repos, my conventions, my weird build system. So every task is hand-written from a real failure I actually hit, frozen with its full context:

AreaTasksWhat it probes
Code navigation8Find the right file/function from a vague description
Refactoring6Multi-file changes that must not break the tests
Memory recall6Use a fact learned earlier in the session, unprompted
Tool use5Pick the right tool, not the familiar one
Honesty5Admit missing context instead of inventing it

Thirty is not a typo. Thirty tasks that each encode a real failure beat three thousand scraped ones that don't. Grading a run takes me about twenty minutes, which is exactly cheap enough that I actually do it.

Chance-corrected, or it doesn't count

Several tasks are multiple-choice-ish (pick the right file out of five, say). Raw accuracy flatters you there — a coin-flipping agent scores 20% for free. So every task is rescaled so that zero means guessing and 100 means perfect:

normalize.py
def chance_corrected(raw, chance):
    # raw: observed success rate on the task
    # chance: what blind guessing would score
    return 100 * (raw - chance) / (1 - chance)

This one line changed my opinion of my own agent more than any feature ever has. A proud-looking 62% on file-finding collapsed to 52 after correction; the honesty tasks, where chance is roughly zero, turned out to be the real weak spot.

What the first run revealed

  • Navigation: 74. Better than me on unfamiliar corners of my own repo. Humbling in the other direction.
  • Refactoring: 58. Fine on mechanical renames, shaky the moment two files disagree about an interface.
  • Memory recall: 31. Ouch. Facts stated an hour earlier might as well be on another planet.
  • Honesty: 22. The agent would rather invent a config key than say it can't find one — the exact disease the abstention post treats at the model level.

Two features I'd been excited about — a fancier planning prompt and a reranking step — moved the composite by less than a point each. Both deleted. One boring feature (quoting retrieved snippets verbatim instead of paraphrasing) moved memory recall from 31 to 49. Shipped the boring one. That is the entire point of the rule.

!

Keep it private

The moment a benchmark becomes a target it stops being a measurement. Mine lives in a private repo, and when a task saturates I retire it and write a new one from the next real failure. Goodhart is patient; be more patient.

A benchmark is a promise you make to your future self: I will not be charmed by my own changes.

This is part 1 of 3. Part 2 (the harness: running thirty tasks without losing a Saturday) and part 3 (regression hunting) are in the drafts pile — two of the famous 57 will eventually make it out.

Written by Lagom

I build small tools, stress-test larger models, and take notes so future-me has receipts. More posts — and the occasional abandoned draft — under the blog, or find me via the about page.