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.
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.
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.
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?
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.
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.
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.
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.
Delegate works for bug fixes with a clear repro, mechanical refactors, boilerplate, tests for known behavior — anything well-scoped and easy to grade.
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.
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.