February 20, 2026 · 16 min read

AI Agent for GitHub: Automate Code Review, PR Summaries & Issue Triage

Engineering teams spend 6+ hours per week on code review. An AI agent handles the mechanical parts — style checks, summary generation, security scanning — so human reviewers focus on architecture and business logic.

Why Code Review Needs AI Agents

Code review is essential but painful. Here's the reality:

An AI agent doesn't replace human review. It amplifies it:

AI handles

The Mechanical Work

Style consistency, naming conventions, unused imports, potential null references, missing error handling, documentation gaps, test coverage, dependency vulnerabilities, common anti-patterns.

Humans handle

The Thinking Work

Architecture decisions, business logic correctness, edge cases that require domain knowledge, performance implications, whether the approach is the right one, team conventions that aren't in a linter.

💡 The ROI

Teams using AI code review agents report: 40% faster PR turnaround, 30% fewer style-related comments from humans, and reviewers spending their time on higher-value feedback. Developers actually prefer AI catching the small stuff — it's less personal than a colleague nitpicking their semicolons.

6 GitHub Agent Use Cases

Use Case 1

Automated PR Review

Reviews every PR for: bugs, security issues, performance problems, style violations, missing tests. Posts inline comments on specific lines. Provides an overall summary with risk assessment.

Use Case 2

PR Summary Generation

Reads the diff and generates a human-readable summary: what changed, why it matters, what to look out for during review. Especially useful for large PRs where reviewers need orientation.

Use Case 3

Issue Triage & Labeling

When a new issue is created, the agent: classifies it (bug/feature/question), sets priority labels, assigns to the right team, suggests related issues, and links to relevant docs or past discussions.

Use Case 4

Security Scanning

Scans every PR for: hardcoded secrets, SQL injection, XSS vulnerabilities, insecure dependencies, exposed API keys. Blocks merge if critical issues are found.

Use Case 5

Auto-Changelog Generation

On every release, generates a changelog from merged PRs. Groups by type (features, fixes, breaking changes). Links to PRs and issues. Posts to Slack and updates docs.

Use Case 6

Codebase Q&A

"What does the auth middleware do?" "Where is the payment logic?" "Who last changed the user model?" The agent indexes your codebase and answers questions, helping new developers onboard faster.

Build: PR Review Agent

// github-review-agent.js
import Anthropic from "@anthropic-ai/sdk";
import { Octokit } from "@octokit/rest";

const anthropic = new Anthropic();
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });

async function reviewPR(owner, repo, pullNumber) {
  // Get PR details
  const { data: pr } = await octokit.pulls.get({
    owner, repo, pull_number: pullNumber,
  });

  // Get the diff
  const { data: files } = await octokit.pulls.listFiles({
    owner, repo, pull_number: pullNumber, per_page: 100,
  });

  // Build review context
  const changedFiles = files.map(f => ({
    filename: f.filename,
    status: f.status, // added, modified, removed
    additions: f.additions,
    deletions: f.deletions,
    patch: f.patch?.substring(0, 5000), // Limit patch size
  }));

  const totalChanges = files.reduce(
    (sum, f) => sum + f.additions + f.deletions, 0
  );

  // Get repo context (README, contributing guide)
  const repoContext = await getRepoContext(owner, repo);

  // Review with Claude
  const response = await anthropic.messages.create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 4000,
    messages: [{
      role: "user",
      content: `Review this pull request.

PR Title: ${pr.title}
PR Description: ${pr.body || "No description"}
Author: ${pr.user.login}
Base: ${pr.base.ref} ← ${pr.head.ref}
Total changes: +${totalChanges} lines across ${files.length} files

Repository context:
${repoContext}

Changed files:
${changedFiles.map(f =>
  `\n### ${f.filename} (${f.status}, +${f.additions}/-${f.deletions})\n\`\`\`diff\n${f.patch || "Binary file"}\n\`\`\``
).join("\n")}

Provide your review as JSON:
{
  "summary": "2-3 sentence summary of what this PR does",
  "risk_level": "low|medium|high|critical",
  "risk_explanation": "why this risk level",
  "inline_comments": [
    {
      "file": "path/to/file.js",
      "line": 42,
      "side": "RIGHT",
      "severity": "critical|warning|suggestion|nitpick",
      "comment": "what's wrong and how to fix it"
    }
  ],
  "general_feedback": "overall architecture/approach feedback",
  "missing_tests": ["list of scenarios that should be tested"],
  "security_concerns": ["any security issues found"],
  "approved": true/false
}

Rules:
- Focus on bugs, security, and logic errors (high value)
- Don't nitpick style if there's a formatter configured
- Be specific: reference exact lines and suggest fixes
- If the PR is fine, say so — don't invent problems
- Flag breaking changes prominently`
    }],
  });

  const review = JSON.parse(response.content[0].text);

  // Post PR summary comment
  await octokit.issues.createComment({
    owner, repo, issue_number: pullNumber,
    body: formatReviewSummary(review),
  });

  // Post inline comments
  for (const comment of review.inline_comments) {
    try {
      await octokit.pulls.createReviewComment({
        owner, repo, pull_number: pullNumber,
        body: `${severityEmoji(comment.severity)} **${comment.severity.toUpperCase()}**: ${comment.comment}`,
        path: comment.file,
        line: comment.line,
        side: comment.side,
        commit_id: pr.head.sha,
      });
    } catch (e) {
      // Line might not be in the diff — post as general comment
      console.warn(`Could not post inline comment on ${comment.file}:${comment.line}`);
    }
  }

  // Submit the review
  await octokit.pulls.createReview({
    owner, repo, pull_number: pullNumber,
    event: review.approved ? "APPROVE" : "REQUEST_CHANGES",
    body: review.approved
      ? "✅ AI review passed. Human review still recommended."
      : "⚠️ Issues found — see inline comments.",
  });

  return review;
}

function severityEmoji(severity) {
  return { critical: "🔴", warning: "🟡", suggestion: "🔵", nitpick: "⚪" }[severity] || "💬";
}

function formatReviewSummary(review) {
  const riskEmoji = { low: "🟢", medium: "🟡", high: "🟠", critical: "🔴" };
  return `## 🤖 AI Code Review

**Summary:** ${review.summary}

**Risk Level:** ${riskEmoji[review.risk_level]} ${review.risk_level.toUpperCase()} — ${review.risk_explanation}

**Inline Comments:** ${review.inline_comments.length} (${review.inline_comments.filter(c => c.severity === "critical").length} critical)

${review.security_concerns.length > 0
  ? `### 🔒 Security Concerns\n${review.security_concerns.map(c => `- ${c}`).join("\n")}\n`
  : ""}
${review.missing_tests.length > 0
  ? `### 🧪 Missing Tests\n${review.missing_tests.map(t => `- ${t}`).join("\n")}\n`
  : ""}
${review.general_feedback ? `### 💡 General Feedback\n${review.general_feedback}\n` : ""}
---
*This is an automated review. Human review is still required before merge.*`;
}

Build: PR Summary Generator

async function generatePRSummary(owner, repo, pullNumber) {
  const { data: files } = await octokit.pulls.listFiles({
    owner, repo, pull_number: pullNumber, per_page: 100,
  });

  const diff = files.map(f =>
    `${f.filename} (${f.status}, +${f.additions}/-${f.deletions})`
  ).join("\n");

  const response = await anthropic.messages.create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 800,
    messages: [{
      role: "user",
      content: `Generate a PR summary for reviewers. Be concise.

Files changed:
${diff}

Return in this format:
## What Changed
(2-3 bullet points explaining the changes at a high level)

## Why
(1 sentence on the motivation)

## Review Focus
(What reviewers should pay attention to)

## Impact
(What could break, who is affected)`
    }],
  });

  // Update PR description
  const { data: pr } = await octokit.pulls.get({
    owner, repo, pull_number: pullNumber,
  });

  await octokit.pulls.update({
    owner, repo, pull_number: pullNumber,
    body: `${pr.body || ""}\n\n---\n\n🤖 **Auto-generated Summary:**\n\n${response.content[0].text}`,
  });
}

Build: Issue Triage Agent

async function triageIssue(owner, repo, issueNumber) {
  const { data: issue } = await octokit.issues.get({
    owner, repo, issue_number: issueNumber,
  });

  // Get repo labels
  const { data: labels } = await octokit.issues.listLabelsForRepo({
    owner, repo, per_page: 100,
  });

  // Search for related issues
  const { data: related } = await octokit.search.issuesAndPullRequests({
    q: `repo:${owner}/${repo} ${issue.title}`,
    per_page: 5,
  });

  const response = await anthropic.messages.create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 500,
    messages: [{
      role: "user",
      content: `Triage this GitHub issue. Return JSON:
{
  "type": "bug|feature|question|documentation|chore",
  "priority": "critical|high|medium|low",
  "labels": ["from available labels below"],
  "component": "which part of the codebase",
  "duplicate_of": issue_number or null,
  "response": "helpful response to post on the issue",
  "assignee_team": "frontend|backend|devops|design|none"
}

Issue #${issueNumber}: ${issue.title}
Body: ${issue.body?.substring(0, 2000) || "No description"}
Author: ${issue.user.login}

Available labels: ${labels.map(l => l.name).join(", ")}

Potentially related issues:
${related.items.slice(0, 5).map(i =>
  `#${i.number}: ${i.title} (${i.state})`
).join("\n")}

Rules:
- Only use labels that exist in the repo
- If it looks like a duplicate, reference the original issue
- Response should be helpful and welcoming
- For bugs: ask for reproduction steps if missing
- For features: acknowledge and explain the process`
    }],
  });

  const triage = JSON.parse(response.content[0].text);

  // Apply labels
  if (triage.labels.length > 0) {
    await octokit.issues.addLabels({
      owner, repo, issue_number: issueNumber,
      labels: triage.labels,
    });
  }

  // Post response
  await octokit.issues.createComment({
    owner, repo, issue_number: issueNumber,
    body: triage.response + (triage.duplicate_of
      ? `\n\nThis might be related to #${triage.duplicate_of}.`
      : ""),
  });

  return triage;
}

Build: Security Scanner Agent

async function securityScan(owner, repo, pullNumber) {
  const { data: files } = await octokit.pulls.listFiles({
    owner, repo, pull_number: pullNumber, per_page: 100,
  });

  const concerns = [];

  for (const file of files) {
    if (!file.patch) continue;

    const response = await anthropic.messages.create({
      model: "claude-sonnet-4-20250514",
      max_tokens: 500,
      messages: [{
        role: "user",
        content: `Scan this code diff for security issues. Return JSON:
{
  "issues": [
    {
      "severity": "critical|high|medium|low",
      "type": "hardcoded_secret|sql_injection|xss|auth_bypass|
              insecure_dependency|data_exposure|other",
      "line": line_number,
      "description": "what the issue is",
      "fix": "how to fix it"
    }
  ]
}

File: ${file.filename}
Diff:
${file.patch.substring(0, 4000)}

Only report REAL security issues. False positives waste developer time.
Check for: API keys, passwords, tokens in code, SQL string
concatenation, unescaped HTML output, missing auth checks,
insecure crypto, exposed internal URLs.`
      }],
    });

    const result = JSON.parse(response.content[0].text);
    if (result.issues.length > 0) {
      concerns.push(...result.issues.map(i => ({
        ...i, file: file.filename
      })));
    }
  }

  if (concerns.some(c => c.severity === "critical")) {
    // Block the PR
    await octokit.pulls.createReview({
      owner, repo, pull_number: pullNumber,
      event: "REQUEST_CHANGES",
      body: `🔴 **SECURITY: Critical issues found**\n\n` +
        concerns.filter(c => c.severity === "critical").map(c =>
          `- **${c.file}:${c.line}** — ${c.type}: ${c.description}\n  Fix: ${c.fix}`
        ).join("\n\n"),
    });
  }

  return concerns;
}

Build: Auto-Changelog Generator

async function generateChangelog(owner, repo, sinceTag) {
  // Get merged PRs since last release
  const { data: comparison } = await octokit.repos.compareCommits({
    owner, repo,
    base: sinceTag,
    head: "main",
  });

  // Get PRs from merge commits
  const prNumbers = comparison.commits
    .filter(c => c.commit.message.startsWith("Merge pull request"))
    .map(c => parseInt(c.commit.message.match(/#(\d+)/)?.[1]))
    .filter(Boolean);

  const prs = await Promise.all(
    prNumbers.map(n =>
      octokit.pulls.get({ owner, repo, pull_number: n })
        .then(r => r.data)
    )
  );

  const response = await anthropic.messages.create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 1500,
    messages: [{
      role: "user",
      content: `Generate a changelog from these merged PRs.

PRs:
${prs.map(pr =>
  `#${pr.number}: ${pr.title} (by @${pr.user.login})\n${pr.body?.substring(0, 200) || "No description"}`
).join("\n\n")}

Format as:
## [version] — YYYY-MM-DD

### 🚀 Features
- Description (#PR)

### 🐛 Bug Fixes
- Description (#PR)

### 🔧 Improvements
- Description (#PR)

### ⚠️ Breaking Changes
- Description (#PR)

Rules:
- Write for end users, not developers
- Group logically, not by PR order
- Highlight breaking changes prominently
- Credit contributors with @mentions`
    }],
  });

  return response.content[0].text;
}

Ship better code, faster

The AI Employee Playbook includes the complete GitHub agent setup with PR review, issue triage, and security scanning — plus 12 other production-ready agent templates.

Get the Playbook — €29

Tool Comparison: 8 AI Code Review Tools

Tool Best For Price Custom Rules
GitHub Copilot PR Review Native GitHub integration $19/user/mo ⚠️ Limited
CodeRabbit Comprehensive AI code review Free / $15/user/mo ✅ Good
Sourcery Python-focused quality checks Free / $20/mo ⚠️ Some
Codacy Code quality + security scanning Free / $15/user/mo ✅ Good
Snyk Security & dependency scanning Free / $25/mo ✅ Full
Qodo (CodiumAI) Test generation from PRs Free / $19/mo ⚠️ Some
Graphite Stacked PRs + AI summaries Free / $20/user/mo ❌ Limited
Custom Agent (this guide) Full control, any workflow ~$5-20/mo (API) ✅ Full

Our recommendation: Start with CodeRabbit — it's the best out-of-the-box AI code review with good customization. Use GitHub Copilot if you're already paying for it. Build custom when you need specific security rules, integration with internal tools, or custom review logic that no SaaS tool supports.

Complete GitHub Action (Copy & Paste)

# .github/workflows/ai-review.yml
name: AI Code Review

on:
  pull_request:
    types: [opened, synchronize]

permissions:
  contents: read
  pull-requests: write
  issues: write

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: actions/setup-node@v4
        with:
          node-version: "20"

      - name: Install dependencies
        run: npm install @anthropic-ai/sdk @octokit/rest

      - name: Run AI Review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          node -e "
            const { reviewPR } = require('./scripts/ai-review.js');
            reviewPR(
              '${{ github.repository_owner }}',
              '${{ github.event.repository.name }}',
              ${{ github.event.pull_request.number }}
            ).then(r => console.log('Review complete:', r.risk_level));
          "
💡 Cost control

Set a max diff size (e.g., 500 lines). For larger PRs, review only critical files (*.ts, *.py, not package-lock.json). Skip draft PRs. Skip PRs from bots (dependabot). A typical review costs $0.02-0.10 in API calls.

6 Mistakes That Annoy Developers

Mistake 1

Too many nitpick comments

If your agent leaves 20 comments about missing semicolons, developers will ignore all of them — including the one about the SQL injection. Filter out low-severity issues unless they violate team standards. Less is more.

Mistake 2

False positives on security scanning

Flagging password = getenv("DB_PASSWORD") as a hardcoded secret is a false positive that erodes trust. Tune your prompts to understand the difference. If you're not sure, mark it as "possible concern" not "critical."

Mistake 3

Reviewing generated files

Lock files, build outputs, migrations, and auto-generated code shouldn't be reviewed. Exclude them: package-lock.json, *.generated.ts, dist/*, migrations/*. Wasted tokens and noisy feedback.

Mistake 4

No way to dismiss or ignore

Developers need to be able to say "not applicable" to AI comments. Add a /ai-dismiss command or a 👎 reaction that teaches the agent. Without this, frustration builds fast.

Mistake 5

Blocking merge on AI review alone

AI should flag, not gate. Make AI review a "required check" only for critical security issues (hardcoded secrets). Everything else should be advisory. Developers should be able to merge with AI warnings if they understand the tradeoffs.

Mistake 6

Not respecting .gitattributes and repo conventions

If the repo uses tabs, don't suggest spaces. If they use CommonJS, don't suggest ESM. Read the repo's config files (eslint, prettier, tsconfig) and align your feedback with existing conventions. Fighting the repo's style creates friction.

Automate your GitHub workflow

The AI Employee Playbook includes the complete GitHub agent with PR review, issue triage, security scanning, and changelog generation — plus 12 other agent templates.

Get the Playbook — €29

What's Next

Start with the PR summary generator — it's the least controversial and immediately useful. Developers love not having to write PR descriptions. Then add the review agent, starting in "advisory only" mode (no blocking). Once the team trusts it, add security scanning as a required check.

The best engineering teams don't resist AI code review. They configure it to match their standards, use it to catch what humans miss, and free up reviewers to focus on what actually matters: "Is this the right approach?"

Want the complete agent-building system?

The AI Employee Playbook covers the 3-file framework, memory systems, autonomy rules, and real production examples.

Get the Playbook — €29