How I Use AI Agents to Actually Ship Faster
Not vibes, not autocomplete. A delegation system: what I hand off, what I never hand off, and the guardrails that keep it honest.
For most of a year my honest answer to "do you use AI to code?" was sort of. I had autocomplete switched on, I pasted stack traces into a chat window, and I told myself that counted. It didn't. What finally moved the needle wasn't a smarter model. It was a change in posture: I stopped treating agents as a faster keyboard and started treating them as something I delegate to, with the same care I'd give a capable new teammate on their first week.
That means a real brief, a bounded surface area, and a review I actually do. Everything below is what shook out after a few months of getting this wrong in public.
01Autocomplete guesses, an agent commits
The distinction matters more than the branding does. Completion predicts the next few tokens in the file you're already staring at. An agent holds a goal, reads across the repo, runs commands, and hands back work it believes is finished.
Their failure modes are not the same size. A bad completion costs four seconds and a keystroke. A bad agent run costs an afternoon, and it costs it quietly, because the output compiles. So the skill worth building isn't prompting. It's scoping.
02The three lanes I run
I don't have one agent. I have three jobs I hand out, and I keep them separate because they need different permissions and different levels of trust.
The scout: read-only, always. "Where does session refresh actually happen?"
"Trace what runs between the webhook landing and the row being written." It
cites file:line and changes nothing. This is the highest-return lane by a
distance, and the one people skip.
The builder: bounded and well-specified. The tenth endpoint that resembles the previous nine. A migration. Test coverage for a module I already understand. Work where the shape is known and the typing is the only thing left.
The reviewer: adversarial by instruction. My diff, before anyone else sees it. Asking "does this look good?" gets me a compliment. Asking "argue this breaks in production" gets me the bug.
03The loop I actually follow
- Frame it myself. Five minutes writing the brief in my own words. If I can't state the outcome in one sentence, the task isn't ready to delegate, and that's information about me, not the model.
- Bound the blast radius. Which files it may touch, which commands it may run, what is off limits. Auth, billing and migrations are named explicitly every single time.
- Let it finish. Interrupting halfway through a plan produces a worse result than restarting with a better brief. I learned this the expensive way.
- Review like a stranger wrote it. Because one did. I read the diff top to bottom before I run it. If I find myself scrolling past a hunk because it "looks standard," that's the hunk to slow down on.
- Fold the correction back. Any note I give twice stops being a note and becomes a line in the repo's context file. The loop only compounds if the lessons outlive the session.
The agent isn't slow because it types slowly. It's slow when I skip the five minutes of thinking that would have made the brief unambiguous.
04Guardrails, written down once
Most of what I used to repeat every session now lives in a file at the root of the repo. It is the single highest-leverage thing I've done here. It turns preferences into defaults, and it makes the same rules apply whether the work is mine or an agent's.
Note the definition of done. "It builds" is not a bar. Plausible code always builds. The test that fails when you revert the change is the bar, because it's the only cheap proof the work did anything at all.
05What I never hand over
- Schema decisions. An agent optimises for the query in front of it. Schemas are a bet on the queries you haven't written yet.
- Naming in the public surface. Route names, event names, anything a consumer will depend on. Those are promises, and I want to be the one making them.
- Auth and money. An agent can draft here, but I read every line, and I write the tests myself.
- The first draft of a hard idea. Thinking is easy to outsource by accident. I want the shape of the problem in my own head first, or I've just become a reviewer of decisions I don't understand.
06Where it still falls apart
- Wide refactors. The moment the change spans more context than can be held at once, quality drops off a cliff. I split it or I do it myself.
- Anything needing taste. Interfaces come back functional and slightly rented-looking. Correct spacing, no point of view.
- Debugging that needs a theory about the real world. Clock skew, a flaky network path, a queue silently dropping jobs under load. The evidence isn't in the repository.
- Long sessions. Quality decays as context fills. A fresh session with a sharper brief beats nursing a tired one, every time.
07What actually changed
Rough and self-reported. I'm counting reclaimed attention, not lines of code:
- ~40% of a typical week that used to go to the boring middle of a task
- 3× more tests written, purely because writing them got cheap
- 0 dependencies added to a project without me knowing about it
None of this is about typing less. Typing was never the bottleneck. What shrank is the boring middle of a task: the wiring, the scaffold, the fourth near-identical handler, the test I know I should write and keep not writing. That work still has to happen. It just stopped costing me my best hours.
The leverage is in where that budget goes instead: the decisions that don't reverse cleanly. Schemas, boundaries, what we refuse to build. An agent is very good at the parts of the job I'd already solved in my head. It is not a substitute for having solved them.
The prompts I actually reuse are on the prompt shelf. They're less clever than you'd expect, which is rather the point.