Planning a task the agent can actually finish
ost coding agents fail on the plan, not the code. If you can turn your fuzzy “do the thing” request into a tight, 4-part task spec, modern agents can usually finish the work in one pass. And ship changes you’re willing to merge.
Finishable Agent Task Loop
- Spot starting leveldefine
- Four-part task specfit
- Right-size scoperun
- Read feedback signalsrewrite
- Tighten and retrycheck
- Review and mergenext task
Article mapOpen the visual summary
Finishable Agent Task Loop
- Spot starting leveldefine
- Four-part task specfit
- Right-size scoperun
- Read feedback signalsrewrite
- Tighten and retrycheck
- Review and mergenext task
Table of Contents10 sections
- What you’ll be able to do· 1 min
- Why agents mostly fail on ambiguity, not ability· 1 min
- Spot your starting level· 1 min
- The four-part agent task spec· 1 min
- Right-sizing: what “under 30 minutes” really means· 1 min
- First attempt: rewrite a vague task into a finishable spec· 2 min
- Reading the results: good vs poor feedback signals· 2 min
- Retry: tightening scope, constraints, and verification· 1 min
- When to plan yourself vs let the agent plan· 1 min
- Reviewing and merging agent-written code· 1 min
What you’ll be able to do
- Define agent tasks using a four-part spec so they reliably end in complete, mergeable changes.
- Right-size work into chunks an agent can handle in one pass—roughly under 30 minutes of human effort.
- Write concrete verification steps (tests, commands, manual checks) that guide the agent toward done, not “almost there.”
- Decide when you should plan the steps yourself versus delegating planning to the agent.
Why agents mostly fail on ambiguity, not ability
You’ve probably seen this pattern: you ask the agent to “add rate limiting to the API,” it edits five files, breaks two tests, and leaves you with a half-finished refactor.
The problem usually isn’t that the agent can’t write the code. It’s that the task is underspecified: scope is fuzzy, constraints are implicit, and “done” isn’t defined beyond your head.
Modern coding agents are very good at following a crisp plan and surprisingly bad at guessing your intent from a one-sentence wish. When they guess wrong, they still sound confident, so you only notice the problems when you try to run or review the change.
If you tighten the plan, the same agent can often produce a small, correct PR on the first try. This article is about how to write that plan in a repeatable way.
Spot your starting level
Before changing your workflow, locate how you already use agents. Different starting points need different adjustments.
Scan these patterns and pick the one that feels closest:
- Level 1: ChatGPT-style helper
- You mostly paste snippets into chat, ask “what’s wrong?”, and copy back fixes by hand. You rarely let the agent touch the repo directly.
- Level 2: Local editor assistant
- You use inline completions or simple edits ("extract this function", "rewrite for readability") but big changes still feel risky. Outputs are often partial or off in style.
- Level 3: Repo-aware agent
- You run agents that read the project, propose patches, or open PRs. Sometimes they nail it, sometimes they wander or leave things half done.
This guide assumes you’re at Level 2 or 3. If you’re at Level 1, you can still apply the same task spec, but you’ll paste the plan and diffs manually instead of pressing an “agent mode” button.
The four-part agent task spec
Size
The intended complexity / time box.
Verification
How we’ll decide it’s done.
Constraints
How it must be done or what it must respect.
Scope
What changes, in one clear sentence.
A task the agent can finish has four parts:
- 1Scope: What changes, in one clear sentence.
- 2Constraints: How it must be done or what it must respect.
- 3Verification: How we’ll decide it’s done.
- 4Size: The intended complexity / time box.
Think of this as a micro design doc you write in 2-3 minutes before invoking the agent.
Here’s a minimal template you can adapt:
Goal / scope: <one-sentence outcome the code should achieve>
Context: <1-3 sentences or a quick bullet list of relevant files, data flows, or existing behavior>
Constraints:
- <any required APIs, patterns, performance or security constraints>
- <any files or areas that must not change>
Verification:
- Automated: <specific tests or test commands that should pass>
- Manual: <explicit steps with inputs + expected outputs>
Size / limits:
- Target: roughly <N> lines / <under 30 minutes> of human work
- If this is too large, stop and propose how to split it.
We’ll use this template in a moment on a concrete example. First, you need a feel for what “under 30 minutes” looks like in practice.
Right-sizing: what “under 30 minutes” really means
"Let the agent implement user profiles" is not a single task. A human can’t do that in 30 focused minutes, and neither can an agent.
You want tasks that are closer to:
- “Add server-side validation that username is 3-20 chars, alphanumeric plus underscore, and show a friendly error on the profile form.”
For most back-end or full-stack work, under 30 minutes of human effort usually means:
If you struggle to describe the change crisply, the task is too big. Split by:
Agents chain well across multiple small tasks; they thrash on one giant, muddy one.
First attempt: rewrite a vague task into a finishable spec
- Vague task
- Reshape into four-part spec
- Swap project-specific paths
- Pass that spec
- Let it run once
Time to practice on something real.
Pick a tiny change you actually need in your current project. If you don’t have one, use this stock example:
Improve the error message when a user enters an invalid email into the signup form, and prevent submitting if the email is invalid.
This is how many people feed it to an agent:
Improve the signup email validation and error message.
That’s vague. Let’s reshape it into the four-part spec.
Worked spec
Goal / scope: Strengthen signup email validation so invalid emails can’t be submitted, and show a clear inline error message near the email field.
Context: Next.js app. Signup form at `app/signup/page.tsx` posts to `/api/signup`. Client-side validation currently uses a simple regex in `lib/validation.ts` but lets some invalid emails through. Error messages appear under the field using the existing `<FormError>` component.
Constraints:
- Reuse the existing `<FormError>` pattern for UI; don’t introduce a new error component.
- Keep the validation logic in `lib/validation.ts`; don’t inline regexes into React components.
- Don’t change the API contract of `/api/signup`.
Verification:
- Automated: Extend or add tests in `__tests__/validation.test.ts` to cover invalid emails like `"a@", "@example.com", "a@b", "user@@example.com"`.
- Manual: In the browser, go to `/signup`, enter `"user@@example.com"`, click submit, and confirm: (1) the request is blocked client-side, (2) the email field is outlined in red as in other error states, and (3) the error text reads “Enter a valid email address.”
Size / limits:
- This should require changes in at most 3 files and be doable in under 30 minutes of careful human work.
- If additional refactors seem necessary, stop and propose a follow-up task instead of doing them now.
Copy this pattern, but swap in your own project-specific paths, components, and checks. Then pass that spec to your agent (Claude Code, Cursor agent mode, etc.) and let it run once without further hand-holding.
Reading the results: good vs poor feedback signals
Strong positive
Changes restricted to expected files; all listed tests updated or added; commit message or summary mirrors your goal and verification steps.
Borderline
Core behavior implemented, but one verification step missing; or the agent asks 1-2 clarifying questions before acting.
Negative
Unrelated files changed; new patterns or libraries introduced; verification steps ignored; tests broken without explanation.
Once the agent finishes, your job is not to fix everything by hand. Your job is to read the feedback and decide what to change in your next task spec.
Here’s what to look for:
| Signal type | What you see in the diff / logs | What it usually means |
|---|---|---|
| Strong positive | Changes restricted to expected files; all listed tests updated or added; commit message or summary mirrors your goal and verification steps. | Your spec was clear and right-sized. Reuse this shape next time. |
| Borderline | Core behavior implemented, but one verification step missing (e.g., tests not updated); or the agent asks 1-2 clarifying questions before acting. | Scope or constraints were mostly clear but slightly thin. Next time, be more explicit about the missing part. |
| Negative | Unrelated files changed; new patterns or libraries introduced; verification steps ignored; tests broken without explanation. | Task was ambiguous or too large, or constraints were too vague. You need to tighten the spec before retrying. |
You can also use runtime behavior as feedback: if your manual check passes exactly as described, your spec guided the agent well.
When an agent “fails,” resist the urge to blame the model or rewrite all the code yourself. Treat the output as a structured critique of your task spec. If the diff is scattered, your scope was fuzzy. If tests are missing, your verification was weak. The model is a mirror for your planning, not just an autocomplete with delusions of grandeur.
Retry: tightening scope, constraints, and verification
- Partial or messy change
- Rewrite the task
- Localize changes
- Add or update tests
- All tests pass
Let’s say your first attempt produced a partial or messy change. Instead of escalating to a giant corrective prompt, rewrite the task using what you just learned.
Using our signup example, imagine the agent:
components/Input.tsx, even though you wanted behavior localized.Your second-iteration spec might sharpen things like this:
Follow-up task: Complete email validation work by localizing changes and adding tests.
Goal / scope: Ensure all email validation logic lives in `lib/validation.ts` and that invalid emails are fully covered by tests.
Adjustments from previous attempt:
- Move any validation changes out of `components/Input.tsx` back into `lib/validation.ts`.
- Do not modify `components/Input.tsx` at all in this task.
Constraints:
- Use the existing test file `__tests__/validation.test.ts`; do not create new test suites.
- For each invalid email case (`"a@", "@example.com", "a@b", "user@@example.com"`), add or update a test asserting `validateEmail` returns a failure with the message “Enter a valid email address.”
Verification:
- All tests in `__tests__/validation.test.ts` pass via `npm test validation`.
- Grep for `validateEmail` shows no remaining ad-hoc regex checks in components.
Instead of saying “fix what you just did,” you’re editing the plan in light of concrete feedback. Over a few iterations, you’ll start to see patterns in where your specs are weak and tighten them preemptively.
When to plan yourself vs let the agent plan
Agents can also plan their own steps: “Summarize the changes required and execute them.” Sometimes that’s fine; sometimes it’s exactly what causes thrash.
Use this rule of thumb:
- You plan when the task involves design, tradeoffs, or non-obvious constraints (performance-sensitive code, security invariants, tricky UX flows).
- Agent plans when the task is constrained and mechanical (convert tests from Mocha to Jest, migrate one endpoint to a new DTO, apply the same validation rule across a set of forms).
If you let the agent plan, bound it:
First, propose a short 3-5 step plan for this task. I’ll confirm it before you execute. Each step should be doable in under 30 minutes and limited to specific files. Do not introduce new libraries or major abstractions without asking.
Evaluate the proposed plan like you would a junior teammate’s. If it’s off, correct it in plain language and have the agent replan before writing code.
Reviewing and merging agent-written code
- Read the actual changesRead the actual changes, not just the agent’s summary.
- Check verification implementedCheck that every verification step you listed is reflected in code.
- Stop on red flagsIf you see new abstractions, extra dependencies, or cross-cutting refactors you didn’t ask for, stop.
Even with good task specs, you remain the editor. Treat the agent like a fast but naive collaborator.
During review, focus on three things:
1. Diffs, not prose.
Read the actual changes, not just the agent’s summary. Look for broken invariants, performance regressions, or security footguns the model can’t fully appreciate.
2. Verification actually implemented.
Check that every verification step you listed is reflected in code:
If any step is missing, send a follow-up task instead of silently patching everything yourself. That keeps the planning loop honest.
3. Red flags that demand a re-plan.
If you see new abstractions, extra dependencies, or cross-cutting refactors you didn’t ask for, stop. Your next task should clarify constraints and explicitly ban that scope, not reward the agent by cleaning it up manually.
Over time, your “unit of work” shifts from “I’ll go fix this” to “I’ll design a finishable task, let the agent attempt it, and then I’ll review and adjust the plan.” That’s the leverage point you control.
Agent task planning cheatsheet
Four-part agent task template
Always include: (1) Scope: one sentence, specific outcome ("add server-side email validation on signup form"). (2) Context: 1-3 sentences naming key files, routes, and existing behavior ("Next.js app, form in app/signup/page.tsx, validation in lib/validation.ts"). (3) Constraints: 2-5 rules on APIs, patterns, and no-go areas ("don’t change API contract", "reuse <FormError>"). (4) Verification: explicit tests and manual steps with concrete inputs and expected outputs ("tests in __tests__/validation.test.ts, manual check with user@@example.com shows message X"). Add a short Size / limits note ("under 30 minutes, max 3 files") and tell the agent to stop and propose a split if it’s larger.
⏱️ Right-size heuristics
Aim for tasks a careful human could do in 10-30 focused minutes. That usually means: 1-3 files touched; a single behavior change; no new core abstractions; max ~100-150 lines of net diff. If you can’t describe the change in one crisp sentence, it’s too big. Split along user actions ("saving" vs "publishing"), layers (API vs DB), or concerns (validation vs UI vs logging). For risky areas (payments, auth), pick even smaller slices (5-15 minutes) and heavier verification.
Verification checklist for tasks
Before you run the agent, write at least one automated and one manual verification step: (1) List exact test files or commands ("npm test validation", "pytest tests/test_signup.py", not "run tests"). (2) Name specific inputs and expected outputs for manual checks ("enter user@@example.com, form should block submit and show 'Enter a valid email address'"). (3) Note any invariants to recheck ("existing success path for valid email remains unchanged"; "no new network calls added"). If you can’t articulate verification, you haven’t understood the change well enough to delegate it.
⚠️ Review-time red flags
During code review, treat these as hard warnings: (1) Diffs touch files or modules not mentioned in your spec. (2) New dependencies or patterns appear (hooks, services, libraries) you did not request. (3) Verification steps you wrote are missing, partial, or ignored. (4) Large, cross-cutting refactors piggyback on a small task. When you see these, don’t just patch by hand. Write a follow-up task that clarifies scope (what must not change), tightens constraints, and restates verification, then let the agent correct its own work under the new plan.
Want a more guided way to practice this?
Agent task planning FAQ
⏱️ How big should an agent task be in practice?
Think of a single agent task as something a mid-level engineer could implement carefully in under 30 minutes. That often translates to touching 1-3 files, changing one behavior, and adding or updating a small number of tests. If the task requires new abstractions, data model changes, or cross-cutting refactors, it’s almost always too big and should be split. A good stress test is: can you describe the change in one sentence and list 2-3 concrete verification steps? If not, it’s a bundle of tasks disguised as one.
Should I let the agent plan or plan myself?
Plan yourself whenever the task involves product decisions, architecture, or subtle tradeoffs (performance, correctness, security). In those cases, you know more about the constraints than the model ever will, so you should define the steps and let the agent execute. Let the agent plan when the task is mechanical and well-bounded, such as migrating similar code across files or updating a pattern in one layer of the stack. A good hybrid is to ask the agent to propose a 3-5 step plan first, then you edit that plan and explicitly tell it to execute the revised version, not to improvise a new one.
⚙️ What if the agent makes the wrong design choice?
Treat a bad design choice like feedback on your constraints, not just on the model. First, decide if the design is truly wrong (e.g., violates performance or security requirements) or just different from your taste; only the former is worth a re-plan. Next, write a follow-up task that (1) states the chosen design you actually want, (2) forbids the rejected approach explicitly, and (3) includes verification that would catch the bad design (like a performance check or resource usage limit). Over time, keep a small “constraints library” in your repo (e.g., ARCHITECTURE.md) and point the agent at it in future specs so it learns your house style.
How do I review agent-written code safely?
Review agent code the way you’d review a new teammate’s first PR: assume good intent, verify everything. Start by scanning the files changed and ensure they match your task spec; unexpected files are a red flag. Then walk through the diff, checking invariants (auth, error handling, performance characteristics) more than style, since LLMs mimic style fairly well but can easily violate invariants. Finally, run the specific tests and manual checks you listed in the verification section of your spec. If anything is off, write a targeted follow-up task to correct it instead of quietly fixing everything by hand; that keeps your planning loop honest and improves future prompts.
How do I handle tasks that don’t fit into a single under-30-minute chunk?
When a task is bigger than 30 minutes of human work, your job shifts from "delegate the task" to "design a sequence of finishable tasks." Start by writing a one-paragraph high-level goal (like a mini design doc), then break it into 3-7 sub-tasks, each small enough to fit the usual constraints. A typical split might be: (1) add or adjust data model; (2) change API or service layer; (3) update UI; (4) backfill or migrate data; (5) harden with tests and docs. For each sub-task, you still apply the four-part spec with its own verification. You can optionally ask the agent to suggest a split, but you should edit and approve that plan before it touches code.
Make finishable tasks your default unit of work
If agents keep handing you half-baked PRs, the fix is rarely a new model or a longer context window. It’s almost always better task design.
When you define clear scope, explicit constraints, concrete verification, and a realistic size, agents start behaving less like chaotic autocomplete and more like a fast, literal-minded teammate. You’re not trying to make the model “smarter”; you’re building a tighter loop between your intent and its actions.
On your next real change, resist the urge to just “ask the agent.” Spend three minutes writing a four-part spec instead. Run a single agent attempt, read the feedback from the diff and tests, and adjust your next spec accordingly. A few cycles of that, and you’ll have a repeatable workflow where agents regularly ship changes you can actually merge.