How to talk to coding agents
Chapter 04of07

The tree

Coding work isn't flat. Every change lives somewhere on a 2D map — across the surface area of your codebase (breadth), and at some level of abstraction (depth). At any point on that map, you have three moves you can make: ask, plan, or delegate.

UX
Performance
Debugging
Architecture
Highthe overall feel
Mida component or flow
Lowone specific line
Generated promptUX · Mid · Ask

Why does the card hierarchy feel cluttered?

Prompting is navigating this tree. The axes are usually fixed by the task — the interesting choice is which of the three moves you make.

ASKWhen you don't know yet.

Use Ask when you need to understand something before you act. It's the cheapest move — a few seconds and a few tokens to widen what you know.

From the wild

The middleware in apps/api/src/auth/check.ts is intermittently returning 401 in staging — about 1 in 30 requests. Trace attached. I see the call to verifyToken returns null but the function looks idempotent to me. What am I missing?

From a real session. The repro and the trace did most of the work.

The classic failure is asking too narrowly. You phrase the question around what you think the issue is; the model answers that question, confidently; you walk away with a clean, wrong answer. The fix is to include what's actually happening, not what you've decided is the problem. Paste the error. Show the file. Describe the symptom before you propose the cause.

PLANWhen you know roughly what, but not how.

Plan pays for itself the most often. The model proposes an approach; you push back on bad assumptions; you converge; then code gets written. Much cheaper to revise a paragraph than a refactor.

From the wild

I want to migrate our notification logic out of the request handlers into a queue. Don't write code yet — propose 2–3 approaches, then pick one and explain the trade-offs. Constraints: must keep delivery semantics at-least-once, must not block API responses, can use the existing Redis instance.

Cross-cutting change with multiple plausible approaches. Plan first, code later.

The trap is treating the first plan as binding. The model will commit to whatever it proposed first unless you push back. Treat the first plan as a draft and make it argue for the choices you're skeptical of.

DELEGATEWhen the path is clear and you can verify the result.

Delegate works for bug fixes with a clear repro, mechanical refactors, boilerplate, tests for known behavior — anything well-scoped and easy to grade.

From the wild

In components/ui/Button.tsx, add a 'loading' boolean prop. When true, disable the button and show a small spinner to the left of the children. Use the existing Spinner component from components/ui/Spinner. Don't change the public API otherwise. Update the stories in Button.stories.tsx to cover the new state.

Narrow scope, obvious success criteria. Easy to verify.

It works badly the moment any of that breaks: the task touches taste (UX, copy, naming), the change is cross-cutting, or you can't easily tell whether the result is right. Don't delegate what you can't grade. The discipline is bounding the blast radius first — smaller diffs, narrower scope, clearer success criteria.

Choosing your move

A few heuristics for picking the right square:

  • Start broad, end specific. Most non-trivial work moves through all three: ask to understand the shape, plan to commit to an approach, delegate to land the change. Skipping a step shows up as rework two prompts later.
  • If you're burning loops, zoom out. Delegate-reject-reprompt cycles are almost always a context problem, not a model problem. The cell you're in is wrong — move up the tree.
  • The most expensive prompts are the ones in the wrong cell. Delegating something that needed a plan. Asking about something you should have just done. Calibration is most of the skill.