I timed it.
Fourteen minutes. One prompt: disable the save button while the Server Action is pending.
What I got back:
-
'use client'at the top ofapp/(dashboard)/invoices/page.tsx -
useEffectfetching/api/invoicesfor data the server already had -
as Useronres.json() - a new
useInvoiceStore.tsnobody asked for - the save button still not disabled
The original file was 78 lines, compiled, and rendered the list. The agent replaced it because a client event handler is illegal in a Server Component and the cheapest local move is "make the whole file a client." That move costs a waterfall, a cache miss, and an auth check that now lives wherever the fetch happens to run.
I started counting the pattern in my own sessions over a week of after-hours work:
| Failure | Times I undid it |
|---|---|
| use client lifted to the page | 11 |
| formData.get(id) as string / String(formData.get()) | 9 |
| Edited components/ui/button.tsx to add a product variant | 4 |
| Middleware redirect treated as authorization | 3 |
| Deleted a test because it failed after a rename | 2 |
None of those are model-capability problems. They are missing constraints. Cursor will follow a 40-line .mdc file with globs on app/**/*.tsx more faithfully than it will follow a 2,000-word blog post you pasted into the prompt once.
So I wrote the constraints down as files the agent actually loads:
- architecture — RSC default, client at the leaf, no function props across the boundary, schema on searchParams / formData
- typescript — no any, parse unknown, branded ids, discriminated UI state
- ui — wrap shadcn, do not edit
components/ui, four states on every list - testing — getByRole first, no page snapshots, Server Actions tested as functions
- git / PRs — no git add everything from root, conventional titles,
.env.exampleonly - security — secrets not in git, authz inside the action, no localStorage sessions
Plus six skills the agent can run on demand: plan before edit, do not rewrite working files, copy pass, a11y pass, PR description, launch checklist.
Install is not a package. You copy the rules folder and AGENTS.md into the Next.js app. Sixty seconds. The point is not more prose — it is fewer sessions that end with git checkout -- app.
If you want the pack: Cursor Agent Ship Kit (USD 19, personal license, refund via Getly).
If you only want the habit: next time the agent wants to recreate a file that already works, the right patch is three lines on the existing Button, not a new folder.













