Build your first AI-assisted feature
PLA first AI-assisted feature in Cursor is a small, complete loop: acceptance criteria are written first, Plan Mode turns them into a reviewed plan, the agent builds one step at a time with a commit after each, and tests mapped to each criterion prove the result. The feature is done when that evidence passes, not when the agent reports success.
This tutorial is for a developer who has installed Cursor, written a few project rules, and now wants to ship something real. You ask the agent for rate limiting, it edits nine files in one response, the tests it wrote pass, and you have no idea whether /health is still reachable behind a load balancer. The workflow below keeps each step small enough to check and makes the checking mechanical.
What you get from your first feature build
Section titled “What you get from your first feature build”- A feature-sized task picked by four criteria, so the first run teaches you something without risking production.
- Acceptance criteria written before any code, which become both the plan’s contract and the test list.
- Five copy-paste prompts: plan, build one step, wire in, prove the tests, and a retrospective that updates your rules.
- A verification routine (criterion-to-test map, a deliberate break per test,
git status --short --untracked-files=allandgit diff --stat, a live request) that replaces reading the whole diff. - Recovery steps for the six ways a first feature usually goes wrong.
Which feature should you build first?
Section titled “Which feature should you build first?”Pick a task that exercises the agent without betting anything on it.
| Criterion | Why it matters for a first run |
|---|---|
| Touches 3–8 files | Enough to see whether the agent coordinates changes and follows your conventions; small enough to check each step. |
| Acceptance criteria you can write in five lines | Criteria give the plan a contract and the tests an oracle. Vague tasks produce confident, untestable code. |
| Integrates with existing code | Shows whether your rules and the codebase index steer the agent toward your patterns. |
| Off the critical path | A mistake costs you a revert, not an incident. |
Good first features: an API endpoint with request validation, a webhook handler, a settings panel, a notification-preferences dialog. Leave authentication rewrites and production database migrations for later, when you have a verification routine you trust.
The example on this page is an in-memory rate-limiting middleware for a Node.js API written in TypeScript, with Express and Vitest. It touches middleware, configuration, routing, and tests, and it hides two classic traps (client IP behind a proxy, and timers in tests) that show why evidence beats reading.
Prepare the repository before the agent starts
Section titled “Prepare the repository before the agent starts”-
Start from a clean tree on its own branch. In a terminal:
Terminal window git status --short # must print nothing; commit or stash firstgit switch -c feat/rate-limiter -
Confirm the gates run from one command each, and note them for the prompts. For this example:
npx vitest run,npm run typecheck, andnpm run lint. If your project has no single test or type-check command, fix that first; see making a codebase agent-ready. -
Check that your project rules are committed and describe where middleware lives and how configuration is read. The agent follows what the rules say, so a missing convention shows up as a wrong file location later.
-
Decide which commands the agent may run without asking. If your workspace’s run mode (Auto-review or Allowlist, set under Settings > Agents > Approvals & Execution) lets you pre-approve commands, pre-approve only your test, type-check, and lint commands; otherwise approve them as they come. Keep approval on for everything else. Essential configuration covers the agent settings.
-
Ask the agent one orientation question in a new chat, and compare the answer with what you know: “Where do the HTTP middleware functions in this repository live, and how do they read configuration?” A wrong answer means the index or the rules need attention before you build.
Write the acceptance criteria first
Section titled “Write the acceptance criteria first”Criteria are the one artifact you must read closely, because everything after them is checked against them. Number them so the plan, the tests, and the review can refer to them. See writing acceptance criteria an agent cannot misread for the full method.
AC1 Requests are counted per client IP. Behind our proxy the client IP comes from req.ip with Express "trust proxy" set to 1, never from a raw header.AC2 Window and limit come from RATE_LIMIT_WINDOW_MS (default 900000) and RATE_LIMIT_MAX (default 100).AC3 Request number MAX+1 inside the window gets 429 with a JSON error body in our standard error format and a Retry-After header in whole seconds.AC4 GET /health and GET /ready are never limited.AC5 Counters reset when the window ends (fixed window).AC6 Counters live in memory. Each instance counts separately; this is accepted until the Redis store ships.AC6 is a limitation written down on purpose. A reviewer who knows it is accepted will not waste time on it, and the next person will not mistake it for a bug.
Plan the feature in Plan Mode
Section titled “Plan the feature in Plan Mode”Switch the agent to Plan Mode (Shift+Tab cycles through the modes), which creates an implementation plan before it writes any code. Paste the criteria into the prompt so the plan is built against them.
Review the plan against a short checklist before you let it build:
- Every criterion AC1–AC6 maps to at least one step and one named test.
- New files sit where your existing middleware sits, and the plan reuses your error helper instead of inventing one.
- No new dependency appears unless you asked for one. An unexpected package is a question to answer now, not after it is installed; see dependency checks for agent changes.
- Tests use fake timers (
vi.useFakeTimers()) for AC5 instead of real waiting.
Correct the plan in the same chat (“Middleware goes in src/middleware/, not src/lib/”) until the checklist passes. A correction here costs one sentence; the same correction after the build costs a rewrite.
Build the feature one step at a time
Section titled “Build the feature one step at a time”Leave Plan Mode by switching the chat back to Agent mode, as building in Agent mode shows, and execute the plan step by step. Switching modes starts a fresh context window (Cursor’s help, checked 2026-10-12), so save the accepted plan to a file before you switch and attach it with @ in the first build prompt. One step per prompt keeps each change small enough to check with git status --short --untracked-files=all, which lists modified files and every new, untracked file (marked ??), and gives you a commit to return to. git diff --stat is not enough here: it ignores files the agent created. Keep --untracked-files=all (short form -uall): without it, a new directory collapses to a single dir/ line and hides the files inside it.
-
Build the core module and its unit tests together. Tests written in the same step as the code lock in the criteria while they are fresh.
Then check the scope and commit:
Terminal window git status --short --untracked-files=all # expect only the two files from the promptgit add -A && git commit -m "feat: rate limiter core (AC1, AC3, AC5)" -
Add configuration. Ask for AC2 in its own prompt: “Implement plan step 2: read
RATE_LIMIT_WINDOW_MSandRATE_LIMIT_MAXthe way our other middleware reads config, with the defaults from AC2, and add tests for the defaults and for an override.” Checkgit status --short --untracked-files=all, then commit. -
Wire the middleware into the app. This step touches shared code, so name the file and the exclusions explicitly.
Commit when all three gates pass.
If the agent edits or creates a file you did not name, do not argue with it in the same chat. Go back to the last commit: git reset --hard reverts changes to tracked files, and git clean -fd deletes the untracked files the agent created. git restore . alone is not enough: it reverts tracked files but silently leaves every new file the agent created in place. Preview that deletion with git clean -nd first, because it also removes any untracked file of your own. Then repeat the prompt with the file list and an explicit “Do not touch any other file.”
git clean -nd # preview: lists the untracked files to deletegit reset --hard && git clean -fd # back to the last commitProve the feature works without reading every line
Section titled “Prove the feature works without reading every line”Passing tests the agent wrote prove only that the code agrees with the tests. You need to know that the tests would catch a wrong implementation. The next prompt makes the agent demonstrate that for each criterion; this is a small, manual form of mutation testing. For the concept behind it, see how strong is your test oracle.
A “no” in the table is a real finding: either the criterion has no test or the test cannot fail. Ask for a test that fails when broken, and rerun the table. Then collect the rest of the evidence yourself:
-
Confirm the whole change is the size you expect:
Terminal window git diff --stat main...HEADAny file outside middleware, config,
src/app.ts, and tests needs a reason. -
Confirm no test was weakened. Search the branch diff for skipped or deleted assertions:
Terminal window git diff main...HEAD -- '*.test.ts' | grep -E '^-.*expect\(|^\+.*\.(skip|only)\('An empty result is what you want. The protect-the-oracle guide explains how to enforce this outside the chat.
-
Hit the running server. Set
RATE_LIMIT_MAX=3in your local environment, then start (or restart) your development server so it reads the new value. In another terminal, run the following, replacing/api/itemswith any limited route:Terminal window for i in 1 2 3 4; do curl -s -o /dev/null -w "%{http_code} " http://localhost:3000/api/items; done; echocurl -si http://localhost:3000/api/items | grep -i retry-aftercurl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/healthExpect
200 200 200 429, aRetry-Afterheader, and200from/health. -
Open the pull request with the criteria table in its description. If your team runs Bugbot, it reviews the pull request for bugs, security issues, and code quality problems; treat its findings as input to the reviewer, not as the gate.
The reviewer, you or a teammate, signs off on three things: the criteria, the criterion-to-test table, and the scope from git diff --stat. Reading code is reserved for the parts that the evidence cannot cover, such as the IP-extraction logic in AC1, which carries security weight. Reading evidence instead of code explains where that line sits as your routine matures.
What goes wrong on a first feature, and how to recover
Section titled “What goes wrong on a first feature, and how to recover”| Symptom | Likely cause | Recovery |
|---|---|---|
| The plan puts files in the wrong directory or invents a helper you already have | Rules do not state the convention, or the agent did not look | Correct it in Plan Mode before building, then add the convention to a project rule |
| One prompt edits files you never mentioned | Scope was implied, not stated | Preview with git clean -nd, then git reset --hard && git clean -fd to return to the last commit; repeat with @ references to the exact files and “Do not touch any other file” |
Tests pass, but the live curl check fails | Tests mock the thing that broke (often req.ip or the router) | Ask for an integration test through the real app with supertest, then rerun the break-each-criterion prompt |
| The agent loops on the same failing test | The chat holds several failed attempts that pull the next one toward them | Stop the agent, return to the last commit with git reset --hard && git clean -fd (preview with git clean -nd), and start a new chat with your own diagnosis; see error recovery in Cursor |
| The agent “fixes” a failing test by changing its expectation | Nothing forbade editing tests | Revert the test file; add “Do not modify test files” to the prompt and check with the grep from the proof step. To enforce it mechanically, add it to a project rule or block writes to *.test.ts with a Cursor hook during build steps; see protect the oracle |
A new package appears in package.json | The plan did not rule out dependencies | Revert it unless you approve it, then verify the name and publisher before reinstalling |
Turn the corrections into rules
Section titled “Turn the corrections into rules”Every correction you typed during this feature is a rule the next session should already know. Run a short retrospective before you close the chat.
Accept only rules that would have prevented a real correction. A rule file grown from vague advice costs context on every request and changes nothing.
How the workflow scales to larger features
Section titled “How the workflow scales to larger features”The same loop works for bigger features with three changes. Split the criteria into slices that each end in a passing test, and run one chat per slice so each starts with a clean context. Save the approved plan as a Markdown file in the repository and reference it with @ at the start of each chat, because a plan held only in chat history is gone when the chat ends. Commit per plan step, not per slice, so a bad step never takes good work with it.
When the slices are independent, Cursor can run agents in parallel, each in its own worktree, from the Agents Window (for manual worktrees, see checkpoints and branching); do that only after the single-agent loop above feels routine. For the team-level version of this workflow, see the Build stage of the lifecycle.
Where to go after your first Cursor feature
Section titled “Where to go after your first Cursor feature”Using another agent as well? The same loop in the terminal is on the Claude Code development workflow page, and in Codex on your first Codex task.
Did this guide help you?
One tap, no sign-in.
What will you do with it?
How did it read?
What got in the way? Pick any that apply
Your role?
Thanks. I read every answer. Michał Jaskólski
Did this guide help?
One tap each. Close whenever you like.
no sign-in