Skip to content
OTFotf
All posts

5 Proven Cursor Prompt Patterns for Shipping Real Features in Existing Codebases

D
DaveAuthor
8 min read
5 Proven Cursor Prompt Patterns for Shipping Real Features in Existing Codebases

1. Five prompt patterns that ship real features

Cursor is a genuinely good agent surface for greenfield work. Type "build me a kanban board", watch a coherent UI appear, ship to staging in twenty minutes. For an existing codebase with a hundred thousand lines of conventions, the same prompt returns a different result every run and burns a million tokens getting worse. The fix is not a better model. The fix is a prompt that constrains the model to match what is already there.

Below are five prompt patterns that ship real features against an existing codebase. Every one is a template — copy, swap the names, run. Every one is grounded in patterns that produce tested diffs, not regenerations.

The vertical-slice prompt

When the goal is "add a new entity end-to-end":

Look at how `src/features/invoices/` is structured: schema in `db/schema.ts`,
queries in `queries.ts`, server actions in `actions.ts`, UI in `components/`.

Add a `customers` feature with the same shape:
- schema: id, org_id, name, email, created_at — same FK + index pattern as invoices
- queries: listCustomers, getCustomer
- server actions: createCustomer, updateCustomer, deleteCustomer
- UI: list page at `/customers`, detail page at `/customers/[id]`,
  form at `/customers/new`

Match the existing error handling, validation, and revalidation calls exactly.
Do not introduce a new state library. Do not create utility files.

Run typecheck and tests for the new feature. Fix until clean.
Report the final diff when done.

The mechanism: the prompt names a sibling feature, lists the exact files, and tells the model what shape to mirror. Without that, the model invents a folder structure based on whatever it last read, which has nothing to do with the codebase.

The match-the-app prompt

When the goal is "add a new screen that does not look bolted on":

Open `src/components/screens/`. Read the three most-recently-added screens.

Build a new screen `BillingSettings` that:
- uses the same header layout (PageHeader with breadcrumbs)
- uses the same form components (FormField, FormSection)
- uses the same data-fetching pattern (server component → queries.ts)
- matches the same spacing rhythm (space-y-6 between sections)

After writing it, run typecheck and fix until clean.
Do not invent new components. If a primitive is missing, extend an existing one.

The pattern is sibling-aware. The model is told to read siblings before writing. Without that instruction, it reaches for whatever component names it has seen most in training, which are usually wrong for the project.

The follow-the-existing-flow prompt

When the goal is wiring auth, billing, or any cross-cutting integration:

The codebase already has Google OAuth wired in `src/lib/auth/`.

Add a "magic link" fallback:
- replicate the provider shape exactly (same `signIn` callback, same `session`
  shape, same `user` augmentation)
- do not touch existing providers
- do not refactor anything outside `src/lib/auth/magic-link/` and the
  new `/auth/verify` page

If you find an inconsistency in the existing auth code, STOP and tell me.
Do not silently fix it.

The mechanism is an explicit blast radius. The model is told exactly which directories may change. Anything else, it stops. This single constraint eliminates the most common failure mode — the agent "improving" code it was not asked to touch and producing an unreviewable diff.

The investigate-before-writing prompt

When the goal is a refactor or a change to a load-bearing file:

Before changing anything in `src/lib/billing/`:

1. read every file in that directory
2. list the exported functions and what they call
3. identify the Stripe webhook handler and what events it handles
4. report: what would break if I added a `subscription.updated` handler?

Do not write any code. Investigate and report only.

This is the cheapest prompt in the kit and the highest-use one. It forces the model to spend tokens reading, not generating. A clear report means the next prompt can be surgical. A vague report means another full-context sweep later.

The refactor-with-gates prompt

When the goal is rename, extract, or restructure:

Rename `useOrgContext``useOrg` across the codebase.

Constraints:
- preserve the exact return shape
- preserve all callers — change call sites only where the rename forces it
- if a call site relies on a deprecated field, leave a `// TODO` with the field
  name; do not silently rename

Steps:
1. grep for `useOrgContext`, list every file
2. rename + update imports
3. run typecheck and tests until clean
4. if anything breaks, STOP and show me the diff before continuing

The pattern is named gates. Each step is a checkpoint the model must pass before continuing. The STOP and show me the diff line is the most important one — it converts a runaway refactor into a reviewable one.

a Cursor agent loop — user sends a constrained prompt, agent reads sibling files, agent wr

These five prompts are the parts that survive every model swap.

2. Why these patterns work

The five patterns share three structural properties that the open-ended prompts lack.

Reference existing files by name. Every prompt names a sibling directory, a file, or a pattern. The model has more context about files it can see than files it has to guess. A prompt without a reference is a request for the model to guess, and the model will guess confidently and incorrectly. Naming src/features/invoices/ is worth a thousand tokens of "follow the codebase conventions."

Constrain the blast radius. "Do not touch X", "do not introduce Y", "match the existing Z exactly". Every constraint is a token the model does not have to spend deciding. Open-ended prompts trade tokens for decisions, and the model's decisions are rarely what the codebase wants.

Demand validation in the same turn. Run typecheck, run tests, "stop and report". The model is forced to verify before claiming success. Without this, the model reports "I've added the feature" and ships a file that does not compile — and the next prompt has to diagnose a problem the model never knew it caused.

The three properties compound. Drop any one and the prompt returns to the open-ended guesswork that burns tokens.

11 production screens. Login, database, payments — all wired.

The SaaS Dashboard Kit ships everything already connected. Nothing to set up. Live demo at saas.otf-kit.dev.

See the live demo

3. The anti-patterns that burn tokens

These are the prompts that look reasonable and produce nothing shippable:

PromptWhy it fails
"Add authentication"No reference to existing auth pattern; model invents one.
"Refactor the billing code"Open-ended scope; model rewrites half the module.
"Make this screen look better""Better" is undefined; model picks one of 200 visual styles.
"Fix the bug"No reproduction; model guesses at the failure mode.
"Use best practices for the API route""Best practices" is whatever the model last saw.

The token cost of every entry above follows the same shape: each "try again" cycle is another full-context sweep, and the model has to re-derive what "good" means from scratch. The fix is never more tokens. The fix is a more constrained prompt. The five patterns above are not magic — they are the minimum structure that survives contact with a real codebase.

4. How OTF bakes these patterns in

The five patterns above are not abstract. They are the working library OTF ships in every kit's ai/prompts/ directory — twenty-plus tested prompts, plus a CLAUDE.md and a .cursorrules that tell the agent what conventions to match before the first prompt is even sent.

That means when you clone an OTF kit — say, the SaaS Dashboard, which ships with auth, billing, DB, and Stripe wired — and open it in Cursor, the agent already knows which directories hold the patterns the prompts above reference. You do not have to write the match-the-app prompt from scratch. It is already there, parameterised for the kit. You write "add a projects entity" and the prompt template fills in the sibling directory for you.

The interesting part is what this is not. It is not "Cursor rules OTF does not". Cursor is a genuinely good agent surface. The five patterns above work in Cursor today, in Claude Code tomorrow, in whatever agent ships next month. The patterns are the durable layer. The tool is the variable.

a single shared conventions file — the durable layer that survives every model swap, every

5. What this gets us

A team that adopts these patterns ships features the model has not been trained on, against codebases the model has never seen, with diffs that pass typecheck and tests on the first run. The model does the typing. The engineer does the design — which sibling to mirror, which blast radius to draw, which gate to stand behind.

The patterns work in Cursor today. They work in Claude Code. They work in whatever agent ships next quarter. The shape of the prompt is what survives; the surface that runs it is interchangeable.

6. The lesson

Prompts are engineering artifacts, not vibes. A working prompt names files, constrains scope, demands gates. Anything less is a request for the model to hallucinate a project that does not exist, into a project that does.

Use the five patterns above in Cursor today. They are the part that survives every model swap — and OTF ships them pre-built, so the first half is cheap to start.

ai-toolstemplatesbackend
OTF SaaS Dashboard Kit

Ship the product, not the setup.

  • 11 production screens — auth, billing, team, analytics, settings
  • Real database, payments, and login — all wired on day 1
  • AI configs pre-tuned so your agent extends instead of regenerates