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(orgithub-rest-apifor the lower-level surface)orbit.aifor the summarisation step
The Function
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.tsWire it to a webhook
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.aiIn 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.refto pick a style ("fast review for hotfix branches", "thorough formainPRs"). - Inline suggestions: instead of one summary comment, post line-level
comments from
orbit.aioutput (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.