Plan aggressively. Give agents narrow responsibilities. Preserve context between sessions. Isolate their git access. Review the important boundaries.
For a small team, they are an insane force multiplier. Things that would have taken us days can sometimes be done in hours. Boilerplate disappears, tests get written faster, unfamiliar codebases become easier to navigate, and one engineer can move through a lot more work than before.
We use them heavily.
But like anything that gives you this much leverage, they are a double-edged sword.
The faster we started building with them, the more we realized that simply giving an agent a task and letting it loose is probably one of the worst ways to use it on a serious codebase.
We’ve learned quite a bit from using these tools every day, so I wanted to share some of the rules that have worked for us.
1. AI coding tools are guiding tools, and they assume you know that
When you ask an AI coding tool to complete something, it usually treats what you gave it as the source of truth.
If you say:
“Add authentication to this app.”
it will add authentication.
But unless you tell it otherwise, it also has to decide how.
Which library? Which pattern? Where should the logic live? How should errors be handled? What assumptions should it make about future scale?
And it will happily make those decisions for you.
This is where things get dangerous.
The first implementation might work perfectly. Then three milestones later, you introduce another feature and realize that the architecture it chose was never designed for where the product was going.
Now you’re asking the same AI to tame decisions it made when you gave it complete freedom.
That can turn into a very large refactor very quickly.
Start with the plan, not the code
For anything substantial, spending two hours thinking through the architecture can save you several days of screaming at your coding agent later.
Before we start a major milestone, we try to define things like:
- architecture and boundaries
- libraries and frameworks
- existing patterns that should be followed
- data models
- edge cases
- security implications
- dependencies
- how this feature might evolve later
One tool we use a lot for this is the /grillme skill.
The idea is basically: before implementation, attack the plan.
Ask the questions you haven’t thought about. Find contradictions. Identify missing edge cases. Force decisions before those decisions turn into code.
We even have rules around this in Claude Code and Codex.
If a new milestone is large enough to introduce actual business logic, not just a UI change or something trivial, we want a proper planning/grill-me step before implementation starts.
Planning feels slower for the first hour.
It makes everything after that much faster.
2. New sessions are dumb. Very long sessions aren't much better.
One thing we learned surprisingly quickly is that context management matters almost as much as prompting.
A fresh coding session knows almost nothing about what you’ve been doing.
But keeping the same session alive forever isn't the answer either.
Long sessions accumulate assumptions, failed approaches, corrections and outdated context. Eventually the model can start fighting its own history.
So we use a simple rule:
If an AI goes outside alignment twice in the same session, change the session.
Not ten corrections.
Two.
We’ve found this works ridiculously well.
The important part is connecting the dots between sessions.
A new session should not have to rediscover the project from scratch.
Give it the architecture. Give it the milestone. Tell it what was already attempted, what changed, what decisions were made and what absolutely shouldn't change.
We use a /handover workflow for this.
At the end of a meaningful session, generate a handover for the next one.
That alone saves a surprising amount of misalignment.
Think of AI coding sessions almost like engineers handing work between shifts. A new engineer joining halfway through the project needs context. Your AI agent does too.
3. Version control and traceability are non-negotiable
I cannot stress this enough:
Do not casually give an AI agent unrestricted access to the main branch of a serious project.
In fact, create a rule that explicitly prohibits git operations on main.
We've seen AI agents do some pretty creative things to a worktree when trying to “fix” a problem, including some of the most capable models available today.
For larger tasks, we highly recommend worktrees.
Give the agent a task-specific worktree and let it operate there.
If that isn't practical, at minimum:
- create a new local branch
- scope the agent to one milestone
- commit frequently
- review what changed before merging
A bad git reset can ruin your day.
Trust me, been there.
We once came dangerously close to losing quite a bit of work. A separate worktree was the reason it stayed an annoying incident instead of becoming a disaster.
AI agents move fast.
Your ability to reverse what they did needs to move just as fast.
4. Treat AI-generated code as untrusted input
Every piece of AI-generated code should be considered untrusted until a human says otherwise.
I actually think this is useful in two ways.
First, reviewing AI-generated code is one of the fastest ways I’ve found to learn new architecture patterns, libraries and coding standards.
Instead of just reading documentation, you’re looking at those ideas being applied directly inside a codebase you already understand.
Second, it forces you to maintain ownership of the system.
There shouldn't be a module in your product that your AI understands and you don't.
You don't need to remember every line of code. That's not realistic even without AI.
But you should understand:
- why the module exists
- how data moves through it
- its dependencies
- its failure modes
- the important architectural decisions behind it
The moment your answer becomes “I don't know, Claude wrote that part,” you are accumulating a very different type of technical debt.
5. Some boundaries deserve much more attention
We don't review every generated line with the same level of paranoia.
The boundaries matter.
There are a few areas where we pay considerably more attention:
Architecture alignment
Does this implementation follow the architecture we agreed on, or did the agent quietly invent another pattern?
Error handling
What happens when dependencies fail, requests timeout, data is malformed or some assumption isn't true?
Input validation
Models are very good at implementing the happy path. Production users are very good at finding every other path.
Dependency choices
Did the agent introduce another package because it was convenient? Do we actually need it? Is it maintained? Are we already solving the same problem elsewhere?
And anything touching:
- authentication
- authorization
- cryptography
- payments
- secrets
- personally identifiable information
- sensitive customer data
gets mandatory human review, and where appropriate, senior review.
Some code is cheap to regenerate.
A security incident isn't.
6. Know where AI gives you leverage and where you still need to drive
There are areas where AI coding tools are almost absurdly useful.
We use them heavily for:
- boilerplate and scaffolding
- unit and integration test generation
- test case generation
- documentation
- code comments
- repetitive migrations
- refactoring well-understood patterns
- navigating unfamiliar parts of a codebase
- debugging with enough context
- implementing clearly defined functionality
These are places where the destination is mostly known and AI can dramatically shorten the road there.
Then there are areas where we still want an engineer firmly in control:
- authentication and authorization design
- architecture decisions
- system design
- infrastructure
- deployment configuration
- database architecture
- security boundaries
- decisions that are difficult to reverse later
AI can absolutely participate in those conversations.
We use it there too.
But participating in the decision and owning the decision are two different things.
That distinction matters.
The goal isn't to write less code
I don't think the interesting part of AI coding tools is that engineers can now avoid typing code.
Typing was never the hard part.
The useful part is that engineers can spend more of their time thinking about what should be built, how it should fit together and whether it actually works, while delegating more of the repetitive implementation.
But that only works if you stay in control.
Giving an AI agent more autonomy without giving it boundaries doesn't automatically make you faster. Sometimes it just lets you create technical debt at machine speed.
Our approach today is fairly simple:
Plan aggressively. Give agents narrow responsibilities. Preserve context between sessions. Isolate their git access. Review the important boundaries. And never let the AI understand your own system better than you do.
We are still learning this ourselves.
The tools are changing almost every week, and I’m sure some of these rules will change with them.
But right now, these are the practices that let us get the speed without giving up ownership of what we're building.