3,025 pull requests in ten months: an AI-assisted delivery process, from the inside
A training platform for education providers started in an AI app builder and is now a multi-tenant SaaS with a web app, native iOS and Android apps, 160 serverless functions and 1,048 automated test files. Over ten months, 3,025 pull requests were merged into it, most of them written by coding agents and every one of them reviewed, tested and released through the same seven stages. A second platform, for a hospitality business, went through 2,133 in six months the same way. This is what that process looks like day to day, where the two hard gates sit, and what I would set up first if I started again tomorrow.
11 min read
1. The setup: one lead engineer, several agents, one process
I was architect and lead engineer end to end. The coding was done largely by agents, Claude Code and Codex, working on tickets in parallel, each in its own branch. That only works if the agents can't do damage on their own, so the process came before the speed: React on Vercel, Supabase Postgres with row-level security on every table, edge functions and scheduled jobs, native apps whose design tokens are generated from the web CSS, and a release pipeline that treats every change the same way, whoever wrote it.
3,025 merged pull requests in ten months is about 300 a month. The number itself is not the point; what matters is that each of them was small enough to review, reversible, and went through staging before production. The guide I wrote about this process describes the seven stages in compact form. Here is how they play out in practice.
2. Guardrails before the first prompt
Every repository has a short instruction file the agents read at the start of each session: the architecture in a few lines, the conventions, how to run the tests, and a list of what an agent may and may not do. The hard rules are few and absolute. Authentication, payments, data deletion and secrets always need a human approval. Agents never touch production data or real customer accounts; they get test accounts in staging and nothing else.
The instruction file is not documentation for its own sake. It is the cheapest way to stop the same mistake twice. Without it, every session starts from zero and an agent will happily repeat a migration pattern that broke staging last week. With it, the lesson is written down once and every future session starts with it.
# AGENTS.md (excerpt)
## Never without a human approval
- auth, payments, data deletion, secrets, production config
## Never
- push to main, touch production data or real customer accounts
## Always
- one ticket = one PR; migrations idempotent, dry-run before merge
- run unit tests + type check before asking for review
## Lessons (append, never delete)
- <date>: <what went wrong> -> <the rule that prevents it>3. Small, reversible changes, staging first
One ticket, one pull request, with branch protection on main so nobody, human or agent, pushes directly. A pull request that changes a thousand lines across ten features can't be reviewed properly, however good the reviewer, so agents are asked for the smallest change that closes the ticket. Database migrations are idempotent and run as a dry run against the target database before anything merges.
Every change reaches a staging environment with the same build and configuration as production before it goes anywhere near customers. When the release goes out, only the functions that actually changed are deployed, which keeps each release small and each rollback obvious. This is the unglamorous part, and it is where most of the speed comes from: when every step is small and reversible, nobody has to be afraid of merging.
4. Verify like a user, not like a compiler
Green types and green unit tests are necessary and not enough. The platform has 1,048 automated test files, and type-check and lint run against baselines that may only improve, so the agents can't quietly make things worse. The first hard gate sits here: nothing merges unless the tests are green.
On top of that, a flow is checked the way a user would experience it. I built an AI browser tester for this: you describe the flow in plain language, for example 'a trainer creates a session, a learner signs in with the QR code, the trainer sees the signature without reloading', and an agent drives a real Chrome through it and returns a pass or fail with console errors, failed requests and a fix prompt. Setting up such a test takes nine steps instead of around two hundred, and multi-role flows like the one above are exactly where conventional tests are thin.
5. Impact check, then a person says yes
Before a release goes to production, a short table answers four questions: what changes, who is affected, what is the risk and what is the way back. Agents draft it from the pull requests; I read it. This is the second hard gate: a person approves every production merge. It takes minutes, because the changes are small and the table is short, and it catches the cases where a technically correct change is the wrong thing to do on a Friday afternoon or during a customer's audit week.
The point is not distrust of the agents. The point is that release decisions involve context the code doesn't contain: a customer about to onboard, a support backlog, a planned migration. That context lives with people, so the decision does too.
## Release <date> — impact check (template, example rows)
| change | who is affected | risk | way back |
|--------------------------------|------------------------|--------|--------------------------|
| attendance flow change | trainers, learners | low | revert PR, redeploy fn |
| new invoice field | admins of all tenants | medium | migration is additive |
| CRM scoring update | sales users | low | feature flag off |
Approved by: ____ (no production merge without a name here)6. Ship, watch, and let failures open tickets
After every deploy, smoke tests run against the vital routes of the live system, such as sign-in and checkout. If one breaks, the deploy turns red and the change is rolled back. Monitoring watches outcomes rather than CPU: did attendance get recorded, did the invoice go out. Each failure opens one issue automatically, and the issue closes itself when the check recovers, so the backlog shows real problems and not alert noise.
Underneath sits the safety net nobody sees: encrypted backups seven times a day, files mirrored to a second provider, and a nightly restore into a separate twin project that proves the backups work. With agents writing code at this pace, being able to undo anything, including data, is what makes the pace acceptable.
7. Close the loop, and measure the right things
Every incident, every review comment that repeats, every migration that failed on staging ends with one question: which line in the instruction file would have prevented this? That line gets added. Customer replies are drafted by an agent and sent by a person. Over months this is what turns a fast team into a safe one: the rules grow with the product.
Measure lead time from ticket to production, change failure rate, merged pull requests per week and bugs found by users, the same kind of delivery metrics the DORA research uses. Don't measure lines of code; agents produce those for free. If you want to start, start with the guardrails and staging, not with more agents. The readiness check below shows where a codebase stands before you add speed.
Interactive
Is your AI-built app ready for production?
Tick what is already true. The gaps that are left are your to-do list, in order.
Your next three steps
- Code lives in Git; changes go through pull requests
- No secret keys in the frontend; server keys only on the server
- Row-level security (or equivalent) on every table
Takeaway
Agents can write most of the code. The process decides whether that's a risk or an advantage: small reversible changes, two hard gates owned by people, and every lesson written back into the rules.
Real projects behind this
Try it yourself
Sources and official guides
More articles
- The EU AI Act for mid-sized companies: what applies to you, and when
- FinOps for AI spend: tokens, caching, routing and budgets that hold
- Making a restaurant network visible in AI answers: a GEO project, step by step
- How this site is built: static where it can be, streaming where it must
- Kubernetes cost on EKS and GKE: the same playbook, different levers
- A landing zone for mid-sized companies, in Terraform or Bicep: the parts that matter
- The legacy migration playbook: waves, parallel runs, and identical row counts and checksums
- MCP security in depth: how to let AI assistants into your product without opening the doors
- Monitoring on business outcomes: green dashboards, empty checkout
- Phone AI agents: the architecture, and the pitfalls nobody shows in the demo
- Restore tests: a backup you have never restored is only a hope
- Streaming AI answers on Azure Static Web Apps: the one header that buffered everything
- Building an AI assistant for WhatsApp, end to end: what it takes beyond the demo
- Air-gapped systems: running critical software with no internet
- Production AI on AWS: Amazon Bedrock and AgentCore in a private setup
- Production AI on Microsoft Foundry: a private reference setup for agents
- /goal, /loop or routines: stop babysitting your coding agent
- Claude's new plans: Max, Ultra and what they mean for teams
- OpenAI Codex at the end of 2026: goal mode, dots and how to lock it down
- GitHub Copilot, Claude Code or Codex? How I'd choose for a company
- GEO basics: how to show up in AI answers
- Production AI on Google Cloud: from Vertex AI to Gemini Enterprise Agent Platform
- Local LLMs in an air-gapped network: AI for your most sensitive data
- I want to run a local LLM: which server should I buy?
- MiniMax M3: an open frontier model you can run yourself?
- Prompt research at scale with an open model
- SEO and GEO together: a practical audit in 6 steps
- Right-size Kubernetes: the playbook that took a cluster from 7 to 4 nodes
- Private AI for sensitive data: a local LLM setup that passes the security review
- From AI prototype to production: the eight layers I add, in order
