AI Dev

Lesson 1

The collaboration contract

What you stay responsible for, and the loop that keeps an agent from running away with your codebase

An agent will write more code in ten minutes than you can carefully read in an hour. That single fact drives every practice in this course.

Everything here follows from one rule.

The one rule

Treat AI output as a first draft you guide and verify.

Cursor is a collaborator under your control, not an autopilot.

Tool choice, prompting, context, rules, review — all of it is machinery for making that rule survive contact with a real codebase.


Why the rule exists

The rule is not caution for its own sake. It follows from an asymmetry in the economics of the tool.

Generation

Near-free and near-instant. Cost barely rises with the size of the change. Producing 800 lines is not meaningfully harder for the model than producing 80.

Verification

Paid entirely by you, in attention, and it scales with the size of the change — worse than linearly once a diff spans several files.

Two consequences follow, and they explain most of what looks like fussiness later in this course.

Diff size is the variable you actually control. You cannot make the model more careful by asking. You can make the diff small enough that careless output is obvious. This is why "small steps" appears in nearly every practice here — it is the only lever that reliably moves verification cost.

Nobody is accountable but you. The model has no stake in the outcome, cannot be on call, and will not be in the incident review. Merging a change transfers responsibility for it to you, permanently and completely, regardless of who typed it.


The litmus test

A change is finished when you can do three things without the tool open.

1 · Explain it

Say what the code does, in your own words, to a colleague who has not seen it.

2 · Reason about its edges

Name what breaks it: nulls, empty collections, concurrency, scale, hostile input.

3 · Extend it

Add the next requirement yourself, without going back to the agent.

Fail any one and the change is not done — no matter how green the checks are.

Why green checks are not enough

Consider a discount calculator an agent produced. It compiles, it is typed, and its tests pass:

TypeScript
export function applyDiscount(price: number, percent: number): number {
  return Math.round(price * (1 - percent / 100) * 100) / 100;
}
TypeScript
test('applies 20% off', () => {
  expect(applyDiscount(100, 20)).toBe(80);
});

Green. Now run the litmus test.

TestResult
Explain itFine — subtract a percentage, round to two decimals.
Reason about its edgesFails. What does percent = 120 do? It returns a negative price. What about NaN, or a float like 0.1 + 0.2 in money? None of this is handled or rejected.
Extend itFails. Add stacked discounts or currency and you discover the function has no opinion about rounding order — a real source of money bugs.

The test suite proved the code does something. It did not prove the code is right, and it certainly did not prove you could maintain it at 2am when a customer is charged a negative amount.


The loop

Agents drift when handed a large task and left alone. The fix is structural: work in small steps and put a verification gate after each one.

Understandthe taskPlan theapproachSmall step(scoped context)Diff ontrack?Tests / build/ lint pass?Reviewed —more to do?Commitsmall, reviewedYesYesDoneNo — revert & refineNo — fix and retryMore work left

Two properties matter more than the exact boxes:

  • Every path back leads to a smaller step, not a bigger prompt. When a diff goes wrong, revert and narrow the scope. Writing a longer instruction and retrying is the reflex to resist.
  • The gates are machine-checkable. "Tests / build / lint pass" is something the agent can run and loop on unaided. "Looks fine" gives it nothing to iterate against.

Stage by stage

1

Understand the task

Before any prompt: can you state what “done” looks like in one sentence? If not, you are not ready to delegate — you are ready to investigate. Use Ask mode, which changes nothing on disk.

2

Plan the approach

For anything big or ambiguous, get a plan before code exists. A wrong plan costs one message to fix; a wrong implementation costs a revert and a re-read. This is the cheapest correction point in the whole loop.

3

Small step, scoped context

One coherent change. Not “build the feature” but “add the validation schema and wire it into this one route”. Scoped context means the specific files it needs, not the whole repository — the subject of Lesson 2.

4

The three gates

Diff on track is your judgement — is it solving the problem you posed, in the shape you expected? Tests / build / lint is the machine’s. More to do asks whether this was one step of several. Only the middle gate can run without you.

5

Commit — small and reviewed

A commit is a claim that you understand and stand behind the change. Small atomic commits with meaningful messages are what make an AI-heavy branch reviewable at all.


Right tool for the job

Cursor is not one feature. Reaching for Agent every time is the most common way to spend tokens and attention on work that Tab would have finished in a keystroke.

ModeReach for it whenWrites to disk?You stay in control by
Tab / autocompleteThe next few lines follow obviously from contextOnly what you acceptReading before you accept
AskYou want to understand code, not change itNoNothing can go wrong — it is read-only
PlanThe task is big, ambiguous, or crosses modulesNoApproving the plan before any code exists
AgentThe change is scoped and you can state “done”YesSmall steps, checkpoints, Stop early
Background agentsWork is parallelisable and you are busy elsewhereYes, on its own branchReviewing the branch like any external PR
Bugbot / AI reviewA diff is ready and you want a second passNo — it commentsVerifying its findings; it hallucinates too

The rule of thumb: the more autonomy you hand over, the more specific the definition of “done” has to be before you start. Tab needs none. An agent turned loose on “improve the auth module” needs one badly, and will invent its own if you do not supply it.

Picking a mode, worked

The task in front of youModeWhy
Finishing a switch statement you are mid-way throughTabIntent is already on screen
“Why does this cache invalidate on write?”AskYou want an answer, not an edit
Migrating auth from sessions to JWTsPlan firstCrosses modules; the design decisions are yours
Adding one validated field to an existing endpointAgentScoped, and “done” is one sentence
Bumping a dependency across 40 call sitesBackground agentMechanical, verifiable, and slow to do by hand
A colleague’s PR that touches paymentsBugbot and a humanSecond pass is useful; it does not replace review

What you never delegate

Some decisions do not become cheaper when an agent is available, because their cost was never in the typing.

Architecture

High-level and component-level design. The agent can draft inside your boundaries; it should not draw them.

Product trade-offs

What to build, what to cut, what to defer. The model has no access to your users or your roadmap.

Security decisions

Threat model, authz boundaries, what counts as sensitive. Lesson 4 covers why agents relax these by default.

Correctness boundaries

What “right” means for this system, and which invariants must never break.

Engineering standards

The conventions the codebase holds to. You set them once — Lesson 3 shows how to make the agent inherit them.

Everything else

Is fair game to delegate — under the loop above, with a diff you read.

A useful split when starting a system: draw the high-level and component diagrams yourself, plan with the agent, break the plan into sub-problems, then let the agent execute sub-problems one at a time. The plan lives in a file the agent can read; your own view of status and priorities can live wherever suits you.


Where AI assistance degrades

Model quality is not uniform across tasks. Three areas stay stubbornly hard, and knowing them tells you when to stop delegating and start thinking.

Complex runtime-state debugging

The bug lives in state the model cannot see — a race, a stale cache, a connection pool under load. It will confidently propose fixes for the code in front of it, which is not where the problem is. Reproduce and instrument first; bring the agent the evidence, not the mystery.

Architecture and system design

These are trade-off decisions against constraints the model does not hold: your team’s size, your latency budget, what you are willing to operate at 3am. It will produce something plausible and generic, which is the worst kind of architecture.

Legacy brownfield code

Undocumented behaviour that some caller depends on looks exactly like a bug worth cleaning up. Agents optimise for clean code and will happily “fix” a load-bearing quirk. Here, small steps and real tests are not optional.


Anti-patterns

Each of these is a real habit with a real replacement.

Anti-patternDo insteadWhy it is tempting
“Vibe coding” — accepting output you cannot explainGuide and verify; own the mergeIt works, and reading is slower than accepting
Blindly accepting a large diffRead it; keep changes small; split the PRThe diff already exists; splitting feels like waste
Letting the agent run away on a huge taskPlan first, small steps, hit Stop earlyWatching it work feels like progress
Prompt-and-pray on a vague requestStructured prompt with acceptance criteriaSometimes it guesses right, which reinforces it
Context dumping — everything, every chatSpecific @files; fresh chats; let it searchMore context feels safer than less
No verification pathTests, build or lint the agent can loop onWriting the test feels like extra work
One giant rules fileSmall, scoped .cursor/rules/*.mdcOne file is easier to write than five
Auto-installing AI-suggested packagesVerify every dependency against the real registryThe import looks plausible and the name sounds real
Skipping human review on security codeNever skip it for auth, payments or dataThe automated checks were green
Trusting self-reported speedupsMeasure throughput, stability and reworkIt genuinely feels faster, and often is, in part

Measuring whether it is actually working

The last anti-pattern deserves its own section, because it is the one that misleads whole teams rather than individuals.

AI tooling reliably increases the number of pull requests. That is a real effect and it is easy to measure, which is exactly why it gets reported on its own. Throughput in isolation cannot distinguish between these two situations:

A real speedup

PRs up. Change-failure rate flat. Rework flat. Time-to-restore flat. You are shipping more of the same quality.

A loan

PRs up. Change-failure rate up. Reverts and follow-up fixes up. You are shipping work that will come back, on someone else’s calendar.

Track at least one stability signal and one rework signal alongside volume. Throughput plus stability plus rework is the smallest honest set.


Recap

Lesson 2 takes the step you will run most often — the prompt — and shows how to structure it and what context to feed it.

Check your understanding

1 / 10
the litmus test: explain, reason about edge cases, extend without the tool

The litmus test says a change is done only when you can do three things without the tool. Which is NOT one of them?

Test your understanding

Prof is ready

Prof will ask you questions about Working with an AI coding agent: the collaboration contract — not explain it. You'll be surprised what you don't know until you have to say it.

Finished this lesson?

Read through the lesson first (0/20s).