GC-301h · Module 2

PR Review Bots

3 min read

A PR review bot runs Gemini CLI on every pull request, posts inline comments on problematic lines, and provides an overall summary. The architecture: a GitHub Actions workflow triggers on pull_request events, runs gemini -p with the PR diff as input, parses the structured JSON output into GitHub review comments, and posts them via the GitHub API. The bot appears as a reviewer on the PR — providing instant feedback while human reviewers handle the nuanced review.

Effective PR review bots require prompt engineering tuned for precision over recall. A bot that flags every line with a minor style suggestion becomes noise that developers ignore. The prompt should focus on high-signal issues: bugs, security vulnerabilities, logic errors, missing error handling, and breaking API changes. Style and formatting issues belong in linters, not AI review. The prompt should also include project-specific context — pull from GEMINI.md so the bot understands your architecture and conventions.

#!/bin/bash
# PR review bot — posts inline comments via GitHub API
set -euo pipefail

PR_NUMBER="$1"
DIFF=$(git diff origin/main...HEAD)

# Get structured review from Gemini
REVIEW=$(gemini -p "Review this PR diff. Focus only on bugs, security issues, and logic errors. Ignore style. Output JSON: {summary: string, comments: [{file: string, line: number, body: string, severity: \"critical\"|\"warning\"}]}\n\n$DIFF" \
  --output-format json)

# Extract inner response
RESPONSE=$(echo "$REVIEW" | jq -r '.response')

# Post each comment via GitHub API
echo "$RESPONSE" | jq -c '.comments[]?' | while read -r comment; do
  FILE=$(echo "$comment" | jq -r '.file')
  LINE=$(echo "$comment" | jq -r '.line')
  BODY=$(echo "$comment" | jq -r '.body')
  SEVERITY=$(echo "$comment" | jq -r '.severity')

  gh api "repos/{owner}/{repo}/pulls/$PR_NUMBER/comments" \
    -f body="**[$SEVERITY]** $BODY" \
    -f path="$FILE" \
    -F line="$LINE" \
    -f commit_id="$(git rev-parse HEAD)" \
    -f subject_type="line"
done

# Post summary
SUMMARY=$(echo "$RESPONSE" | jq -r '.summary // "No issues found."')
gh pr comment "$PR_NUMBER" --body "## Gemini Review\n\n$SUMMARY"