Prompting Coding Agents
You typed “make the checkout flow better” into Cursor, hit enter, and got back a diff touching fourteen files that you now have to read. The tool did something. Whether it did the thing you wanted is a separate question, and you cannot tell without a lot of scrolling.
The problem is almost never the model. It is the prompt. Prompting a coding agent is a different skill from chatting with an LLM, and most people carry over the wrong habits.
You are giving a goal, not asking a question
When you chat with an LLM, you ask a question and read the answer. The model produces text; you decide what to do with it. Nothing changes until you act.
A coding agent is different. You give it a goal and it acts on your repo: it reads files, decides what to edit, applies changes, and often runs your tests. The output is not text for you to interpret. It is a diff that already exists on disk.
A chat prompt can be a little vague, because you turn the answer into action. An agent prompt cannot, because the agent turns your words into edits with no human in between. Ambiguity does not get clarified; it gets guessed, and the guess lands in your codebase.
So treat the prompt as a work ticket for a fast, capable, slightly literal engineer who has never seen your codebase and will not ask follow-up questions before starting. What would that ticket need to say?
flowchart LR
CHAT["Chat prompt"] --> ANS["Text answer"]
ANS --> YOU["You act"]
GOAL["Agent prompt"] --> ACT["Agent reads,<br/>edits, runs"]
ACT --> DIFF["Diff on disk"]
DIFF --> REV["You review"]
Scope it to something you can review
The single biggest lever is task size. A good agent task is one whose diff you can read and reason about in one sitting. If you cannot hold the finished change in your head, you cannot review it, and an unreviewed agent diff is a liability.
“Refactor the payments module” is not a task. It is a project. The agent will make a hundred decisions you never see, and you will approve them by exhaustion. Break it down:
- Extract the retry logic from
PaymentClientinto a separateRetryPolicyclass. - Add idempotency keys to the charge endpoint.
- Replace the inline currency formatting with the
format_moneyhelper.
Each of those is a reviewable diff. You can read it, test it, and merge it before starting the next. Small scope also keeps the agent’s context window focused, which directly improves output quality. Default to the smallest task that still makes sense as a unit of work; you can always ask for the next step once the current one is on a branch.
Tell it what “done” means
An agent stops when it thinks it is done. Your job is to make “done” something it can actually check, not something it has to guess. That means acceptance criteria, in the prompt, up front.
Concretely, give it:
- The behavior you want, in specifics. Not “handle errors” but “return a 429 with a
Retry-Afterheader when the rate limit is exceeded.” - The tests that must pass. Point at an existing test file, or ask it to write tests first and make them pass. A failing test is an unambiguous “not done” signal the agent can act on.
- Constraints. “Do not change the public API.” “Keep it in one file.” “No new dependencies.”
Give an agent a command it can run to check its own work (the test suite, a linter, a type check) and it will run it, read the output, and keep going until it passes. That is the loop working for you. Without a checkable target, its only stopping signal is its own judgment about whether the code looks finished, which is exactly the judgment you do not want to outsource.
Why do tests make agents so much better?
Because they turn a vague goal into a signal the agent can act on inside its loop.
An agent runs plan, act, observe on repeat. Without tests, the “observe” step is weak: the model looks at the code it wrote and asks itself whether it seems right. With tests, “observe” becomes running a command and reading a pass or fail. A failure tells the agent exactly what is broken, and it will iterate against that signal on its own until the bar is green. You get the benefit of the loop instead of a single confident guess.
Point at references, do not describe them
Beginners describe the pattern they want in prose. “Make it follow our usual repository pattern, with a service layer and dependency injection.” The model will build a repository pattern, probably not yours.
The fix is to point instead of describe. Your codebase already contains the pattern you want. Name the file.
Add a
ShipmentRepository. Follow the exact structure ofOrderRepositoryinapp/repositories/order_repository.py, including how it handles the DB session and the error wrapping. Use the same test layout astests/repositories/test_order_repository.py.
Now the agent has ground truth. It reads your actual code and matches it, instead of reconstructing your conventions from a description that can only ever be approximate. This is faster to write than a paragraph of prose and far more accurate.
It is the same idea as a project rules file, which encodes conventions once so you do not repeat them every prompt; setting that up is covered in rules and context. References in the prompt handle the specifics for one task; rules handle the standing conventions for every task.
Iterate in small steps, correct mid-task
The instinct is to write one perfect mega-prompt that specifies everything, fire it, and hope. This rarely works: you cannot anticipate every decision the agent will face, and a wrong early decision poisons everything after it.
Better: give it the first concrete step, watch what it does, and correct course. Coding tools let you interrupt and steer while the agent works. Use that.
You: Add caching to get_user_profile. Start by reading how
we cache in get_org_settings so you match it.
Agent: [reads get_org_settings, starts adding a new cache client]
You: Stop. Reuse the existing cache client from cache/client.py,
do not create a new one. Same TTL as org settings.
Agent: [switches to the shared client, applies the org-settings TTL]
That correction cost one sentence. Catching the same mistake after a fourteen-file diff costs a full review and a re-prompt. Treat the agent as a conversation with a fast collaborator, not a batch job you submit and collect. The tighter your feedback loop, the less rework you do.
Before and after
Here is a weak prompt and a strong one for the same task.
Weak:
Add authentication to the API.
The agent has to guess the auth scheme, which endpoints, where to put the middleware, how to signal failures, and whether tests are expected. Every guess is a coin flip, and the diff will be large and hard to trust.
Strong:
Add JWT bearer-token auth to the API. Protect every route under
/api/v1/adminand leave the rest public. Follow the middleware pattern inmiddleware/rate_limit.pyfor how middleware is registered and how it short-circuits a request. Return 401 with{"error": "unauthorized"}on a missing or invalid token. Add tests totests/test_auth.pycovering a valid token, a missing token, and an expired one. Do not add new dependencies; we already havepyjwt.
The strong prompt scopes the surface (/api/v1/admin only), points at a reference (rate_limit.py), defines done (specific status and body, three named test cases), and sets a constraint (no new deps). The resulting diff is small, checkable, and reviewable. Same model, completely different result.
Common beginner mistakes
- Prompting like a chat: writing a vague question when you are handing over an action. The agent will not ask you to clarify; it will guess and edit.
- Tasks too big to review: “refactor X” produces a diff you approve by exhaustion. Scope to one reviewable unit.
- No definition of done: leaving out acceptance criteria and tests, so the agent stops on its own vibe instead of a checkable bar.
- Describing patterns instead of pointing: writing a paragraph about your conventions when naming one existing file would be exact.
- The one-shot mega-prompt: trying to specify everything up front instead of steering the agent as it works.
- Ignoring the tests it could run: not pointing at a test command, so the agent never gets a hard signal it is wrong.
Questions you will face in production
“Should I write a long detailed prompt or a short one?” Detailed on scope, references, and done; short on everything else. Precision is the goal, not length. A three-line prompt that names the file to match and the test to pass beats a three-paragraph essay of adjectives. Add words that reduce guessing, cut words that just sound thorough.
“The agent keeps drifting from our conventions. Do I repeat them every time?” No. One-off specifics go in the prompt as file references; standing conventions go in a rules file so you write them once. If you find yourself typing the same instruction into every prompt, that is a signal it belongs in your project rules, not your prompt.
“It did the task but touched files I did not expect. What went wrong?” Usually scope. A broad goal gives the agent permission to roam. Constrain it: name the files or directories in play, say what not to change, and keep the task small enough that a wide blast radius is obviously wrong when you read the diff.
What to remember
- A coding agent acts on your repo; a chat model hands you text. Prompt for action, not for an answer.
- Scope every task to a diff you can read and reason about in one sitting.
- Put acceptance criteria in the prompt: specific behavior, tests that must pass, hard constraints.
- Point at an existing file to copy a pattern instead of describing the pattern in prose.
- Iterate in small steps and correct mid-task; steering early is cheaper than reviewing late.
- Precision beats length; add words that reduce guessing, cut words that just sound thorough.
What to study next
Good prompts get you good diffs, but only if the agent had the right context to work from in the first place. The next step is managing what the agent can see: what fills the context window, when it goes stale, and how to keep a long session from losing the plot. That is context management.
The prompting principles here are a specialization of a broader discipline that applies to every LLM feature you build, not just coding tools. The foundation is treating prompts as code: versioned, tested, and precise.
Further reading
- Anthropic: Claude Code best practices. Field-tested advice on scoping tasks, using tests as a target, and steering an agent.
- Cursor documentation. How to reference files, set rules, and interrupt an agent mid-task.
- Anthropic: Building effective agents. Why a clear goal and a checkable signal matter to anything running an agent loop.
Where this article comes from. This is a synthesis of common practice in AI engineering as of 2026, not a citation of any single paper. The sources above are where the mechanics come from. If you find an error or have a better source for a claim, the article gets fixed within a day, send me a note.