Manual code review is slow and inconsistent. Not because engineers are careless, because humans are terrible at scanning for the same class of bug across hundreds of lines for the twentieth time this month. We get bored. We miss things. And we definitely miss things at 11pm before a deadline.
AI code review doesn't get bored. I've been running CodeRabbit on TypeScript projects for eight months. It catches stuff my team misses every single week: type assertions that looked fine in isolation but broke an assumption downstream, console.log statements left in API handlers, a missing await in a function that looks synchronous but isn't.
This tutorial gets you from zero to a full AI review pipeline in one afternoon.
TL;DR:
- CodeRabbit installs in 5 minutes and reviews every PR automatically
- GitHub Actions runs tsc, ESLint, and tests on every push, blocks merges on failure
- Together they create a quality gate that catches type errors, logic bugs, and style issues
- Free tier covers most small teams; paid plan is $15/user/month
What You're Building
By the end of this tutorial, every pull request to your repo will automatically:
- Run
tsc --noEmitto catch type errors - Run
eslintwith your typescript-eslint config - Run your test suite
- Get an AI review from CodeRabbit with inline comments
None of these require approval to post. They run in parallel. A PR that fails any check is blocked from merging until the author fixes it.
Part 1: GitHub Actions Quality Gates
The setup below is what I run on my own monorepo in production. We rolled it out in February after AI-generated PRs from interns and contractors started landing without anyone reading them closely. Two-tier quality gates, automated checks first, then AI review for nuance, caught 14 real bugs in the first three weeks that human reviewers had missed.
The Base Workflow
Create .github/workflows/ci.yml:
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Type check
run: npx tsc --noEmit
- name: Lint
run: npx eslint . --ext .ts,.tsx --max-warnings 0
- name: Test
run: npx vitest run --reporter=verbose
--max-warnings 0 is the key setting for ESLint. Without it, warnings accumulate silently and your lint check always passes. Treat warnings as errors in CI, if a rule isn't worth failing the build, remove the rule.
Why tsc --noEmit in CI?
Your editor shows type errors inline. Developers sometimes ignore them when they're in the middle of a flow. tsc --noEmit in CI makes ignoring them impossible, the PR can't merge until the type errors are gone.
This catches a specific failure mode I see constantly: a developer adds an as any to silence an editor error, the code ships, and the type information that other code depends on is silently wrong. TypeScript in CI doesn't forgive as any, it flags the underlying type mismatch.
For that to work properly, your tsconfig.json needs to be strict. If it isn't, read the TypeScript strict mode guide first, the CI check is only as good as your compiler configuration.
Caching Dependencies
npm ci on every run is slow. Add caching:
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
The cache: 'npm' line tells the action to restore node_modules from cache if package-lock.json hasn't changed. On a project with 200 dependencies, this drops install time from 45 seconds to about 4 seconds.
Branch Protection Rules
The workflow file makes the checks run. Branch protection rules make them mandatory. In your GitHub repo:
- Settings -> Branches -> Add rule
- Branch name pattern:
main - Enable: "Require status checks to pass before merging"
- Select the
qualityjob from your workflow - Enable: "Require branches to be up to date before merging"
Now a PR that fails the type check, lint, or tests literally cannot be merged by anyone, including repo admins.
Part 2: CodeRabbit Setup
Installation
Go to coderabbit.ai and sign in with GitHub. Install the GitHub App on your account or organization. Select the repos you want it to review.
That's it for basic setup. CodeRabbit will automatically comment on your next PR.
TypeScript-Specific Configuration
Create .coderabbit.yaml in your repo root:
language: en-US
reviews:
profile: assertive
request_changes_workflow: true
path_instructions:
- path: "**/*.ts"
instructions: |
- Flag any use of 'any' type that isn't explicitly justified
- Check that async functions are awaited at all call sites
- Verify that union types in switch statements have exhaustive cases
- Flag type assertions (as SomeType) unless there's a comment explaining why
- path: "**/*.test.ts"
instructions: |
- Check that test descriptions match what the test actually verifies
- Flag tests that don't have at least one assertion
- Flag tests that mock the same thing that a sibling test tests directly
chat:
auto_reply: true
The path_instructions section is where you teach CodeRabbit your project's conventions. The TypeScript-specific checks above cover the most common issues I see in AI-generated code: untyped any, missing await, non-exhaustive switches, and unexplained type assertions.
profile: assertive tells CodeRabbit to flag issues rather than just suggest them. On a team where reviews sometimes go stale, this matters.
What CodeRabbit Actually Reviews
On a TypeScript React project, a typical CodeRabbit review might flag:
// CodeRabbit: 'data' is typed as 'any' here. The fetch response has a
// known shape based on the API definition in types/api.ts, consider
// typing this explicitly to prevent silent type mismatches downstream.
const data: any = await response.json();
Or:
// CodeRabbit: This switch handles 'pending' | 'active' but the Status
// type also includes 'suspended'. The default case silently ignores it.
// Consider adding an explicit case or a TypeScript exhaustiveness check.
switch (user.status) {
case 'pending': return 'Waiting';
case 'active': return 'Active';
default: return 'Unknown';
}
These aren't lint rule violations, they're contextual reasoning about the code's intent. That's what makes AI review different from static analysis.
The Complete Setup Checklist
Before opening your first PR with this pipeline:
-
.github/workflows/ci.ymlcommitted to the repo -
tsconfig.jsonhasstrict: true(see the strict mode guide) - ESLint configured with
@typescript-eslint/strict-type-checked - Test suite runs via
npm testornpx vitest run - Branch protection enabled for
mainrequiring thequalitycheck -
.coderabbit.yamlcommitted with TypeScript-specific instructions - First PR opened to verify the pipeline runs end-to-end
The whole setup takes two to four hours the first time. After that, every PR gets type checking, linting, test coverage, and AI review without anyone remembering to do it.
A Note on AI Review False Positives
CodeRabbit will flag things that aren't bugs. I'd say maybe 20% of its comments on a mature codebase are "no action needed", it flagged something that's intentionally designed that way, or it misread context from adjacent files.
This isn't a problem if you treat AI review comments the same way you treat human review comments: read them, decide if they're valid, and reply with "LGTM, this is intentional because X." CodeRabbit reads your reply and updates its understanding. Over a few weeks, false positives on project-specific patterns drop significantly.
The remaining 80% are genuinely useful. Finding one real bug per PR that would have made it to production is worth far more than the noise from the false positives.
For the next step in quality automation, automating CI/CD gates specifically for AI-generated code at scale, the vibe coding quality framework covers how to extend these patterns across a larger workflow.