This is a list of some rules I follow when building with AI. Some I learned the hard way, some I borrowed from people who did.

Inspired by Andrej Karpathy.

  1. 1
    Always

    You merge it, you own it. #

    If it's in your PR, it's your code. "The AI wrote it" doesn't get you out of a review comment, and it gets you out of an incident call even less. Nobody pages the model.

    This is the rule the other nine hang off. The tooling can generate as much as it wants, but accountability stays with whoever hit merge. Once you really accept that, you start reading diffs differently.

    AIwrites codeYouthe authormainproposesmergeIncidentor reviewasks younever asked

    In practiceI should be able to explain any line in the diff without scrolling back through the chat. If I can't, it doesn't go in.

  2. 2
    Plan

    Write the spec before the prompt. #

    Before I generate anything, I write down what it should do, what it shouldn't touch and how I'll know it works. Vague prompts get you code that looks right and isn't, and you usually find out in production.

    The spec doesn't have to be fancy. Three or four bullets is plenty. The useful part is that it forces me to decide what I actually want before the model decides for me.

    Specintent, limits,when it's donePromptCodeTestsgenerateschecked against

    In practiceA few lines in the ticket or PR description will do, and they double as test cases. "Returns 404 for an unknown id" is a requirement and a test in one sentence.

  3. 3
    Plan

    A person defines the interfaces. #

    Types, schemas and API contracts are written by a person. The AI can implement against them, but it doesn't get to change them. Any PR that touches a contract gets a proper look.

    Models are great at filling in a box and bad at deciding where the boxes go. If one is allowed to reshape an interface, every call site turns into a guess and the boundaries between modules quietly rot.

    Orders serviceAI writes thisCheckout UIAI writes thisimplementscallsContract: you write thisPOST /orders → { id, total }

    In practiceWrite and commit the types first, then let the AI build against them. If it wants to change one, that's a design conversation, not a code suggestion.

  4. 4
    Build

    One feature per PR. #

    Each PR does one thing. If a reviewer can't get through the diff in one sitting, split it.

    Agents make it very easy to end up with 2,000 lines touching six things. That feels productive right up until one of them is wrong and you can't pull it out without dragging the rest along.

    Small PRsauthlistfilterexportbad PR+42+65+38+51revert the PROne big PRauth + list + filter + export+2,400one bug means reverting all four

    In practiceCommit before you run the agent so a bad run is easy to throw away. If a merged PR turns out to be wrong, you revert that one PR without pulling other features out with it.

  5. 5
    Build

    Expect to iterate. #

    The first output is rarely the one you keep. Run it, read it, adjust the prompt and run it again.

    People treat a bad generation like a bug in the code and start fixing it by hand. It's usually a bug in the spec or the prompt. Patch the code and you've fixed one output. Fix the prompt and you've fixed the next ten.

    PromptRunReadRefineShipgenerateoutputwrong?fix the specor promptgood

    In practiceIf the output is wrong, fix the spec or prompt and regenerate. Hand-patching a bad generation hides why it went wrong, and the next run will make the same mistake.

  6. 6
    Verify

    Read every line you ship. #

    Writing code is cheap now. Reading it properly still takes time, and that's where mine should go. If I can't explain a change without asking the AI again, I don't merge it.

    The bottleneck moved. AI opens PRs faster than anyone can read them, so review is the slowest step, and skimming it is how subtle bugs get through. A diff that looks plausible is the most dangerous kind.

    AIgenerateswaiting PRsYoureviewmainfast, cheappiles up hereslowest step

    In practiceDo a task by hand at least once before you hand it off. Otherwise you won't notice when the AI gets it subtly wrong.

  7. 7
    Verify

    No green tests, no merge. #

    AI-written code goes through the same CI, security scans and review as everything else. Looking fine isn't a reason to skip any of them.

    There's a pull to relax the gates because the code "looks clean". It always looks clean. That's the catch with generated code: it's confidently formatted whether it's right or wrong.

    Human codeAI codesame gates for bothTestsScanReviewpassmainfail: back to the author

    In practiceThe AI can write tests too, but check them. A test that can't fail tells you something is covered when it isn't. I like to break the code on purpose and make sure the test notices.

  8. 8
    Verify

    Slow down on auth, security and data. #

    Changes in these areas get a slow, line-by-line review, even when the diff is small. A three-line change to a permission check can matter more than a thousand lines of UI.

    The prompt is also a place data leaves. Whatever I paste goes to a third party, so secrets, credentials and client data stay out of it.

    Everyday codeReviewfast laneAuth, data,securityCareful reviewline by lineslowmainSecrets, client dataPromptnever pasted in

    In practiceBefore using a tool on client work, find out where it sends and keeps what you type. If you can't find out, don't use it.

  9. 9
    Sustain

    Make code easy to delete. #

    Keep modules small and behind clear interfaces. Generated code is cheap to rewrite, so throwing it away should be cheap too.

    This flips an old instinct. We used to protect code because it was expensive to write. Now the expensive part is understanding it, so a module I can delete and regenerate behind a stable contract is worth more than a clever one I'm scared to touch.

    Module AModule BdeleteModule CregenerateNew Bsame contractsame contractA and C never change

    In practiceIf you can't say what a module does in one sentence, split it.

  10. 10
    Sustain

    Treat prompts like code. #

    Prompts, agent instruction files and shared context live in the repo and get reviewed like anything else. A consistent codebase helps too, since agents copy whatever patterns they find.

    If your instructions live in a chat history, nobody can review them and you can't reproduce them. In the repo they get versioned, diffed and rolled back, and people and agents read the same thing.

    PR #142searchsrc/search.ts+48tests/search.test.ts+31prompts/search.md+12AGENTS.md+3prompts reviewed with the codemergeTeammatesAgents

    In practiceUpdate them in the same PR as the code they affect.

A rule nobody checks is just a vibe. I try to tie each one to something concrete: a PR template checkbox, a CI step, or a thing I look for every time I review.