Coding Prompt Structure That Works

Goal + constraints + acceptance criteria. Skip any and the AI guesses.

What this covers

Most “AI wrote bad code” stories are really “I wrote a bad prompt” stories. The single biggest leverage move when prompting an AI to write code is structural: goal, constraints, acceptance criteria, hand-off rule. Skip any one of the four and the model fills the gap with assumptions — usually generic, sometimes wrong, occasionally catastrophic. This guide is the template, the worked example, and the failure modes that disappear once you commit to the structure.

Who this is for

Anyone prompting an AI to write code: Cursor users, Claude Code users, Codex users, ChatGPT-on-the-side users, agents and autocomplete alike. Especially useful for engineers whose AI output looks fine but breaks during review or in production.

When to reach for it

Before any non-trivial coding prompt — a new feature, a refactor, a bug fix that touches multiple files. Skip for genuinely one-line tweaks or completions where structure is overkill.

Before you start

  • Know which files the change should touch and which it should not. Vague scope kills more PRs than vague goals.
  • Have one concrete acceptance test in mind. If you cannot write the test, you do not yet know what “done” looks like.
  • Know your project conventions: naming, error handling, async style. The AI will guess these unless you supply them.
  • Decide whether you want a plan first or code first. Plan-first costs 30 seconds and saves 30 minutes when the goal is ambiguous.

Step by step

  1. Goal: one sentence, specific, with measurable scope.
    • Bad: “Improve the login flow.”
    • Good: “Add rate limiting to /api/login to block more than 5 failed attempts in 15 minutes per IP, returning 429.”
  2. Constraints: language, framework, files to touch, files to NOT touch, existing patterns to mirror.
    • “Use the existing rate-limit helper in src/middleware/rate-limit.ts. Do not add new dependencies. Do not modify other API routes.”
  3. Acceptance criteria: one test or one observable behavior that proves it works.
    • “A unit test in src/api/__tests__/login.test.ts asserts that the 6th attempt within 15 minutes returns 429 with the existing error format.”
  4. Hand-off rule: how much autonomy the AI has.
    • “Plan first. List the files you intend to change and the test name. Do not write code until I approve the plan.”

A worked example

Goal:
Add rate limiting to /api/login to block more than 5 failed
attempts in 15 minutes per IP, returning HTTP 429.

Constraints:
- Use src/middleware/rate-limit.ts; do not add new dependencies.
- Do not modify other API routes.
- Match the existing error response format (see auth.ts).
- Failed attempts only — successful logins reset the counter.

Acceptance:
- New unit test in src/api/__tests__/login.test.ts asserts the
  6th failed attempt within 15 minutes returns 429 with the
  standard error JSON.
- Existing login tests still pass.
- No console warnings during npm test.

Hand-off:
Plan first. List target files and test name. Wait for approval
before writing code.

This prompt produces a usable plan in any modern coding agent. The same skeleton works for refactors, bug fixes, and dependency upgrades.

First-run exercise

  1. Pick a coding task you would normally describe in one sentence. Write the one-sentence version first.
  2. Now rewrite it using the four-block structure. Resist the urge to be brief — the structure pays off when it is complete.
  3. Send both versions to the same coding agent in separate chats. Compare outputs.
  4. Note the gap. Usually the structured prompt’s output ships and the one-line prompt’s output needs a rewrite.

Quality check

  • Did the AI honor every constraint? Diff the affected files; anything outside the constraints is a bug regardless of how clever the change is.
  • Does the acceptance test exist and pass? “Looks right” is not a substitute for a passing test.
  • Did the AI add anything you did not ask for? “Helpful” extras are a common failure mode and should be reverted.
  • Read the code. Even with structure, AI output is reviewable first-draft, not merge-ready.

How to reuse this workflow

  • Save the four-block template as a snippet. Same template, fresh content per task.
  • Maintain an AGENTS.md or CONTRIBUTING.md with project conventions — the AI will read it as part of context.
  • Log prompts that produced clean PRs and ones that did not. The patterns surface within a week.
  • Re-test the template quarterly. Model behavior shifts; what worked in spring may need tweaks in autumn.

Goal (one sentence, specific) + constraints (touch/do-not-touch, existing patterns) + acceptance (one test or behavior) + hand-off (plan-first or direct) → execute → review against the four blocks before merging.

Common mistakes

  • One-liner prompts. “Add rate limiting” produces a different rate limiter every time.
  • No acceptance criteria. Without a test, “done” drifts to whatever the model felt good about.
  • Missing constraints. The AI will pick conventions; sometimes wrong, often inconsistent with your codebase.
  • Skipping hand-off rule. Plan-first prevents 80% of “the AI wrote 200 lines I have to throw away.”
  • Reusing yesterday’s prompt without updating constraints. Codebases drift; prompts must too.
  • Treating the structure as bureaucracy. It is the structure that makes the difference; brevity is a separate skill.

FAQ

  • Does this work for autocomplete-style assistants?: Partially. Autocomplete favors brevity. Use the four-block structure for Composer, Cursor Agent, Claude Code, Codex, and Aider.
  • What if I do not know the constraints yet?: Ask the AI to propose them, then approve or edit. “Propose 3 constraints before writing code” is a valid first message.
  • How long should the prompt be?: 100-300 words for typical work. Longer when constraints stack up; shorter is suspicious.
  • Can I skip the hand-off rule for trusted models?: On simple tasks, yes. On anything multi-file or production-bound, keep plan-first.

Tags: #AI coding #Tutorial