Automated PR code review powered by Claude Code + GitHub Actions
Inline comments on exact diff lines. Requests changes or approves. Learns from your codebase.
No API billing — Claude Max subscription via OAuth token • Bot identity — reviews from a GitHub App, not your account • Full Claude session — subagents, skills, memory, slop detection
PR opened / @cc-review ping
│
▼
┌─────────────────────────┐
│ GitHub Actions │
│ │
│ Clone bot repo │
│ Copy .claude/ into repo │
│ Pre-fetch PR diff │
└──────────┬──────────────┘
│
▼
┌─────────────────────────┐
│ Claude Code Session │
│ │
│ Load .cc-review.yaml │
│ Load persistent memory │
│ Deploy slop-researcher │
│ Analyze diff + patterns │
└──────────┬──────────────┘
│
▼
┌─────────────────────────┐
│ review-cli.ts post │
│ │
│ Findings JSON in │
│ → Resolve line numbers │
│ → Build review payload │
│ → Post APPROVE or │
│ REQUEST_CHANGES │
└─────────────────────────┘
Bot repo (this) Target repo (yours)
├── .claude/ ├── .cc-review.yaml ← customize this
│ ├── CLAUDE.md └── .github/workflows/
│ │ ├── cc-review.yml
│ ├── commands/ └── cc-review-interactive.yml
│ │ ├── review-pr.md
│ │ ├── bug-hunt.md Only 3 files. Everything else
│ │ ├── simplify-review.md is fetched from the bot repo
│ │ ├── memory-load.md at CI runtime.
│ │ └── memory-save.md
│ │
│ ├── agents/
│ │ ├── slop-researcher.md
│ │ ├── logic-bug-scanner.md
│ │ ├── edge-case-scanner.md
│ │ ├── integration-bug-scanner.md
│ │ ├── code-quality-scanner.md
│ │ ├── code-reuse-scanner.md
│ │ └── efficiency-scanner.md
│ │
│ ├── skills/review-guidelines/
│ │ ├── scripts/
│ │ │ ├── review-cli.ts ← review lifecycle CLI
│ │ │ └── diff-lines.ts ← diff parser
│ │ └── references/
│ │ ├── python-patterns.md
│ │ ├── typescript-patterns.md
│ │ └── csharp-patterns.md
│ │
│ └── hooks/
│ └── scripts/
│ └── enforce-review-cli.ts
│
└── scripts/
├── setup.sh / setup.cmd
└── install-to-repo.sh
Principle: Walls > Instructions. Everything deterministic is enforced outside the model.
The model never calls gh pr review or raw GitHub API endpoints. All review operations go through review-cli.ts — a PreToolUse hook blocks any attempt to bypass it.
review-cli.ts <command> --repo owner/repo --pr N [options]
| Command | What it does |
|---|---|
post |
Resolve findings to diff lines, build payload, post review |
approve |
Approve PR (refuses if unresolved threads exist) |
status |
Latest review state + unresolved thread count |
list |
List all reviews on a PR |
resolve |
Resolve a review thread via GraphQL |
Why not let the model call the API directly?
Models hallucinate line numbers, post multiple partial reviews, and skip safety checks before approving. The CLI makes these mistakes structurally impossible:
- Line resolution — Model writes a search string, CLI finds the exact diff line
- Single review — CLI bundles all inline comments into one payload
- Approval guard — CLI queries GraphQL for unresolved threads first
- Enforcement —
enforce-review-cli.tshook blocksgh pr review, direct APIPOSTs to the reviews endpoint, and raw GraphQL review mutations
- GitHub CLI (
gh) — installed and authenticated - Claude Code — logged into your Max account
- Admin access to the target repository
git clone https://github.com/Fennixx/cc-review.git && cd cc-review && ./scripts/setup.shManual setup steps
claude setup-tokenCopy the sk-ant-oat01-... token. Valid for 1 year.
Go to github.com/settings/apps/new:
| Setting | Value |
|---|---|
| Name | your-team-reviewer |
| Webhooks | Uncheck "Active" |
| Permissions | Contents (R/W), Issues (R/W), Pull requests (R/W) |
| Install scope | Only on this account |
After creating: note the App ID, generate a private key (.pem), and install on your repo.
| Secret | Value |
|---|---|
CLAUDE_CODE_OAUTH_TOKEN |
The sk-ant-oat01-... token |
REVIEWER_APP_ID |
Numeric App ID |
REVIEWER_APP_PRIVATE_KEY |
Full .pem file contents |
./scripts/install-to-repo.sh /path/to/your/repo
cd /path/to/your/repo
git add -A && git commit -m "Add cc-review bot" && git pushCreate .cc-review.yaml in your repo root:
version: 1
mode: standard # standard | strict | bug-hunt | simplify
auto_review: true # Review on PR open
languages:
- python
- typescript
ignore_paths:
- "docs/**"
- "**/*.md"
instructions: |
FastAPI project using SQLAlchemy.
All subprocess calls must use `uv run`.
known_patterns:
- "We use broad exception handlers in middleware intentionally"
slop_detection: true # AI-generated code detection
memory: true # Learn from past reviews| Mode | Trigger | Focus |
|---|---|---|
| standard | PR open (default) | Bugs, security, logic errors |
| strict | Label strict / manual |
Zero-tolerance — every finding is a required change |
| bug-hunt | Label bug-hunt / manual |
Logic errors, edge cases, integration bugs |
| simplify | Label simplify / manual |
Code reuse, quality, efficiency |
Comment on any PR to talk to the bot:
@cc-review # standard review
@cc-review bug-hunt this # deep bug hunting
@cc-review what does this change? # explain the PR
Specialized subagents are deployed depending on the review mode:
| Agent | Mode | Focus |
|---|---|---|
| slop-researcher | all | AI-generated code patterns |
| logic-bug-scanner | bug-hunt | Deep logic error analysis |
| edge-case-scanner | bug-hunt | Boundaries, off-by-one, null handling |
| integration-bug-scanner | bug-hunt | Cross-component interaction bugs |
| code-quality-scanner | simplify | Dead code, complexity, naming |
| code-reuse-scanner | simplify | Duplication and abstraction |
| efficiency-scanner | simplify | Performance and resource usage |
The bot maintains a persistent memory branch (claude-reviewer/memory) in the target repo when memory: true. It learns:
- False positives specific to your codebase
- Bug patterns your code is prone to
- Conventions and architectural decisions
Memory is loaded before every review and updated when the bot learns something new.
Bot not reviewing
- Check the Actions tab — is the workflow running?
- Verify all 3 secrets are set correctly
- Check the GitHub App is installed on the repo
Bot can't approve
- The GitHub App must be a different identity from the PR author
- Verify the App has
pull-requests: writepermission
OAuth token expired
Tokens last 1 year. Regenerate with claude setup-token.
Review is too strict / too lenient
- Change
modein.cc-review.yaml - Add project-specific
instructionsandknown_patterns
Built with Claude Code