CHAPTER 13 · MASTERY
Driving Coding Agents
The previous twelve chapters gave you mental models and vocabulary. This one assembles them into a repeatable workflow: how to turn fuzzy intent into a spec an agent can execute precisely, where to step in, and how to review output efficiently. The goal is for you to always hold the direction and the pace, instead of being pushed along by whatever the agent produces.
- Drive a feature through "explore → spec → plan → implement → verify → review" and know which points you must decide yourself.
- Write a task description using the six-element template.
- Translate a vague symptom ("the page is slow", "the data is wrong") into precise technical language.
- Review an agent-generated PR in 10 minutes with a checklist.
- Recognize the signs of an agent going in circles and know what to do.
Opening: two developers, one feature
A and B use the same agent to add "filter by tag" to LinkNote. A types "add a tag filter" and spends two hours going back and forth: the agent uses useState, A says the filter is lost on refresh; the agent switches to localStorage, A says others don't see the filter in shared links; the agent switches to a URL param but "helpfully" refactors the list component and breaks pagination… B spends 15 minutes writing a description, and the agent finishes in one go with all tests passing. What did B do right?
Where the answer lies: A is making the agent guess the requirements by trial and error, exposing one hidden requirement per round; B said the hidden requirements out loud before starting: filter state in the URL (shareable, survives refresh), don't touch pagination, and what "done" means. Agents execute extremely well, but they can't read requirements you never stated. B's 15 minutes weren't "writing docs" — they were design, which is your core job in the agent era.
The workflow at a glance
① Explore: have the agent investigate before it touches anything
For unfamiliar code or complex changes, the first instruction should be "investigate and report", not "implement". For example: "How does the list page load its data? Where do filter and pagination state live? Read only, change nothing, give me a short report." It's cheap, and it exposes your own wrong assumptions.
② Spec: your core output
See the six-element template in the next section.
③ Plan: reject the wrong direction when it's cheapest
Have the agent produce a plan before writing code (many tools have a dedicated "plan mode"). Reviewing a plan is ten times cheaper than reviewing code. Ask of the plan:
- Do the files it intends to touch match what I expected? Anything out of scope?
- Any data-model changes, new dependencies, DB migrations? Those need my explicit OK.
- Are security aspects (auth, validation) covered?
- What's the test plan? How will it prove it's done?
④ Implement: small, verifiable, committable steps
Cut work into vertical slices: each slice is the smallest end-to-end runnable piece ("first make the URL param filter the list; no UI yet"), rather than "all DB code, then all endpoints, then all UI". Run checks and commit after each slice. If something breaks, you roll back one small step.
⑤ Verify: let the machines check first
Chapter 10's Definition of Done kicks in here: the agent may only say "done" when type checks, lint and tests all pass. For UI, open the preview link and click through yourself — nothing automated replaces that.
⑥ Review → ⑦ Merge → ⑧ Capture
Review method below. After merging, spend one minute asking: what did I have to tell the agent more than once? Write it into AGENTS.md or turn it into a test or lint rule. Every correction should happen only once.
The six elements of a task description
| Element | Question it answers | Typical result when missing |
|---|---|---|
| 1. Goal & context | Why? For whom? | Technically correct, solves the wrong problem |
| 2. Scope | What to do, and explicitly what not to do | The agent "optimizes" unrelated code on the way |
| 3. Constraints | Required / forbidden tech, patterns, dependencies | New libraries, a different state approach, strict checks turned off |
| 4. Interfaces & data | Shape of the data, where it lives, function signatures | A different data model every time; front and back don't line up |
| 5. Acceptance criteria | What counts as done? (executable, observable) | "Looks like it works", every edge case missed |
| 6. Deliverables | What to hand back: code, tests, notes, screenshots | No idea what changed or how to verify |
A description like this takes 10–15 minutes. It forces you to decide first: where state lives, which layer filters, what the edge cases are. Leave those decisions for the agent to make implicitly and you get A's two hours.
If you can't write acceptance criteria, you probably haven't decided what you want yet. Then flip it and let the agent help: "I want tag filtering. Interview me to clarify the requirements, one question at a time, then write it up as a task description." That uses the agent for requirements analysis instead of making it guess.
Precise language: from symptom to term
What you observe is usually a "symptom"; what the agent needs is a "direction for diagnosis". This table maps common vague descriptions to precise expressions from earlier chapters. Fluency with these words is the most direct lever you have over an agent:
| What you see | A likely precise expression | Ch. |
|---|---|---|
| The page keeps re-requesting an endpoint | useEffect depends on an unstable reference, forming a "render → effect → setState" loop | 06 |
| Changed the data, UI didn't update | State object was mutated; reference unchanged; use an immutable update | 03 / 06 |
| Filter / pagination lost on refresh | That state belongs in URL query params, not component-local state | 06 |
| Search results don't match the input | Request race: an older request returned after a newer one; cancel or discard stale results by key | 06 |
| Same data shown differently in two places | Stored derived state / no single source of truth; or a cache that wasn't invalidated | 06 / 08 |
| First page load is slow | Too much first-screen JS / request waterfall / should be server-rendered or streamed | 07 |
| Page shows one thing, then flashes to another | Hydration mismatch / client refetching data | 07 |
| Others can see or delete my data | Missing authorization (IDOR); put the ownership condition in the query | 08 |
| API errors in the browser, curl works | CORS: declare allowed origins and credentials, or go same-origin | 05 |
| Occasional lost data or wrong counts after deploy | Shared state kept in serverless instance memory | 09 |
| "Too many connections" at peak | Connection explosion under serverless; need a pooling proxy or HTTP driver | 08 |
| Batch processing "finishes early" | forEach(async) not awaited; or a floating promise | 03 |
| AI answers take ages to appear | No streaming; time to first token (TTFT) too long | 11 |
| AI output format is right only sometimes | Missing structured output and schema validation | 11 |
| The agent gets messier and repeats mistakes | Context too long or polluted; write progress to a file and start a new session | 12 |
Note the word "likely". These expressions are hypotheses, not conclusions. The good move is to give the agent both the symptom and your hypothesis, and require it to verify first: "I suspect a request race; add logging first to confirm the order requests are sent and returned, then fix it."
Reviewing agent output
Reviewing a design
When an agent hands you a design doc or technical proposal, the point isn't polished prose but:
- Requirement coverage: does every acceptance criterion map to an implementation approach?
- Data model: are new tables / fields sensible? Will changing them later be painful?
- Failure modes: what happens on network failure, LLM timeout, double submission, concurrent edits?
- Alternatives: which other approaches did it consider, and why not them? — if none, ask: "Give me two alternatives and the trade-offs."
- Over-engineering: abstraction layers, plugin systems or generic frameworks built for imagined future needs?
Reviewing code: a 10-minute checklist
Don't start reading line by line from the first file. Go from highest information density down:
- Scope of change: does the list of modified files match expectations? Anything from the "don't" list touched?
- Data structures: schemas, type definitions, Zod schemas, DB migrations. They decide the shape of everything else.
- Tests: do they cover the acceptance criteria? Were existing tests modified (Chapter 10)?
- Boundaries: is external input validated? Is the authorization condition there? Did secrets leak into client code?
- Search for red flags:
any,as,!,@ts-ignore,eslint-disable, emptycatch, new dependencies,useEffect. - Core logic last: by now you know what it should look like, so it reads much faster.
Open a new session (or a subagent), give it only the task description and the diff, and have it find problems with the checklist above. It hasn't been "convinced" by the implementation process and often catches what the implementing session can't see. The final call is still yours.
Controlling the pace
When to step in
- Three failed attempts at the same problem: stop. Don't say "try again". Ask the agent for hypotheses and evidence, or look at the error yourself. Letting it keep guessing only makes the context messier.
- It starts changing things outside the described scope: point it out immediately and ask for a revert.
- It proposes turning off checks, skipping tests, adding dependencies: all need your explicit approval.
- The diff is too big to want to read: the task was cut too large. Roll back, slice smaller, retry.
Collaborating on debugging
The key: give evidence, ask for hypotheses, verify before changing. That turns the agent from "guess a fix" into "run a small scientific experiment".
When to do it yourself
A one-line config change, a small bug you already know how to fix, UI tweaks that need taste — doing it yourself is often faster than describing it to an agent. You don't have to use an agent for everything.
Running in parallel
Once fluent, you can run several agents on independent tasks at once (one building a feature, one adding tests, one investigating a performance issue), each on its own git worktree or branch. The precondition: the tasks really are independent and you have the bandwidth to review everything — your review capacity is always the bottleneck of parallelism.
Writing AGENTS.md well
- Short and specific: it occupies context in every session. Write "use pnpm", not an essay on package managers.
- Write what the agent can't guess: project-specific conventions, known pitfalls, prohibitions. Generic framework knowledge doesn't belong.
- Point, don't copy: "DB conventions: see docs/db.md" lets the agent read it when needed.
- Layer it: global conventions at the root; local ones in subdirectories (e.g.
apps/api/AGENTS.md). - Keep it alive: update it whenever you notice a repeated correction; delete lines that go stale.
How the tools differ Aware
Claude Code, Codex CLI, pi, Cursor and IDE agents share the same underlying principles (Chapter 12), and this chapter's methods apply to all of them. The differences are mostly in harness philosophy: some ship rich built-ins (plan mode, subagents, hooks, plugin marketplaces, cloud runs), others are deliberately minimal and let you assemble what you need via extensions. When choosing, look at: model support, the project-instructions file convention, permission granularity, whether it can run unattended (CI, batch jobs), and whether you like how it feels. No need to chase every new tool — the workflow and your ability to express yourself are the assets that transfer.
Anti-patterns
| Anti-pattern | Why it hurts | Instead |
|---|---|---|
| Never reading code, only checking the result | Security holes and data-model problems don't show in the UI | At least review data structures, tests and boundaries with the checklist |
| "Fix all the errors" | The agent makes errors vanish the fastest way (any, as, ignore) | Add constraints: forbidden escape hatches; explain before fixing |
| One session all day | Context rot; quality drops later on | One task per session; progress written to files |
| One giant requirement at once | Vague plan, huge diff, unreviewable | Vertical slices, each verifiable |
| Letting the agent make architecture decisions silently | Where state lives, which layer filters, which library — these shape the project for a long time | State them in the spec, or approve them at plan time |
| Building the perfect toolchain before building the product | Time goes into preparing instead of shipping | Ship a minimal working version first; add tools when real problems appear |
This question is extremely common in 2026 interviews. A good answer isn't "I use tool X and I'm N× faster" but a demonstration of your method and judgment:
- Write specs and acceptance criteria first, then let the agent implement; review the plan first for complex tasks.
- Use type checks, tests and CI as an automated verification net instead of reading every line.
- Review focus: data models, authorization and validation, whether tests were modified, new dependencies.
- Give an example of catching a subtle agent mistake (an IDOR, an effect loop) and how you caught it.
- Explain how you turn repeated corrections into project instructions, hooks or lint rules.
Self-check
1. Rewrite this request as a six-element task description (abbreviated is fine): "Add an export feature to LinkNote."
Reference points: goal (users want to back up or migrate bookmarks); scope (export all of the current user's bookmarks as JSON and Markdown; no import, no scheduled exports); constraints (generated server-side, streamed download to avoid memory issues with large data; no new dependencies); data (url, title, summary, tags, createdAt; exclude internal id and userId); acceptance (1,000 bookmarks export without timing out; users can export only their own data; file name includes the date; tests exist); deliverables (plan first).
The point isn't matching this exactly, but whether you thought of "what not to do", authorization, data volume and verification on your own.
2. The agent has tried three times to fix "the list sometimes shows stale data", each time saying "fixed", but it still happens. What should your next message say?
Stop the attempts. Something like: "Don't change code yet. List at least three possible causes of the list showing stale data (cache not invalidated, request race, server-side cache), and how to verify each with logs or tests. Then add logging and give me reproduction steps; we'll fix it once the evidence points to a cause." If the session is already long, have it write findings to a file and continue in a new session.
3. The agent's PR touches 23 files, 15 of which are "code style cleanup while I was there". What do you do?
Ask for a split: move the style changes out of this PR (or just revert them) and keep only the feature changes. Mixed diffs hide the real logic changes, make review hard, and raise conflict and rollback costs. Then add to AGENTS.md: "Don't modify files outside the task's scope; formatting is the formatter's job."