A Free-Tier AI PR Reviewer: A GitHub Actions Workflow That Actually Works A developer built a GitHub Actions workflow that uses the open source MonkeyCode project's free model allowance to automatically review pull requests. The workflow captures a unified diff, sends it to the model with a prompt for structured JSON feedback, and posts deduplicated comments via the GitHub API. The design emphasizes working within free-tier limits by truncating diffs and handling duplicate comments. Automated code review is one of the few AI workflows that pays for itself on the first pull request, and you can run it entirely on a free model allowance if you design the pipeline around the model's limits rather than against them. I built a GitHub Actions workflow that calls the open source MonkeyCode project's free model access to comment on pull requests, and the result is a reviewer that catches real issues without spamming the conversation. Disclosure: This article was prepared as part of MonkeyCode's product outreach. The open source MonkeyCode project offers a free model allowance of ten million tokens and a free server option at the time of writing, and while the server is not required for this pipeline, it becomes useful if you later want to move the same logic to a hosted webhook. The setup is deliberately simple because the value is in the workflow, not in the model. The workflow triggers on pull request events, checks out the repository with full history, and then passes a unified diff to a Python script that asks the model for structured feedback. The first step is a workflow file that captures the diff between the base branch and the head branch. Using fetch-depth: 0 ensures that git can compute the exact changes, and the diff is saved to a temporary file that the review script can read. The environment variables carry the API key and the GitHub token, so no secrets appear in the repository. name: AI PR 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/${{ github.event.pull request.base.ref }}...HEAD /tmp/diff.txt - name: Run AI review env: MONKEYCODE API KEY: ${{ secrets.MONKEYCODE API KEY }} GITHUB TOKEN: ${{ secrets.GITHUB TOKEN }} run: python review.py /tmp/diff.txt The pull request event fires on both opened and synchronize, which means every new push to the branch will trigger a fresh review. That is usually desirable, but it also creates a duplicate-comment problem that the script must handle. The diff command compares the merge base with the head, so it only includes changes that are actually part of the pull request. The Python script is where the design decisions matter. The diff is truncated to a reasonable size before being sent to the model, because a pull request can easily exceed the input limits of a free-tier endpoint, and the prompt asks for a JSON array of comments with a path, line, and body. The model is instructed to return an empty array when there are no issues, which makes the parsing logic trivial. python import json, os, sys, urllib.request def review diff diff path : diff = open diff path .read :12000 prompt = "You are a senior code reviewer. " "Review this diff and return a JSON array of comments. " "Each comment must have 'path', 'line', and 'body'. " "Only comment on real issues. If no issues, return .\n\n" f"Diff:\n{diff}" payload = json.dumps { "model": "free-model", "messages": {"role": "user", "content": prompt} , "temperature": 0.2 } .encode req = urllib.request.Request "https://api.monkeycode.example/v1/chat/completions", data=payload, headers={ "Content-Type": "application/json", "Authorization": f"Bearer {os.environ 'MONKEYCODE API KEY' }" } with urllib.request.urlopen req as resp: data = json.loads resp.read content = data "choices" 0 "message" "content" try: return json.loads content except json.JSONDecodeError: return The script then posts each comment through the GitHub API, but only if the comment does not already exist. This deduplication step is essential because a workflow that triggers on both opened and synchronize events will otherwise repeat the same feedback on every push. The script also limits the total number of comments to five, which keeps the noise low and forces the model to prioritize the most important findings. python def post comments comments : existing = fetch existing comments posted = 0 for c in comments: if posted = 5: break key = c "path" , c "line" , c "body" if key in existing: continue create comment c "path" , c "line" , c "body" posted += 1 The workflow has real limitations that you should know before copying it. The free model will occasionally produce false positives, so the comments are suggestions rather than blockers, and the JSON output can be malformed, in which case the script simply skips that review cycle. The diff truncation means very large pull requests are only partially reviewed, and the model has no awareness of the surrounding codebase beyond the diff itself, so it cannot catch cross-file issues. This is not a replacement for a human reviewer; it is a triage layer that surfaces obvious problems before a human looks at the code. What surprised me most was how little code was needed to make this useful. The entire workflow is under a hundred lines, and the hardest part was not the API call but the deduplication and the output parsing, which are the same problems you would face with any external review tool. The free model allowance from MonkeyCode is generous enough for a small team's pull request volume, and the free server option becomes relevant if you want to move from GitHub Actions to a self-hosted webhook that can also handle other AI tasks. If you want to try this pattern, check the MonkeyCode repository for the current free model access and free server details, because quotas and endpoints change over time. The workflow itself is the part worth keeping, and it transfers to any model provider you might use later. A free-tier AI reviewer is not a gimmick; it is a practical way to spend a small portion of your allowance on something that saves real attention every day.