Better Code From AI Agents: A Prompt Playbook

A reusable set of prompts I attach to real production tasks — so the agent thinks about security, data integrity, permissions, and edge cases, not just "make it work."

AI coding agents are fast, but by default they optimize for one thing: make this feature work. On a production app, that's the gap between a demo and a system that survives real users — and the danger hides in security, data integrity, permissions, concurrency, and the edge cases nobody typed into the prompt.

So I stopped asking agents to "build X" and started attaching a reusable set of instructions that force senior-engineer behavior. Below is the set I actually use, grouped by concern. Copy any block, paste it with your task, and swap the placeholders for your stack:

{FRAMEWORK} your backend framework {DB} your database {FRONTEND LANGUAGES} your markup, styling & client language {ORM} your query layer

These work for any production app — a SaaS dashboard, an internal tool, an API, a marketplace. Where a prompt needs a concrete example I give one, but the principle is the point — adapt it to your domain.

1 · The core command

This goes on top of almost every task. It stops the agent from blindly rewriting working code, and forces it to inspect first and review after.

Before making changes, inspect the existing implementation: architecture, models, views, templates, {FRONTEND LANGUAGES}, styles, URLs, forms, permissions, and related code.

Do not blindly rewrite working code. Follow the existing architecture and conventions.

Requirements:
- Use {FRAMEWORK} best practices.
- Follow SOLID, DRY, KISS, and separation of concerns.
- Keep business logic out of templates.
- Prefer reusable components / functions / services.
- Use {DB} efficiently; prevent N+1 queries and unnecessary calls.
- Maintain backwards compatibility unless the change explicitly requires otherwise.
- Do not break existing functionality or responsive behavior.
- Keep the code readable, maintainable, and production-ready.

After implementation:
1. Review your own changes.
2. Check edge cases, security, permissions, and validation.
3. Check responsiveness and performance.
4. Test the complete user flow.
5. Fix any issues you find before considering the task complete.

2 · Trace the flow before touching existing code

The single most damage-preventing prompt. It makes the agent understand the whole path before it changes one part of it.

Before modifying this feature, trace the full flow first.

Identify: entry point, URL, view/controller, form/input layer, model,
service/business logic, template, {FRONTEND LANGUAGES}, related permissions,
related APIs, and side effects.

Then make the smallest clean change necessary.
Do not replace large existing sections unless there is a strong architectural reason.

3 · Never trust the frontend

The rule that separates a toy from real software. A user should never be able to send role = admin (or price = 1) and have the backend believe it.

Treat this as production software. Never trust values sent by the client for anything
with security or business meaning: amounts, prices, quotas, permissions, roles,
ownership, status flags, or record IDs.

Recalculate and validate every sensitive value on the server before acting on it.

4 · Security review

Review this change for security vulnerabilities, including:
- authorization bypass and IDOR (insecure direct object access)
- CSRF, XSS, and injection ({DB} / query injection)
- unsafe file uploads and mass assignment
- privilege escalation and sensitive-data exposure
- insecure redirects and session / authentication problems
- rate-limit abuse

Never trust IDs, amounts, roles, permissions, or ownership from the client.
Recalculate and validate sensitive values on the server.

5 · Authorization & data ownership

The moment your app has more than one user, this is non-negotiable — one user must never reach another's data. It only gets more critical if you're multi-tenant.

Enforce authorization and data ownership on every request.

Every query that touches user- or account-owned data must be scoped to the
currently authenticated principal. A user must never read or modify another
user's (or account's) records, files, settings, or history — not by guessing an
ID, not through a related object, not via any endpoint.

Do not rely on hidden client-side IDs for access control.
Check ownership and permissions on the server for every read, write, update, and delete.

6 · Server-authoritative values

Treat every business-critical value as server-authoritative.

Independently compute and validate on the server any value that carries meaning:
amounts and totals, quantities and limits, quotas and usage, entitlements and
plan/role, status and state transitions — before creating or confirming anything.
(For commerce that includes price, discounts, tax, and shipping.)

Never trust a value the client calculated.

7 · Concurrency & limited resources

Agents almost always miss this one. Two requests must not both grab the last available slot.

Consider race conditions and concurrent requests.

For any limited or one-time resource — a counter, a balance, stock, a single-use
token or coupon, a unique slot, a "run once" job — make sure two simultaneous
requests cannot produce invalid state. Use database transactions, atomic
operations, row-level locking, or unique constraints as appropriate.

Example: two requests must not both claim the last available unit, or redeem the same one-time token twice.

8 · Idempotency & external callbacks

Never treat an operation as done because the client reached a success page.

Confirm the real outcome server-side from the source of truth (the provider's
API/webhook, the job result, the external system). Webhook and callback handlers
must: verify signatures, be idempotent, handle retries and out-of-order delivery
safely, reject invalid events, and never double-apply an effect. Store the
external transaction/event IDs for reconciliation.
(Payments are the classic case: verify with the payment provider, never the browser.)

9 · Forms & validation

Audit the entire form and validation flow. Validation must exist BOTH
client-side and server-side — requests can bypass the frontend.

For every field: required vs optional, type, format, allowed ranges, business
rules, and input sanitization. Show clear, human-readable errors; never fail
silently. On failure, indicate what is wrong, where, and how to fix it, and
move focus to the first invalid section.

10 · Database efficiency

Review database usage as part of this task.

Avoid: queries inside loops, repeated queries, loading whole tables, and
unnecessary saves. Where appropriate, use your {ORM}'s eager-loading
(joins / prefetch), existence checks, column-only selects, bulk insert/update,
pagination, and indexes.

Do not optimize prematurely, but fix obvious scalability problems.

11 · Find the hidden problems

I use this constantly. It turns a narrow task into a small, safe cleanup of the surrounding code.

Do not stop at the requested change.

While working in this area, inspect closely related code for obvious bugs,
broken edge cases, security issues, UX problems, and data-integrity risks.
Fix issues directly related to this task when it is safe to do so.
Do not refactor unrelated parts of the project.

12 · Make it actually test its work

Do not consider the task complete just because the code compiles or the page loads.
Test the feature as a real user.

Test: normal flow, empty inputs, invalid inputs, min/max values, duplicate
submission, refresh, back button, unauthorized user, another user's data, nonexistent
objects, network/API failure, mobile layout, and empty-database state.

Fix the problems you discover.

13 · The final senior-engineer review

Probably my favorite one to append to a big task. It makes the agent grade its own work the way a reviewer would — and then fix it.

Now perform a senior-engineer review of everything you changed, as if another
developer opened this as a pull request.

Look for: bugs, security holes, authorization mistakes, bad architecture,
duplicated logic, database inefficiencies, missing validation, missing edge
cases, race conditions, broken responsiveness, weak UX, and accessibility issues.

Do not just explain the problems — fix them, then review the result one final time.

One file to rule them all

If your agent supports a rules file — AGENTS.md, PROJECT_RULES.md, a Cursor or Claude rules file — put the whole standard in one place so you never repeat yourself. This is the master prompt I'd actually commit to a project:

You are working on a production {FRAMEWORK} + {DB} + {FRONTEND LANGUAGES} application.
Operate like a senior software engineer, not a code generator.

Before implementing anything:
- inspect the existing implementation and understand the complete flow
- understand related models, views, templates, {FRONTEND LANGUAGES}, URLs, forms, permissions, and business logic
- follow existing architecture and conventions; reuse existing components when reasonable

Engineering standards: {FRAMEWORK} best practices, SOLID, DRY, KISS, separation
of concerns, clean readable code, reusable architecture, secure-by-default,
server-authoritative business logic.

Never trust the client for security- or business-critical values: amounts, prices,
quotas, permissions, roles, ownership, status flags, or record IDs.
For user- or account-owned resources, always enforce ownership on the server.

Pay special attention to: authentication, authorization, IDOR, CSRF, XSS,
injection, file-upload security, concurrency, transactions, data integrity,
and input validation.

Database: avoid N+1 and queries-in-loops; use eager-loading, pagination, and
indexes when justified; keep migrations production-safe and data-preserving.

Frontend: responsive from mobile to desktop; clean UI/UX; clear validation;
loading / error / success / empty states; prevent duplicate submissions;
accessible and consistent with the design system.

Business logic: compute and validate every authoritative value on the server;
handle concurrent access to shared or limited resources safely; make external
callbacks and retried operations idempotent; never trust a client-reported
"success" — confirm it against the source of truth. (Commerce is one example:
prices, stock, coupons, and payment verification all belong on the server.)

After every implementation: inspect your own diff; test the full flow, invalid
inputs, permissions, access to other users' data, edge cases, and mobile; check
performance, security, and database queries; fix anything you find.

Do not make unnecessary unrelated changes. Do not rewrite working architecture
without a strong reason. Prefer the smallest clean production-quality change.
Before declaring the task complete, review your work as if reviewing a pull
request, and fix anything you would reject.

The part that actually matters

None of these slow the agent down in a way you'll feel. They just move the work — the review, or the 2 a.m. production incident — to the moment the code is written. If you adopt only a few, make these non-negotiable: authorization and data ownership, server-authoritative values, concurrency, idempotency, and honest edge-case testing. That's the line between an average AI-built app and a serious production system. The rest follows.

Shipping real software with AI in the loop?

If you want a second set of eyes on your architecture, security, or your AI-assisted workflow, that's exactly what my consultations are for.