Implementation Prompts
Implementation is where agents do their best work and their most expensive damage: the code arrives fast, compiles, and looks native — so review pressure drops exactly when invented decisions are densest. Every pattern below assumes the prompt anatomy; this page covers what changes per implementation type. Ready-to-fill versions live in the implementation prompt library.
One rule dominates all four patterns: point at existing code instead of describing style. "Follow the pattern in src/routes/invoices.ts" is worth more than any paragraph about your error-handling philosophy, because the agent reads the actual file and copies real structure — middleware order, error envelope shape, naming — instead of interpreting your abstract description. Every adjective you use ("clean", "idiomatic", "consistent") is a decision you just delegated; every file path is a decision you kept.
Product prompts
Building a user-visible capability end to end — new flow, new screen-plus-API, new integration.
When to use: the task is a product outcome, not a code change. Required inputs: the user story with the why, the entry point in the existing product, which existing flows it must resemble, and what's explicitly deferred. What to avoid: describing the feature purely from the user's perspective with zero code anchors — the agent will invent an architecture for it; and bundling more than one user-facing behavior per prompt.
For anything larger than a single flow, don't prompt at all — write a spec first (Idea to Spec) and prompt against the spec.
Mini checklist for reviewing the output:
- [ ] The flow matches an existing flow's structure, not a parallel invented one
- [ ] Deferred items were actually deferred, not half-built
- [ ] No new top-level directories or "framework" abstractions for a single feature
Feature / implementation prompts
The workhorse: a scoped change to an existing system with a known design.
When to use: design decided, code needed. Required inputs: files that define the pattern to follow, precise behavior, acceptance criteria, out-of-scope list. What to avoid: leaving data shapes implicit ("store the preferences" — where, keyed how, migrated how?).
Weak:
Add rate limiting to the API.The agent must pick: which endpoints, what limits, keyed by IP or user or API key, in-memory or Redis, response code and headers, and whether to add a middleware framework. Expect a new express-rate-limit dependency with an in-memory store that silently breaks the moment you run two replicas.
Strong:
Add rate limiting to the public API endpoints in src/routes/public/.
Context:
- We run 3 replicas behind an ALB; state must live in Redis.
Redis client is already configured in src/lib/redis.ts — reuse it.
- Middleware conventions: src/middleware/auth.ts — same style,
same registration point in src/app.ts.
Behavior:
- 100 requests/minute per API key (key extraction already exists:
src/middleware/auth.ts exports getApiKey).
- Sliding window, not fixed window.
- On limit: 429, JSON error envelope matching src/lib/errors.ts,
Retry-After header in seconds.
- Internal routes (src/routes/internal/) untouched.
Constraints: no new dependencies; implement the sliding window
against Redis directly (ZADD/ZREMRANGEBYSCORE approach is fine).
Acceptance:
- Test: 101st request within a minute returns 429 with Retry-After.
- Test: two different API keys don't share a bucket.
- Test: Redis unavailable → fail OPEN (allow request, log error).
This is deliberate: availability over strict limiting.
Out of scope: no per-endpoint configurable limits, no admin UI,
no changes to auth middleware itself.The fail-open line deserves attention: fail-open vs. fail-closed is precisely the kind of judgment call an agent resolves by coin flip, and either default is defensible — which means it will pick without asking. Decisions that are defensible-either-way are the most important ones to state.
Expected output: one middleware file, registration in src/app.ts, tests. Anything beyond that is scope creep.
Mini checklist:
- [ ] Diff touches only the files the task implies
- [ ] Pattern files were actually followed (compare middleware shape side by side)
- [ ] Every acceptance criterion has a corresponding test, and the tests test behavior, not mocks
Backend prompts
Data-layer and service work: endpoints, jobs, queries, schema changes.
When to use: any change where the failure mode is data corruption, not a bad pixel. Required inputs: everything a feature prompt needs plus explicit data semantics — idempotency, transaction boundaries, null/duplicate handling, volume assumptions. What to avoid: letting the agent design a schema unsupervised (schema is an architecture decision); leaving concurrency behavior unstated.
Weak:
Create a webhook handler for Stripe payment events that updates
invoice status.Missing: signature verification, idempotency (Stripe retries — this handler will receive duplicates), event-type filtering, out-of-order delivery, and whether "update status" may ever move an invoice backwards from paid. The weak version yields a handler that marks invoices paid twice and emails the customer twice.
Strong:
Create a Stripe webhook handler: POST /api/webhooks/stripe.
Context:
- Route + error conventions: src/routes/invoices.ts
- Invoice model: src/models/invoice.ts (status enum: draft, sent,
paid, void)
- Stripe SDK already configured: src/lib/stripe.ts
Behavior:
- Verify the Stripe signature (constructEvent with
STRIPE_WEBHOOK_SECRET); invalid signature → 400, log, no body echo.
- Handle only payment_intent.succeeded and payment_intent.
payment_failed; other events → 200 immediately (ack, ignore).
- Idempotent: store processed event IDs in a stripe_events table
(migration included); duplicate event ID → 200 no-op.
- succeeded → invoice status 'paid' + paid_at. Status transitions
only move forward: a 'void' invoice never becomes 'paid' — log a
warning instead.
- DB writes for one event happen in a single transaction.
Acceptance:
- Test: duplicate delivery of the same event ID mutates nothing
the second time.
- Test: bad signature → 400 and no DB writes.
- Test: succeeded event on a 'void' invoice leaves it 'void'.
Out of scope: no refund handling, no customer emails (that's the
existing on-status-change hook's job — do not duplicate it).Expected output: handler, one migration, tests using Stripe's event fixtures. Mini checklist:
- [ ] Idempotency test actually replays the same event, not just a similar one
- [ ] Transaction boundaries match the prompt (grep for writes outside it)
- [ ] Migration is reversible and touches only the new table
UI implementation prompts
When to use: building against an existing design system. Required inputs: the component(s) to imitate by path, the states to handle (loading / empty / error / success), and data-source pointers. What to avoid: adjectives as design direction — "modern and clean" is how you get an agent-flavored redesign of one corner of your app; and unstated state handling, because the happy path is the only one agents build unprompted.
The four states are the UI equivalent of backend idempotency: never assumed, always stated.
Build the invoice-export panel in src/components/invoices/.
Follow ExportPanel patterns from src/components/reports/
ReportExportPanel.tsx — same layout primitives, same hooks style,
same Tailwind conventions. Do not introduce styled-components or
new CSS files.
States (all four required):
- idle: date-range picker (reuse src/components/ui/DateRange.tsx)
+ disabled Export button until range valid
- loading: button spinner, inputs disabled (see ReportExportPanel)
- error: inline error via src/components/ui/Alert.tsx, form stays
filled and retryable
- success: browser download triggers; panel returns to idle
Data: call GET /api/invoices/export via the existing api client
(src/lib/api.ts) — no raw fetch.
Out of scope: no changes to DateRange or Alert, no new routes,
no storybook stories in this pass.Expected output: one component + test; zero changes under src/components/ui/. Mini checklist:
- [ ] All four states reachable and tested
- [ ] No new styling system smuggled in; class usage matches the pattern file
- [ ] Shared components consumed, not forked into local copies
Related
- Prompt Anatomy — the six-component structure these patterns instantiate.
- Prompt Library: Implementation — fill-in-the-blank versions of these prompts.
- Adding a Feature Safely — the full playbook these prompts slot into.
- Shallow Implementation — the failure mode weak implementation prompts feed.
- Reviewing AI Pull Requests — what to do when the diff comes back.