Your pull request pipeline deserves a free AI review stage. It takes about 30 minutes to wire. This tutorial uses MonkeyCode's free tier. You get automated comments on every PR. The cost is zero until the quota runs out.
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
MonkeyCode is an open-source AI coding assistant. It offers free model access and a free hosted server. Both are operator-supplied claims. Verify the current quotas in the docs before you plan around them.
Why Add an AI First Pass
Human review is slow. It is also expensive. An AI reviewer catches obvious issues first. Your team then focuses on design and architecture.
Treat the AI as a filter. Not as a replacement.
What You Need
- A GitHub repository
- A CI provider (GitHub Actions here)
- A MonkeyCode account with API access
- A token for the free model endpoint
Stage 1: Get a Token
Sign in to MonkeyCode. Create an API token. The dashboard shows your free quota. Note the number. Record the date. Quotas change.
Store the token as a CI secret. Name it MONKEYCODE_TOKEN.
Stage 2: Write the Review Script
The script reads a diff. It sends the diff to the model. It prints issues in a parseable format.
import os
import sys
import requests
def get_diff():
if os.environ.get('PR_DIFF'):
return os.environ['PR_DIFF']
return sys.stdin.read()
def review(diff):
url = os.environ.get('MONKEYCODE_URL', 'http://localhost:3000/v1/completions')
token = os.environ['MONKEYCODE_TOKEN']
prompt = f"""Review this code diff. Focus on:
1. Bugs and logic errors
2. Security issues
3. Performance problems
For each issue, give: line number, severity (critical/warning/nit), one-sentence fix.
DIFF:
{diff}"""
response = requests.post(
url,
headers={'Authorization': f'Bearer {token}'},
json={'prompt': prompt, 'max_tokens': 500},
)
data = response.json()
return data['choices'][0]['text']
if __name__ == '__main__':
diff = get_diff()
if not diff.strip():
print('No diff to review.')
sys.exit(0)
print(review(diff))
Stage 3: Test the Script Locally
Do not push to CI yet. Test on your machine first.
Create a sample diff file.
cat > /tmp/sample.diff << 'EOF'
+def calculate_total(items):
+ total = 0
+ for item in items:
+ total += item.price
+ return total
EOF
Run the script.
export MONKEYCODE_TOKEN=your-token
export MONKEYCODE_URL=http://localhost:3000
python review.py < /tmp/sample.diff
Verify: You see a list of issues. The format includes line numbers and severity. If you get an error, fix it now. CI debugging is slower.
Stage 4: Wire It Into GitHub Actions
Create .github/workflows/ai-review.yml.
name: AI Code Review
on:
pull_request:
types: [opened, synchronize]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get diff
run: |
git diff origin/main...HEAD > /tmp/diff.txt
echo "PR_DIFF=$(cat /tmp/diff.txt)" >> $GITHUB_ENV
- name: Run AI review
env:
MONKEYCODE_TOKEN: ${{ secrets.MONKEYCODE_TOKEN }}
MONKEYCODE_URL: ${{ vars.MONKEYCODE_URL }}
run: |
python review.py < /tmp/diff.txt > /tmp/review.txt
- name: Post comment
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const review = fs.readFileSync('/tmp/review.txt', 'utf8');
if (review.trim() === 'No diff to review.') {
console.log('Nothing to review.');
return;
}
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: '## AI Review\n\n' + review
});
Stage 5: Verify It Works
Open a test PR. Add a deliberate bug. Watch the CI run.
Verify:
- The CI job passes
- A comment appears on the PR
- The comment mentions the bug you planted
If the comment does not appear, check the CI logs. Common causes: wrong token, wrong URL, empty diff.
Expected Failure Modes
Free tiers fail in predictable ways. Here is what you will hit.
| Symptom | Cause | Fix |
|---|---|---|
| 401 | Wrong token | Regenerate. Update the secret. |
| 429 | Quota exhausted | Add a fallback. Or wait. |
| Empty comment | Model returned nothing | Increase max_tokens. |
| Timeout | Free server slow | Increase CI timeout. |
Add a Fallback
A free tier can run out. Your CI should not break when it does. Add a fallback. If the review fails, post a warning instead of failing the build.
try:
review_text = review(diff)
except Exception as e:
print(f'AI review failed: {e}')
print('Skipping AI review. Human review required.')
sys.exit(0)
This keeps the pipeline green. The AI review is a bonus. Not a gate.
Tune the Prompt
The default prompt is a starting point. Your codebase has its own patterns. Adjust the prompt to match.
Add your project's conventions. Add your security checklist. Add your common bug patterns.
prompt = f"""Review this diff for a Django project.
Check for: missing migrations, N+1 queries, missing CSRF protection.
Also check: {', '.join(EXTRA_CHECKS)}
...
"""
A tuned prompt beats a generic one. Spend ten minutes on it.
Limit Diff Size
Large diffs burn tokens fast. A 1000-line diff can cost thousands of tokens. Set a limit.
MAX_DIFF_CHARS = 10000
if len(diff) > MAX_DIFF_CHARS:
print('Diff too large for AI review. Skipping.')
sys.exit(0)
This protects your quota. It also keeps review quality high. Models lose focus on huge inputs.
Limitations
- The free quota is finite. Heavy teams will exhaust it.
- Free servers are shared. Latency varies.
- Model quality varies. The review is a first pass. Not a guarantee.
- The prompt matters. Tune it to your codebase.
Who Should Skip This
- Teams with strict data policies. Code goes to a third-party server.
- Teams needing guaranteed reviews. Free tiers have no SLA.
- Teams with huge diffs. Token costs scale with diff size.
Your Pipeline, Upgraded
You now have a free AI reviewer. It catches obvious issues. It runs on every PR. It costs nothing until the quota runs out.
Start with a small repo. Tune the prompt. Watch the first few reviews. Then expand.
The script is yours. The workflow is yours. The free tier is the only dependency.
Top comments (0)