Keep AI From Building More Than You Asked
You ask for a one-line fix and get a sixty-line diff — a refactor, a fallback, some renames "while it's in there." Here's how to keep AI from building more than you asked: state the exact change, spell out the non-goals, cap the blast radius, and make it show a plan first.
Structure a Scoped Change RequestWhen one small fix becomes a sixty-line diff
You ask for one small thing — "fix this validation bug" — and the AI does it. Then it keeps going: it refactors the validation helper, adds a fallback, renames a couple of variables, tidies the upload handling "while it's in there." The one-line fix you wanted is now buried in a sixty-line diff, and you can't approve the fix without also vouching for everything it brought along. It looks helpful. It is really a loss of control: the change you asked for is no longer the change you are reviewing.
The problem isn't that the AI is careless — it is that a task, on its own, has no ceiling. "Fix the bug" says what to do; it doesn't say what not to do, and a model trying to be helpful reads the silence as permission to improve everything nearby. This guide is how to keep AI from building more than you asked: state the exact change, spell out the non-goals, cap the blast radius, and make the model show its plan before it writes code. NewPrompt helps you build that scoped prompt — the Prompt Formatter pulls the "don't touch X" clauses out of your request into a constraints section the model is less likely to overlook — and it is honest about the limit: it doesn't run the model, apply the change, scan your repo, or inspect the diff. You run the scoped prompt in your own AI tool, and you read the diff. A boundary lowers the odds of scope creep; it doesn't lock the door, which is why the review is still yours.
Why AI builds more than you asked
A model handed a narrow task and nothing else optimizes for looking helpful, and "helpful" and "minimal" are not the same thing. Left to fill the gaps, it reaches for more, not less. Here is where the extra comes from:
- Helpfulness bias. The model is tuned to be maximally useful, so it treats an adjacent improvement as a favor rather than an overstep — a fallback here, a cleanup there.
- Pattern completion. It has seen thousands of "proper" versions of this code, and it drifts toward completing that pattern instead of making the one change you asked for.
- The "while I'm here" reflex. Once it is editing a file, touching the messy function two lines down feels efficient — to the model. To your reviewer, it is noise around the real change.
- A vague ask reads as a broad mandate. "Fix the validation" with no boundary can mean the one bug or the whole validation system, and the model picks the generous reading.
- No non-goals. Nothing said "don't refactor, don't rename, don't add features," so nothing stopped it. Absent a ceiling, the change grows to fill the ambition.
- "Best practice" as a license. A config option, a DTO layer, or error handling you didn't ask for gets justified as good engineering — which makes the scope creep feel principled instead of optional.
Step 1: Name the change — and the non-goals
A scoped prompt has two halves, and most people write only the first. The first is the exact change: not "fix the validation" but "the required file field should block submit only when it is visible and empty." The second — the half that does the real work — is the non-goals: the explicit list of what the model may not do. Write them as commands: do not refactor, do not rename, do not change the public API, do not add new features, do not touch unrelated code, do not change behavior that already works. The model improvises in the space you leave blank, so the "do not" list is where you take that space back.
The Prompt Formatter is built for exactly this split: paste a run-on request like "fix the bug but don't refactor the helper or change the upload flow," and it separates the action into a Task section and each "don't" into a Constraints section, so the boundaries stop hiding inside the sentence that describes the work. The Developer Request Prompt Formatter is that shaped for coding — a Task, a Code Context, and the section that matters here: a Constraints list of what the AI must not change or break, because, as it puts it, the AI won't infer the don't-touch list. Both hand you a prompt you run yourself — they organize your words, nothing more.
Step 2: Fence the blast radius and set a change budget
Non-goals say what not to do; the blast radius says where the model may not go. Name the files or sections it is allowed to touch, and say plainly that everything else is off-limits: "change only the validation condition in this file; leave every other file and function unchanged." Then name the behavior that must stay identical — the outputs, the side effects, the log lines something downstream depends on — so a "small" edit can't quietly alter something you weren't watching. The tighter the fence, the smaller the surface you have to review afterward.
A change budget is the blunt version of the same idea, and it works because it is blunt: "make the smallest change that satisfies the goal," "prefer a two-line fix over a two-function refactor," "if it can't be done in one place, stop and tell me why." The Safe Refactoring Prompt is a strong model of this discipline even outside refactoring — it tells the model a smaller, safer change beats a better, riskier one, caps it to "the smallest change set that achieves the goal," and forbids rewriting unrelated code ("touch only what the goal requires"). Borrow that framing for any change: the target is the sufficient edit, not the impressive one.
Step 3: Make it propose the change before it builds it
The cheapest place to catch scope creep is before the code exists. Add a checkpoint to the prompt: before writing anything, have the model list the exact lines or conditions it plans to change, and — just as useful — the out-of-scope changes it was tempted to make but is holding back. That second list is a scope-creep early-warning system: if "refactor the helper" and "add a fallback" show up as temptations, you have caught the expansion as a plan instead of as a diff. And give it an explicit exit: if the fix genuinely can't be done within the boundary, stop and ask rather than quietly widening the scope to make it fit.
This flips the default from "build first, explain later" to "agree on the boundary, then build." It costs one extra round-trip and saves the review where you would otherwise be reverse-engineering which of forty changed lines were actually necessary. It also surfaces the genuine cases where the small change really does require a bigger one — better to learn that from a one-paragraph plan than from a diff you have to unpick.
Step 4: Have it report changed, unchanged, and out-of-scope
Ask the output to account for itself in three parts, not one. Changed: what it actually modified, and why each edit serves the goal. Intentionally unchanged: the things it deliberately left alone — the helper, the variable names, the upload flow — so you can confirm the fence held. Out of scope: the improvements it noticed but did not make. Add assumptions and risks, and put any follow-up ideas under a heading that makes their status unmistakable — suggested, not applied. A change list shaped like this is reviewable at a glance; a bare patch makes you diff the whole file to find out what it touched.
The point of the "out of scope" and "suggested" sections is that you don't lose the model's good instincts — you relocate them. If it spots that the helper really is a mess, that observation is worth having; it just doesn't belong in this diff. Keeping it as a written suggestion means you get the insight and keep the small change, instead of trading one for the other. The Safe Refactoring Prompt models this too, with its "Suggested but not applied" list — the skipped work is captured, not smuggled in.
Step 5: Review against the non-goals, and keep the diff yours
The scoped prompt makes a small change likely; your review is what makes it real. Read the diff against the "do not" list, line by line: did it touch a file you fenced off, rename something you told it not to, add the fallback you forbade? Check the changed-files list against the ones you allowed, and treat any bonus change as a defect to remove, not a gift to keep — even a good extra change is one you didn't ask for, review, or plan for. And keep the model's follow-up suggestions in their own bucket: a suggestion you choose to act on later is fine; a suggestion the model acted on for you is the scope creep you were trying to prevent.
None of this is enforced for you. NewPrompt structures the request; it doesn't scan your repo, inspect the diff, run the code, or block a change that crosses a line — the model can still ignore a boundary, and the only thing that catches it is you reading the result. The output is a candidate change, not an approved one. So on anything that ships — and especially on high-risk code where an unnoticed extra change is a production risk — the diff review and the decision to merge stay with you.
Common mistakes
The habits that let a small task grow:
- Giving the task with no non-goals. "Fix the bug" has no ceiling; add the explicit "do not refactor / rename / add features / touch unrelated code" list.
- Trusting a vague boundary. "Keep it minimal" is a wish, not a constraint — name the files it may touch and the behavior that must not change.
- Letting it build before it plans. Without a propose-first checkpoint, you review the expansion as a diff instead of catching it as a plan.
- Accepting bonus changes because they look good. A helpful extra you didn't ask for is still unreviewed, unplanned work in your name — pull it out or scope it separately.
- Mixing suggestions into the change. If the model's "you should also…" ideas land in the diff, scope control is already lost; keep them as suggestions, not commits.
- Treating the scoped prompt as a guarantee. A boundary lowers the odds of creep; it doesn't enforce it — you still read the diff against what you asked for.
A worked example: one bug fix, kept to one bug fix
Watch one bug fix turn into a refactor, then get fenced back to one bug fix.
"Fix the bug" invites a refactor, a fallback, and a rename you never asked for; naming the change plus the non-goals, a propose-first step, and a changed/unchanged/out-of-scope report keeps the diff to the one fixTHE SMALL ASK:
"Fix the required-file validation bug in this form."
WHAT THE AI DID (helpful, and out of control):
"Fixed the validation bug, refactored the form-validation helper, added a
fallback, renamed a few variables, and cleaned up the upload handling."
the problem:
- the bug fix is now buried in a refactor you didn't ask for
- the fallback and upload cleanup can change behavior you weren't testing
- the diff went from ~4 lines to ~60 -- the fix is no longer isolated
- you can't review the fix without reviewing everything around it
A SCOPED PROMPT (the change, and the non-goals):
Fix ONLY the required-file validation bug.
Goal: required file fields should block submit only when visible and empty.
Allowed scope:
- the validation condition for file inputs
- the smallest local change that fixes it
Do NOT:
- refactor the form-validation helper
- rename variables or change the public API
- add fallback logic or new features
- change upload behavior or unrelated validation rules
- touch markup or styling unless strictly required
Before writing code:
list the exact lines/conditions you plan to change, and any out-of-scope
change you were tempted to make. If the fix needs broader changes, stop
and ask first.
THE OUTPUT SHAPE YOU WANT BACK:
Planned change:
- Adjust the required-file condition so hidden file inputs don't block submit.
Intentionally unchanged:
- upload handler, validation helper, variable names, markup.
Out of scope (noticed, not done):
- the helper has duplicate rule logic; flagging it only, not touching it.
Patch:
<the small diff>
NEXT: read the diff against the "Do NOT" list before you merge. A scoped
prompt makes the small diff likely; it doesn't make it certain -- you are
the one who confirms nothing extra came along.
Where this fits in NewPrompt
Keeping a change small is a prompt-craft move before it is a coding move: you decide the boundary in the request, not in the review. The Prompt Formatter pulls the constraints out of a run-on request into their own section; the Developer Request Prompt Formatter does the coding version, with an explicit don't-touch list; and the Safe Refactoring Prompt shows the fullest form of the discipline — smallest change set, no rewriting unrelated code, and a "suggested but not applied" list for the work it holds back. Each gives you a prompt you run in your own AI tool; NewPrompt structures the request, and the change happens on your side, where you review it.
The nearest neighbor is easy to mix up with this one. Breaking a large task into smaller prompts is for work that is genuinely too big to do safely in one go — you divide it because the whole thing won't fit. This guide is the opposite situation: the task is already small enough, and the model is the one trying to make it bigger. You are not splitting the work; you are capping it. Related but separate: steering output toward acceptance criteria says what the result must include, while this says what the change must not touch — a floor versus a ceiling, and a bounded change usually wants both.
A change you didn't ask for isn't a bonus — it is unrequested work you now have to read, understand, and stand behind, because the moment it merges it is yours as much as the line you wanted. The smallest diff that solves the problem is the one you can actually hold in your head; scoping the request is how you keep the diff that size. The model writes the change; you are the one who signs it — and the fewer surprises in it, the more that signature is worth.