# Pair programming with Cursor's agent

URL: https://developertoolkit.ai/en/cursor-ide/build/pair-programming/
Description: Pair with Cursor's agent on one feature: agree the design in Plan Mode, build test-first slices, debug from evidence, and verify each step by command.

Pair programming with Cursor's agent is a session in which a developer and the agent split driver and navigator roles across one feature. Plan Mode settles the design, Agent mode builds one test-first slice at a time, and debugging starts from a failing test. The developer owns the acceptance criteria and the evidence; the agent does most of the typing.

**Documentation freshness**

**Covers:** the Cursor 3.x line; the current release on 2026-10-12 is Cursor 3.24 (2026-10-09, Cursor's release notes). Plan Mode, Rules and Bugbot were verified against Cursor's docs on 28 August 2026; Cursor's SDK (1.0.32, 22 September 2026) confirms the agent and plan modes. Cursor's docs and help, checked 2026-10-12, list four modes (Agent, Ask, Plan and Debug) and say that Shift+Tab cycles through them, that checkpoints are stored locally and separate from Git and restoring one reverts files only, and that Enter queues a message while **Send a follow-up now** steers the active turn at the agent's next tool call. Cursor's pages on those topics could not be reached on 26 September 2026, so every step below still works with Plan Mode, Agent mode and Git alone.

This page is for developers who already use Cursor's agent for single tasks (see [Agent chat in Cursor](/en/cursor-ide/build/agent-chat/)) and now want it on a whole feature. The situation: you are building notification preferences with per-channel settings, organization defaults that users override, and timezone-aware delivery windows. The happy path is an afternoon. The edge cases are where it goes wrong, and one long "build the whole thing" prompt returns 600 lines you cannot check.

## What you'll walk away with from a pairing session in Cursor

- A role table that says who drives in each phase and which piece of evidence closes it
- Four copy-paste prompts: a design session, a read-only design fork, a test-first build slice, and an evidence-first debugging detour
- A per-step check (red test, green test, diff inside the plan, one commit) that replaces reading every line
- A way to stop the same correction from coming back, and a way to carry the session into a new chat
- Recovery steps for the six ways a pairing session goes wrong

## Who drives when you pair with Cursor's agent?

In human pair programming, the driver types and the navigator watches direction. With an agent, the agent drives almost every keystroke, so your job moves to the navigator's seat full-time: you set the direction, define "done" for each step, and check the evidence. This is [AI pair programming](/en/glossary/ai-pair-programming/): the agent is the second programmer, and you steer. The table is the whole method; the sections below fill it in.

| Phase | The agent drives | You navigate | Evidence that closes the phase |
| --- | --- | --- | --- |
| Design | Reads the code, proposes a plan, asks questions | Answer the questions, choose at every fork, cut scope | A saved plan: numbered slices, a file list, one test per acceptance criterion |
| Build a slice | Writes the test, then the code, then runs the checks | Name the slice, the files, and what must not change | The new test failed first and passes now; the verify command is green; the diff stays inside the file list |
| Debug detour | Reproduces the bug in a test, proposes hypotheses, adds logging | Pick the hypothesis to test; refuse fixes before proof | A failing test or log line that confirms one cause |
| Handoff | Writes a short state note | Check the note in 30 seconds | A note with decisions, done slices and the next step |
| Pull request | Summarises what changed and why | Read the tests and any file the evidence flags | CI green, review comments resolved |

The one rule behind the table: **no slice ends on the agent's word.** Each one ends on a command you or CI can re-run.

## Set up the session before the first prompt

Five minutes of setup makes every later step checkable.

1. Start a branch from a clean tree: `git switch -c feat/notification-prefs`. Keep one terminal of your own open for checks; the agent's terminal output is its report, not your evidence.
2. Know your verify command, the one CI runs: for example `npm run verify` wrapping type check, lint and tests. If the repository has none, write one before you pair, because every slice below ends on it.
3. Write the acceptance criteria down before the agent sees the task, in plain sentences you could turn into tests: "A user with no preferences receives the organization default for every channel." If you cannot write them yet, the design session below is where they come from. [Executable acceptance criteria](/en/workflows/plan/acceptance-criteria/) shows the format.
4. Check that your project rules cover logging, error handling and data access, so you do not correct the same pattern in every slice. [Project rules in Cursor](/en/cursor-ide/quick-start/project-rules/) covers the file location and load modes.

## Agree the design in Plan Mode

Plan Mode, in Cursor's words, "creates detailed implementation plans before writing any code" ([Plan Mode docs](https://cursor.com/docs/agent/plan-mode), verified 28 August 2026). That is the navigator's first job: agree the route before anyone drives. Open a new chat, start the chat in Plan Mode, and paste the prompt.

**Copy-paste prompt: open a pairing session in Plan Mode**

```text
We are pairing on a notification preferences feature. Requirements:
- Users set preferences per channel: email, sms, push, in_app.
- Organizations set defaults; a user's own setting overrides the default.
- Each preference can have a delivery window (start, end, IANA timezone).
- GET /api/preferences/preview returns what a user would receive right now.

Before proposing anything, read the existing user, organization and
notification code and list the files you read.

Then ask me every question whose answer changes the design. Wait for my answers.

After my answers, write a plan with:
1. Slices small enough that each one ends with one new test passing.
   Order them so the data model comes first and the preview endpoint last.
2. For each slice: files to create or change, and the test that proves it.
3. The edge cases you would test: midnight-crossing windows, DST changes,
   a user with no preferences, an organization with no defaults.
4. What you will NOT build in this feature.
Save the plan to docs/plans/notification-preferences.md and the file list,
one path per line, to docs/plans/notification-preferences.files.
```

Push back on the plan the way you would with a colleague. Cut a slice that exists only "for future flexibility". Ask why a new table is needed if an existing one could carry a column. When a question has two reasonable answers, do not let the agent choose silently: ask for a comparison in which it may not edit anything.

**Copy-paste prompt: settle a design fork without edits**

```text
Do not edit any files in this turn. Read @docs/plans/notification-preferences.md
and the existing models it names.

I am choosing between:
A) One preferences table with a scope column ('organization' | 'user'),
   merged at query time.
B) Separate org_preferences and user_preferences tables, merged in the
   service layer.

For each option, answer with file paths from this repository:
- The query that answers "what does user X receive on channel Y right now?"
- What happens when the user has no row for a channel.
- What changes if we add team-level preferences next quarter.
- Which existing table or service it most resembles.
Finish with your recommendation and the one fact that would change it.
```

You make the call, and the plan file records it. Cursor's read-only Ask mode suits this prompt; the "do not edit" line keeps the prompt safe in any mode. [Cursor agent modes](/en/cursor-ide/build/agent-modes-deep-dive/) covers when to use each mode in more depth.

When the plan is final, commit it in your own terminal and tag the base that every scope check compares against. A tag, unlike a shell variable, is still there when you reopen the terminal or pick the work up in a new chat:

```bash
git add docs/plans && git commit -m "docs: notification preferences plan"
git tag -f plan-base                    # durable base; survives a closed terminal
```

## Build one slice at a time in Agent mode

Switch to Agent mode and hand over one slice. A slice ends with one new test passing and a green verify command, which keeps each diff small enough for the per-step check below to be meaningful.

**Copy-paste prompt: build one test-first slice**

```text
Implement slice 1 of @docs/plans/notification-preferences.md
(the preferences data model and migration). Follow the patterns in
@src/lib/db/schema.ts exactly.

Work in this order and stop at each marker:
1. Write the test for slice 1 first. Run it and show me that it fails,
   and why. STOP and wait for me.
2. After I reply "go", write the minimum code to make it pass.
3. Run `npm run verify` and paste the last 20 lines of output.

Rules for this slice:
- Change only the files the plan lists for slice 1 (see the plan's slice 1 section).
- Do not create API routes, services or UI; those are later slices.
- Do not add dependencies.
- If you think the plan is wrong, say so and stop instead of improvising.
```

The stop after the failing test is the most valuable pause in the session. A test that fails for the right reason proves it tests something; a test written after the code often passes whatever the code does. Read the test, not the implementation: it is 20 lines, and it is the specification the code will be held to.

When the agent reports green, check the evidence yourself before the next slice:

```bash
# Run in your terminal, not the agent's.
npm run verify                          # the same gate CI runs
git add -A                              # stage everything, new files included
git diff --cached --stat                # size and spread of the change
git diff --cached --name-only plan-base -- . ':!docs/plans' ':!docs/handoff' \
  | grep -vxF -f docs/plans/notification-preferences.files
git commit -m "feat(prefs): slice 1 - preferences model"
```

Empty output from the `grep` line means every changed file is on the plan. The two `:!` pathspecs leave out the plan and handoff files themselves, so adding a gap to the plan or writing a handoff note later does not show up as drift. The `.files` list covers the whole feature, so this check proves the change stays inside the plan, not inside slice 1; compare the `--stat` output with the plan's slice 1 section for that. A printed path is either a real gap, which you add to the plan file, or drift, which you unstage and revert with `git restore --staged --worktree PATH` (or `git rm --cached PATH` and delete it, for a new file). Commit every green slice: each commit is a known-good point you can return to, and it keeps the next slice's diff separate. If your Cursor build keeps its own checkpoints, [Checkpoints and branching](/en/cursor-ide/build/checkpoints-branching/) explains how they fit alongside these commits.

If something is wrong, say exactly what and why, in one message:

```text
The migration stores delivery_window_start as a timestamp with timezone.
Use a plain time column, because the timezone lives in its own column.
Add a unique constraint on (scope_type, scope_id, channel). Re-run the
slice 1 test and npm run verify, and change nothing else.
```

## Keep the agent on your architecture

An agent that drives most of the keystrokes drifts in predictable ways: a new date library, a second logging style, a query the plan never mentioned. Three habits keep it on your road.

**Fence each slice with what must not happen.** Negative constraints are cheap and easy for the agent to follow:

```text
Implement the delivery-window check in src/services/preferences.ts. Do NOT:
- add a date library; use the helpers in src/lib/time.ts
- add a database query; use the preferences already loaded by the caller
- change the signature of isWithinDeliveryWindow()
```

**Point at an example, do not describe one.** `Follow the error handling in @src/services/orders.ts` beats a paragraph about your error classes. [Context management in Cursor](/en/cursor-ide/quick-start/context-management/) covers choosing that one canonical file.

**Promote a repeated correction into a rule.** The second time you type "use the logger from `src/lib/logger.ts`, not `console.log`", stop pairing for two minutes and ask the agent to draft a project rule with that line. Review it, commit it, and the correction stops recurring in this chat and in your colleagues' chats. [Project rules in Cursor](/en/cursor-ide/quick-start/project-rules/) shows how to prove with a probe task that the rule loads.

## Take a debugging detour without losing the thread

Bugs surface mid-feature. The trap is letting the agent "try a fix" on a guess: it will produce plausible changes until one happens to pass, and the session loses its plan. Make the detour evidence-first and fence it.

**Copy-paste prompt: evidence-first debugging detour**

```text
Detour from slice 5. Do not change production code until I say so.

Symptom: GET /api/preferences/preview?user_id=abc-123 returns []
although the user's organization has defaults for email and push.
What I know: the merge function passes its own tests in isolation;
org preference rows exist in the local database.

1. Write a failing test that reproduces this through the route handler.
   Run it and show the failure.
2. List at most three hypotheses, each with the file and line it points at.
3. For the most likely one, add temporary logging or an assertion that
   would confirm or rule it out. Run the test again and show the output.
4. STOP. Tell me which hypothesis the evidence confirms.
```

Once the evidence confirms a cause, say "fix it", and the failing test becomes the proof of the fix. Ask the agent to remove the temporary logging, then run the verify command and commit the fix as its own commit before you return to slice 5. Cursor's Debug mode, listed for tricky bugs that need runtime evidence, runs a similar hypothesis-and-logging loop; the prompt above works in Agent mode either way. [Bug hunting in Cursor](/en/cursor-ide/test/bug-hunting/) covers longer investigations.

## Carry a long session across chats

A feature can take longer than one chat stays useful. The signs: the agent repeats a mistake you already corrected, or forgets a decision from an hour ago. Do not argue with a long history. Close the chat with a handoff note and continue in a new one, following the handoff prompt in [Context management in Cursor](/en/cursor-ide/quick-start/context-management/). The plan file, the committed slices and the note carry the state, so the new chat starts with:

```text
Read @docs/plans/notification-preferences.md and @docs/handoff/notification-prefs.md.
Slices 1-4 are committed (see git log). Continue with slice 5 exactly as planned,
test first, and stop after showing me the failing test.
```

Because every finished slice is a commit with a green verify command, you lose nothing when a chat ends.

## How do you verify a pairing session without reading every line?

You read three things closely: the plan, each new test, and any file that the scope check flags. Everything else is covered by commands that do not depend on the agent's report.

| Check | When | What it proves | Who signs off |
| --- | --- | --- | --- |
| Test fails before the code exists | Every slice | The test checks the behaviour, not just the code that was written | You |
| `npm run verify` in your own terminal | Every slice, and in CI | Types, lint and the whole suite pass, not only the new test | You, then CI |
| Scope check against the plan's file list | Every slice | The agent changed nothing it was not asked to | You |
| One commit per green slice | Every slice | Each step is reversible on its own | You |
| Criteria-to-test map in the PR description | Pull request | Every acceptance criterion has a named test | The reviewer, who reads the map and the tests |
| Bugbot or another review agent on the PR | Pull request | A second reader for bugs and security issues across the whole diff | The reviewer decides what to act on |

[Bugbot](/en/cursor-ide/ship/bugbot/) reviews pull requests for bugs, security issues and code quality problems, and [Code review in Cursor](/en/cursor-ide/ship/code-review/) shows how to layer it with a human reviewer. For the wider argument that reviewers should read evidence instead of whole diffs, see [evidence, not diffs](/en/ladder/evidence-not-diffs/) and the [evidence bundle for agent pull requests](/en/workflows/ship/evidence-bundle/).

## What breaks when you pair with Cursor's agent?

| Symptom | Likely cause | Recovery |
| --- | --- | --- |
| The agent improvises beyond the plan | The plan file is not in the chat, or the slice was vague | `@`-mention the plan in every build prompt and name the slice by number. Revert extra tracked files with `git restore --staged --worktree PATH`; delete extra new files (after `git rm --cached PATH` if they are staged) |
| You asked for the model and got the model, routes and tests | No stop condition in the prompt | Add "Do not create routes, services or UI" and a STOP marker. Keep only the slice's files, then commit |
| Corrections stop sticking | The chat history carries old attempts that compete with your corrections | Write a handoff note and start a new chat; turn the correction into a project rule |
| Three prompts in, the approach is wrong | The design fork was settled by the agent, not by you | Discard the uncommitted slice with `git restore --staged --worktree .`, then `git clean -n` to preview and `git clean -f` to remove any untracked files that are left, go back to the design-fork prompt, and update the plan before rebuilding |
| Tests pass, but the feature is wrong | An acceptance criterion had no test, or the test was written after the code | Add the missing criterion to the plan, write its test and watch it fail, then fix |
| The agent says "all tests pass", CI disagrees | The agent ran a subset or read stale output | Treat only your own terminal and CI as evidence. Ask the agent to run the exact verify command and paste its output |

## Where to go next with pairing in Cursor

- [Cursor agent modes](/en/cursor-ide/build/agent-modes-deep-dive/) — When to plan, investigate, build or debug, and the evidence that ends each mode.
- [Checkpoints and branching](/en/cursor-ide/build/checkpoints-branching/) — Undo one agent turn or a whole experiment, and keep only verified changes.
- [Test-driven development with Cursor](/en/cursor-ide/test/testing-tdd/) — Make the failing test the specification every slice is held to.
- [Human-AI collaboration patterns](/en/method/principles/human-in-the-loop/) — Where a person must decide, and where evidence can decide instead.
