Course · Cursor · Getting started
Ship your first reviewed change with Cursor
Here is the change you’ll ship, driving the loop yourself. The course’s illustrative repo, budgetcli - a small self-hosted personal-finance API that tracks accounts, imports bank statements from CSV exports, and flags overspend - has a bug in its CSV importer: a statement row that plainly reads one day lands in the database as another. No sample CSV or database ships with this site, so build the check yourself: in your repo, or in a disposable TypeScript repo, write a two-line CSV with a header and one row dated 03/02/2026 (3 February, day first), run it through the importer, and compare the date it returns with the date in the row. An importer that splits the day, month, and year and then hands the rebuilt DD/MM/YYYY string to Date.parse() returns a March date, because Node reads that string month first. Only some rows are wrong, which is the tell - the importer assumes one fixed date format, so a bank that writes dates differently gets silently misread. The change to ship: make the importer handle the common bank date formats, pin the broken case with a test, and commit it once you’ve reviewed the diff.
Describe the outcome, not the steps
Section titled “Describe the outcome, not the steps”Open the Agent sidebar (Cursor’s chat panel, Cmd/Ctrl+I - not Tab, which is inline completion) and tell it what’s wrong in terms of behavior:
> the CSV importer is parsing some statement dates into the wrong day - it looks like it assumes one date format. Make it handle the common bank date formats correctly, and add a test that pins down the case that's currently broken.Notice what you didn’t say. You didn’t name the function, didn’t paste the parsing code, didn’t spell out the test framework. You stated the what and left the how to the Agent - and on a repo you don’t know yet, that’s deliberate: you’re letting Cursor do the part it’s genuinely better at than you right now (finding the relevant code in an unfamiliar codebase) while you stay the judge of whether its answer is right. Here’s an illustrative run of the whole turn:
Read src/importers/csv.ts, tests/csv-import.test.ts (2 files)
The importer parses every row's date with a single hardcoded format, so a statement using a different one is silently parsed wrong. I'll make it try the common formats in order and fail loudly if none match, and add a test covering the format that's currently broken.
Edited src/importers/csv.ts - const parsed = new Date(Date.parse(`${day}/${month}/${year}`)); + const parsed = parseStatementDate(dateStr);
Edited tests/csv-import.test.ts Ran npx vitest run tests/csv-import.test.ts → 2 passedIt read the relevant files first - including the existing test, so its new test would match the house style instead of inventing one. It proposed a plan in two sentences. Then - and here’s where Cursor differs from a terminal agent that stops and asks before every write - the Agent applied the edits to your files as it worked, showed them to you as red/green inline diffs, and ran the test itself to check its own work.
That difference is worth sitting with for a second, because it’s the heart of Cursor’s review model and the thing the next two sections are about.
Cursor edits first, then you review - so the review is the gate
Section titled “Cursor edits first, then you review - so the review is the gate”In a terminal agent the leash is the approval prompt: nothing touches disk until you say yes. In Cursor’s Agent sidebar the leash is the review pane: the edits land in your working tree immediately, rendered as red/green diffs you can read in the editor, and they stay in a pending, reviewable state until you decide what to do with them. The checkpoint between the Agent’s intent and your committed history hasn’t gone away - it just moved from before the write to after it. Which means the review beat isn’t optional polish you can skip on a small fix; on this surface it is the gate.
So go read it. The Agent’s closing summary is a claim about what it did; the diff is the evidence - and on code you inherited, holding your own money, the gap between claim and evidence is exactly where you want your eyes. Cursor gives you the diff two ways, and you’ll use both:
- Inline, file by file. Open
src/importers/csv.tsand the changed lines show as red/green right in the gutter. Each file the Agent touched carries Keep All and Undo All controls (the exact label may vary by version), so once you’ve read a file you can lock it in or throw it out without leaving the editor. - A dedicated review pass. For anything bigger than a one-liner, Cursor can walk the changes for you: Agent Review (as of September 2026) runs a dedicated code review over your local changes. Enable it in Settings → Agents → Agent Review (from Cursor 3.11 the setting lives under Git & PRs → Pull Requests), trigger it with the
/agent-reviewcommand in the agent window, or run it from the Source Control tab. It offers two depths: Quick, a fast, low-cost pass suited to small diffs and sanity checks, and Deep, a slower pass for complex logic, security-sensitive code, and large refactors (Agent Review docs). Useful later; overkill for a date fix you can read in thirty seconds.
You’re reading for two things: does the change do what I asked, and did it do anything I didn’t ask. For this fix that’s a quick read, but the point isn’t the time - it’s that you never skip it, because the muscle you’re building on a one-liner is the one that protects you when the diff is forty lines across six files and you’re tempted to skim. Three checks, every time:
- Did it change what you asked - and only that? A date-parsing fix should touch the date path. If the Agent also reformatted the file or renamed a variable, that’s scope creep you Undo now, not in code review.
- Is the fix actually correct? Read the new parsing. Does it try formats in a sensible order and fail loudly when none match, or does it quietly fall back to something that buries the next bad date? And read the new test - a test that passes because it asserts the wrong day is worse than no test at all.
- Did anything drift near the money path? This is the
budgetcli-specific one. Money here is stored as integer cents, and the original author wasn’t consistent about it - so an edit that wandered from the date code into how an amount gets parsed is exactly the thing to catch while it’s still pending. You’ll make that rule explicit in a later chapter; for now, just see it in the diff.
If it’s all right, Keep All on each touched file. If something’s off, the clean move on this surface is to Undo All the bad file and re-ask in the same chat (“keep the new parser but make it throw on an unknown format instead of returning null”) rather than hand-patching on top of the Agent’s mistake - that back-and-forth is the tool working as intended. Read first, decide second.
Two undo levels: checkpoints catch the Agent, git catches everything
Section titled “Two undo levels: checkpoints catch the Agent, git catches everything”Before the commit, know your two safety nets, because they are not the same net and they fail differently.
The first is checkpoints. Cursor snapshots your files automatically before the Agent makes significant changes, and you can hover any earlier message in the chat and hit Restore Checkpoint to roll the working tree back to that point - the escape hatch when a turn goes sideways and Undo-by-file would be tedious. But checkpoints are stored locally, separate from Git, and Cursor’s docs are explicit that they’re only for undoing Agent changes, not version control (Agent overview, as of September 2026; Cursor also snapshots automatically before significant changes, per the same page). Treat them as a session-scoped undo, not a floor.
The second net is the one that doesn’t vanish: git. When the review passes, commit immediately - and you can have the Agent do it:
> commit this with a sensible message
Ran git add tests/csv-import.test.ts git commit -am "Fix CSV importer to handle multiple bank date formats"In this run the test file already existed (the Agent read it first), so the add is belt-and-braces - but make it the habit anyway: commit -am only stages changes to files Git already tracks, so a test file the Agent created would otherwise be left out of the commit. This is the single most valuable habit in the chapter, and on Cursor it’s doubly load-bearing precisely because the Agent edits straight to disk. Everything it did is, until you commit, sitting in your working tree one bad next step - or one stray Restore Checkpoint - away from being lost or tangled. Git is the floor that doesn’t vanish. Checkpoints undo the Agent; commits make a reviewed state permanent in a way nothing in Cursor’s local session can quietly undo. Commit at every green, reviewed checkpoint and you can let the Agent take bigger swings, because the downside is always capped at “go back to the last commit.” On someone else’s codebase that floor is what lets you move fast without fear.
Your first change is described, applied, reviewed in the diff, kept, and committed - the whole loop, closed once by hand on a real bug. The shape never changes for the rest of the course; what changes is how much latitude you give the Agent to run it. You ran that loop once, deliberately, as a ceremony. The next chapter is the next forty times you run it - fast enough that it stops being a ceremony and becomes a reflex, across the Agent sidebar and Tab, the two surfaces you’ll reach for a hundred times a day. Next: the daily edit loop.