HarborHarbor
DocumentationGuidesPlugins
Recipes

PR Review Bot

Always-on PR reviewer. Listens to GitHub events, summarises diff, posts inline comments.

When a PR is opened or updated, fetch the diff, summarise the change, and post a structured review back as a GitHub comment. Backed by a scheduled Function or a webhook-triggered App route.

Plugins

  • github-mcp (or github-rest-api for the lower-level surface)
  • orbit.ai for the summarisation step

The Function

pr-review.ts

defineJob({
  name: "pr-review",
  description: "Summarise a PR and post a review comment.",
  handler: async (ctx, input: { owner: string; repo: string; pr: number }) => {
    const pr   = await ctx.plugins.githubMcp.getPullRequest(input);
    const diff = await ctx.plugins.githubMcp.getDiff(input);

    const summary = await ctx.orbit.ai.run({
      model: "anthropic/claude-3.7-sonnet",
      prompt: [
        "You are reviewing a pull request.",
        "Return a concise structured review with:",
        "1. One-sentence summary of intent.",
        "2. Top 3 risks (if any).",
        "3. Test coverage assessment.",
        "",
        `Title: ${pr.title}`,
        `Description: ${pr.body ?? "(no description)"}`,
        "",
        "Diff:",
        diff.slice(0, 20_000),
      ].join("\n"),
      maxTokens: 600,
    });

    await ctx.plugins.githubMcp.createComment({
      owner: input.owner,
      repo:  input.repo,
      issue: input.pr,
      body:  `## Harbor PR review\n\n${summary}\n\n— [trace](https://tryharbor.ai/dashboard/traces/{{ run.id }})`,
    });

    return { pr: pr.html_url, summary };
  },
});
hrbr inspect -f ./pr-review.job.ts

Wire it to a webhook

pr-review-app.ts

deployApp({
  name: "pr-review",
  description: "GitHub webhook → PR review bot.",
  jobs: { review: "pr-review" },
  routes: {
    "POST /": {
      auth: "public",          // GitHub signs the webhook; verify HMAC inside
      job:  "review",
    },
  },
});
hrbr inspect -f ./pr-review-app.app.ts
# → URL: https://pr-review.<workspace>.tryharbor.ai

In GitHub repository settings → Webhooks, add the URL above with secret = some value you check inside the Function via HMAC. Trigger on pull_request events.

The public route fires on every webhook. Always verify the GitHub signature inside the handler before doing any work — otherwise anyone who guesses the URL can spam your AI budget.

Customising

  • Per-team prompt: read repo metadata, branch on pr.base.ref to pick a style ("fast review for hotfix branches", "thorough for main PRs").
  • Inline suggestions: instead of one summary comment, post line-level comments from orbit.ai output (parse line refs from the model output).
  • Skip drafts: bail out early if pr.draft === true.

Where to go next

The same shape works for CI status summaries, release notes, daily digests. The pattern: pull data → orbit.ai.run → post.