When an agent run goes wrong, the first instinct is to blame the model. Look at the prompt first. Most failed runs we see start with a task that would also have confused a new colleague: a one-line goal, no pointers to the code, no constraints, and no way to tell when it is done.
The fix isn't clever prompting. It is writing the task the way a good ticket is written, with a few details that matter more for agents than for people.
A vague task, and what the agent does with it
Add CSV export to the invoices page.An agent will happily do this. It will pick a CSV library and add it as a dependency, build the file in memory, put the route wherever seems natural, and maybe forget the auth check that every other route has. Each choice is reasonable. Several of them are wrong for your codebase, and you only find out in review.
Five parts of a task an agent can finish
- Goal. The outcome, in terms of what a user or system can do afterwards. Not “add an endpoint” but “an admin can download all invoices for a month as a CSV”.
- Context. Why this is needed, and where the relevant code lives. Point to files, not concepts: the route that is most similar, the helper to reuse, the test file to extend.
- Constraints. What not to do. No new dependencies, don't touch the billing package, keep the public API unchanged. Agents follow explicit limits well and invent their own poorly.
- Done when. Acceptance criteria someone could check. Include the commands that must pass.
- How to verify. What you will do to check it, so the agent can do it first: a request to send, a page to open, a test to run.
The same task, written properly
Goal
Admins can download all invoices for a given month as a CSV.
Context
- Finance exports invoices by hand every month; this replaces that.
- Follow GET /api/invoices in apps/api/src/routes/invoices.ts (same auth, same filters).
- Reuse toCsv() from apps/api/src/lib/csv.ts. Don't add a CSV library.
Constraints
- The route must use requireAuth and the admin role check, like the routes around it.
- Stream the response; a month can have 50,000 invoices.
- Don't change the existing GET /api/invoices response.
Done when
- GET /api/invoices/export?month=2026-10 returns text/csv with one row per invoice.
- Non-admins get 403; logged-out requests get 401.
- pnpm test and pnpm typecheck pass.
How to verify
- Add tests next to invoices.test.ts for: admin, non-admin, logged out, empty month.
- If anything above is unclear or conflicts with the code, ask before writing code.It takes five minutes to write. It saves a round of review, and it turns the review into checking criteria instead of discovering them.
Let the agent plan before it codes
For anything bigger than a small fix, ask for a plan first: which files it will change, in what order, and what it is unsure about. Most agents have a planning mode for this. Reading a ten-line plan takes a minute, and correcting a wrong assumption there is far cheaper than correcting it in a 600-line diff.
The last line of the example matters too. Agents tend to resolve ambiguity by guessing. Telling them that asking is allowed, and expected, changes that.
Size tasks for review, not for the agent
Agents can now handle large tasks. That doesn't make large pull requests a good idea. The real limit is how much a reviewer can check carefully in one sitting. A good rule: one task, one pull request, one thing to verify. If the “done when” list has more than five or six items, it is probably two tasks.
Notice what you keep repeating
After a few weeks of writing tasks like this, you will notice the same lines in every one: use pnpm, every route needs requireAuth, don't edit applied migrations. Those don't belong in tasks. They belong where every agent reads them on every task, in your rule files or shared memory, so each task can focus on what is actually new.
A template to copy
Goal
<what someone can do afterwards>
Context
- <why it is needed>
- <the most similar existing code, as a file path>
- <helpers or patterns to reuse>
Constraints
- <what must not change>
- <dependencies, packages or files that are off limits>
Done when
- <checkable criteria>
- <commands that must pass>
How to verify
- <tests to add, requests to send, pages to open>
- If anything is unclear, ask before writing code.