AI code generators write more code than ever, and they do it fast. Sahil Lavingia said it well in a recent tweet. If developers now produce five to ten times more code with AI, we need something that can review five to ten times more code too.
That is the real problem. Tools like Cursor generate code that looks right but often contains small mistakes that only show up when the project runs. Wrong Prisma fields, missing checks, loose validation, repeated logic, or scripts that fail silently. None of this feels dramatic. It is just enough to slow you down or break production.
I hit all of this while building an Express TypeScript API. Cursor helped me create the project fast, then I spent real time fixing the parts it got wrong. That is when the pattern became clear. AI code generation is not the bottleneck anymore. Code review is.
The only way to keep up is to bring AI into the review step, not just the generation step.
The rest of this post walks through how that played out in my project, what went wrong, and how AI code review solved the gap Cursor left. I will talk about the tool I used later in the post.
The project I used to test this
I used an Express TypeScript API that handled auth, user management, Prisma, JWT, validation middleware, and a few automation scripts. It had routes, controllers, types, a Prisma schema, and a small shell toolchain for creating pull requests through the GitHub API.
Everything tied together.
- The DTOs shaped the request data.
- The controllers expected those shapes.
- The Prisma model enforced its own contract.
- The middleware ran checks before the handlers.
- The scripts needed correct error handling and clean parsing.
That structure made it clear when something went wrong. If Cursor guessed a field name, the query failed. If it added logic in the wrong layer, the flow broke. If it skipped error checks in the scripts, automation stopped working.
This project gave me a clear view into where AI generated code drifts from the actual codebase.
Where Cursor started breaking things
When I asked Cursor to generate code for this project, the gaps showed up fast.
It used wrong field names in Prisma queries
Cursor produced queries with fields that did not exist in the Prisma schema. The handlers failed as soon as they hit the database.
It placed validation in the wrong layer
I already had middleware for input checks. Cursor added the same checks inside controllers, which created duplication and forced updates in two places.
It drifted from the actual DTOs
Some controllers expected request shapes that did not match the DTO definitions. TypeScript let a few of these slip through because the structures looked close enough.
It skipped error handling in bash scripts
The pull request scripts used curl and git commands with no exit code checks. If an API call failed, the script continued as if nothing happened.
It parsed JSON in fragile ways
Cursor relied on grep and cut to extract fields from GitHub responses. That approach broke as soon as the response shape changed.
It exposed the GitHub token
One script printed the token to the terminal. That leaked it to shell history and anyone watching the screen.
...and many more.
All of this came from a simple pattern. Cursor generated each file on its own, while the project depended on consistent behavior across routes, controllers, models, middleware, and scripts. Once the pieces drifted, problems stacked up.
How AI code review filled the gap
Cursor generated large chunks of this project fast, but it introduced inconsistencies across files. To keep the codebase stable, I needed something that reviewed the entire diff, not just the file I was currently editing.
I used Bito for this. The review on PR #1 in the repo showed exactly why this layer is required. Here are the concrete issues Bito surfaced in that pull request.
1. Incorrect assumptions about project flow
Bito traced the request path across files and produced an interaction diagram. It showed the exact flow:
Client → Express App → Route Handler → ValidationMiddleware → AuthController → Database → Response.
Cursor did not maintain this order. Bito caught cases where Cursor placed logic in the wrong layer or duplicated it.
2. Duplicate validation across middleware and controllers
In authRoutes.ts, Cursor generated:
router.post('/register', register);
router.post('/register', validateRegister, register);
Same for login.
Bito flagged these as duplicate routes and pointed out that the controller still performed its own validation.
It specifically referenced the sections in validation.middleware.ts (lines 10–50) and authController.ts (lines 11–26).
This was not a style preference. It broke the request flow and doubled maintenance work.
3. Prisma field and type drift
Cursor produced controller logic that assumed certain fields existed. In the PR review, Bito cross-checked controller usage with schema.prisma and flagged mismatches in user lookup and update logic.
Cursor did not verify the fields across files. Bito did.
4. Missing branch checks and error handling in bash scripts
The automation scripts were the worst offenders.
For example, in push-and-create-prs.sh:
git push -u origin main
Cursor wrote this with zero checks.
Bito flagged:
- no error handling
- no branch existence check
- no exit status fallback
It suggested explicit guards, such as verifying refs/heads/branch-a before checkout and returning a non-zero exit code if the push fails.
This tightened the entire CI path.
5. Unreliable JSON parsing
Cursor parsed GitHub API responses with grep and cut, for example:
echo "$RESPONSE_A" | grep -o '"html_url":"[^"]*' | cut -d'"' -f4
This breaks on any format change.
Bito called this out directly in the PR and recommended using structured parsing (jq) or capturing HTTP status codes first.
6. Token exposure in interactive scripts
In create-prs-now.sh, Cursor prompted for token input like this:
read -p "Enter your GitHub token: " GITHUB_TOKEN
This prints the token in plain text and stores it in shell history.
Bito flagged this as a security issue and suggested:
using read -s to hide input
validating token prefix
avoiding echo statements that leak secrets
7. Missing exit codes for automation reliability
Cursor ended the script with:
echo "Done!"
No exit status.
CI cannot detect failures without exit codes.
Bito explained why exit codes matter and gave an explicit fix:
if [ ! -z "$PR_URL_A" ] && [ ! -z "$PR_URL_B" ] && [ ! -z "$PR_URL_C" ]; then
exit 0
else
exit 1
fi
This alone prevents silent deployment failures.
8. Repeated code that violated DRY
In create-prs-automated.sh, Cursor duplicated the entire PR creation block three times.
Bito highlighted the repetition and suggested extracting a reusable function.
Cursor rarely attempts global refactors on its own.
Bito is designed to detect them because it reviews the diff holistically.
9. Cross-file consistency issues
This was the biggest win.
Bito reviewed:
- authRoutes.ts
- validation.middleware.ts
- authController.ts
- userRoutes.ts
- userController.ts
- all four bash scripts
Cursor did not track how these pieces interacted.
Bito cross-referenced them.
This prevented logic drift across layers.
All of this came from one insight. Cursor can write code fast. It cannot guarantee consistency across the entire project. AI code review filled that gap in a measurable, concrete way, and the PR made that clear.
The workflow that produced code I could ship
Once I saw how Cursor and Bito behaved on the same project, I locked in a workflow that kept speed and removed breakage. The sequence is simple, but every step matters.
1. Generate code with the Cursor in small steps
I stopped asking Cursor to create large chunks at once. I asked for one file or one change at a time. This reduced cross-file drift and made each review cycle easier to reason about.
2. Run Bito inside the IDE immediately after each change
Bito reviewed the updated file in the context of the full codebase.
If a controller referenced the wrong field, Bito pointed back to the Prisma model.
If the change introduced duplicated validation or unnecessary checks, Bito flagged both spots.
If a script skipped exit code checks, the review highlighted the exact line.
3. Fix the issues while the context is fresh
I applied the suggestions right away.
If the issue required refactoring, I asked Cursor for a targeted fix. For example, if Bito flagged repeated PR creation blocks, I asked Cursor to extract a function and replaced the duplicates.
4. Open a pull request and run Bito again on the full diff
This is where most AI generated code breaks. Single-file checks miss cross-file inconsistencies.
In the PR review for this project, Bito identified duplicate register and login routes, repeated validation in controllers, missing error handling across scripts, fragile JSON parsing, and token exposure.
The second review pass ensured nothing slipped into the main.
5. Merge only when the review produced zero high-risk issues
Once Bito showed a clean review, I merged the PR.
This kept the repo stable while still letting Cursor generate large amounts of code.
This loop removed the guesswork. Cursor handled generation. Bito handled cross-file review. Together, they gave me a development flow where the output moved fast and stayed consistent.
Conclusion
AI helps you write more code, but it also adds more chances to slip. I saw that every time Cursor moved faster than the rest of the project could keep up. Once I added AI code review, the whole workflow settled. The code lined up across files, the scripts stopped failing in silence, and I spent less time chasing small errors.
If you use AI to generate code, pair it with an AI reviewer. Do not rely on one without the other. I use Bito for this, and it has saved me a lot of cleanup time. Try any AI code review tool you trust, but use one. It makes the entire process far more stable.
Top comments (0)