End Every Prompt With a Do-NOT Section
The most powerful part of your prompt is the part that says no. You asked for one endpoint; the agent "helpfully" refactored three others, swapped a dependency, and touched the schema. Nothing you wrote was wrong — you just never drew the boundary. A three-line Do-Not section at the end of the prompt is the cheapest fix in prompt engineering.
Why AI over-builds
Coding agents optimize for a complete-looking result, not a minimal one. Given "add a rate limiter," the model has to guess the blast radius: should it also update the middleware chain? Add a config flag? Pull in a library? When the prompt is silent, the model fills the silence — GitHub's own prompt-engineering guidance says to state requirements explicitly and avoid ambiguity precisely because the model resolves ambiguity on its own. Anthropic's Claude Code guide makes the same point from the other side: the more precise your instructions, the fewer corrections you'll need, and a good spec "states what is out of scope."
Over-building isn't a model bug you can wait out. It's under-specification, and it's yours to fix — in about 15 words.
The Do-Not section
End the prompt with explicit negative constraints, one per line:
Add a rate limiter to POST /api/orders.
Return 429 with a Retry-After header when the limit is hit.
Do NOT:
- modify any existing endpoint
- change the database schema
- add new dependencies (use what's already in package.json)
- touch files outside src/middleware/
Putting it last matters less than making it explicit and checkable: each line is something you can verify in the diff. "Nothing outside the task's scope changed" becomes a review criterion instead of a hope.
Which boundaries to set
| Boundary | Example line | Catches |
|---|---|---|
| Files | "Only touch src/middleware/" | Drive-by refactors |
| Dependencies | "No new packages" | Surprise lockfile churn |
| Interfaces | "Do not change any public API or endpoint" | Breaking consumers |
| Data | "Do not modify the schema or migrations" | Irreversible changes |
| Tests | "Do not delete or skip existing tests" | Green-by-deletion |
| Process | "Do not commit; leave changes staged" | Unwanted side effects |
Three to five lines is the sweet spot. A 20-line Do-Not wall gets skimmed — the same failure mode as a bloated CLAUDE.md, where important rules get lost in the noise.
Power-user moves
- Pair the "no" with a "do." Anthropic's prompting guide notes models follow positive instructions better than pure negations for style ("write flowing prose" beats "don't use markdown"). For scope, hard negatives work — but adding the alternative helps: "Do not add new dependencies; use the stdlib
httpclient." - Promote recurring boundaries. A Do-Not you type every day belongs in
CLAUDE.md(or your agent's project rules file), so it applies to every session. Truly non-negotiable ones belong in deterministic guardrails — e.g. a Claude Code hook that blocks writes to your migrations folder. Prompts are advisory; hooks are enforced. - Close the loop in review. Ask the agent (or a fresh reviewer session) to verify the diff against the Do-Not list: "Confirm nothing outside
src/middleware/changed." Boundaries you can grep for are boundaries that hold. - Scope investigations too. "Investigate the auth flow — do not make any changes" turns an eager agent into a read-only one.
Resources
- Prompting best practices — Anthropic — being explicit about constraints; positive vs. negative instructions
- Prompt engineering for GitHub Copilot Chat — GitHub Docs — avoid ambiguity, state specific requirements
- Claude Code best practices — Anthropic — scoping prompts, out-of-scope specs, hooks as enforced boundaries
- System prompts — Anthropic prompt-engineering guide — where standing rules and boundaries live
Building an AI feature? Yeda AI designs, audits, and ships production LLM systems.