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.
- 1Always
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.
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.
- 2Plan
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.
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.
- 3Plan
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.
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.
- 4Build
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.
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.
- 5Build
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.
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.
- 6Verify
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.
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.
- 7Verify
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.
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.
- 8Verify
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.
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.
- 9Sustain
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.
In practiceIf you can't say what a module does in one sentence, split it.
- 10Sustain
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.
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.