Appearance
Build a PR reviewer with Agent SDK
You'll build a reviewer that rates each pull request as trivial, moderate, or large, then approves safe changes or asks for a human review.
When it's deployed, you'll manage it in Deployed Agents.
Build it with a coding agent
Paste this prompt into your coding agent to build the reviewer from this page. The sections after it walk through the same steps by hand.
text
Build the PR reviewer from https://cursor.com/docs/agent-sdk/quickstart.md
in ./pr-reviewer. Fetch that page and follow each step in order.
- If agent-sdk isn't on PATH, install it with
npm install --global @grok/agent-sdk. Wait while I finish agent-sdk login.
- Use the code from the page as written. Ask me for a GitHub repository and
a pull request I didn't author, and use them in place of acme/checkout#42.
- Run both tool-call checks, and confirm the complexity each one reports.
- Ask me before any step that posts a review on GitHub. Skip the deploy step.
Finish with agent-sdk validate --dir . and the project's TypeScript check,
then tell me what passed.Prerequisites
You need Node 22.13 or newer and a Cursor login for model turns:
bash
npm install -g @grok/agent-sdk
agent-sdk loginCreate and run the project
bash
agent-sdk init ./pr-reviewer
cd pr-reviewer
agent-sdk devIn a second terminal, confirm the agent replies:
bash
agent-sdk run --dir . --message "Introduce yourself in one sentence."Add review instructions
Replace bot/instructions.md:
md
# PR reviewer
Call `inspect_pr` before you judge a pull request, then act on the
complexity it reports:
- `trivial`: approve with `submit_review` if the diff matches the title
and nothing looks risky.
- `moderate`: approve only when you understand every patch and see no
risk. Otherwise request a human review and name the files that worry you.
- `large`: request a human review right away and point the reviewer at
the biggest files.
Never approve a draft. End with one sentence that gives the verdict and why.Share the URL parser
Both tools parse a pull request URL, so put the parser in bot/lib/github.ts, where Agent SDK doesn't look for tools.
ts
export function parsePrUrl(prUrl: string) {
const [owner, repo, pulls, number] = new URL(prUrl).pathname.split("/").filter(Boolean);
const pull_number = Number.parseInt(number ?? "", 10);
if (pulls !== "pull" || owner === undefined || repo === undefined || Number.isNaN(pull_number)) {
throw new Error(`Not a pull request URL: ${prUrl}`);
}
return { owner, repo, pull_number };
}Add the inspect tool
Create bot/tools/inspect_pr.ts. It skips patches on a large pull request and caps the rest at 3,000 characters.
ts
import { defineTool } from "@grok/agent-sdk/tools";
import { z } from "zod";
import { parsePrUrl } from "../lib/github.js";
function rateComplexity(linesChanged: number, changedFiles: number) {
if (linesChanged <= 25 && changedFiles <= 2) {
return "trivial";
}
if (linesChanged <= 400 && changedFiles <= 15) {
return "moderate";
}
return "large";
}
export default defineTool({
description: "Fetch a pull request's title, patches, and complexity.",
inputSchema: z.object({ prUrl: z.string().describe("GitHub pull request URL") }),
async execute({ prUrl }, ctx) {
const pull = parsePrUrl(prUrl);
const octokit = await ctx.host.github.getOctokit();
const { data: pr } = await octokit.rest.pulls.get(pull);
const { data: files } = await octokit.rest.pulls.listFiles({ ...pull, per_page: 100 });
const complexity = rateComplexity(pr.additions + pr.deletions, pr.changed_files);
return {
title: pr.title,
draft: pr.draft ?? false,
complexity,
files: files.map((file) => ({
path: file.filename,
additions: file.additions,
deletions: file.deletions,
patch: complexity === "large" ? undefined : file.patch?.slice(0, 3000),
})),
};
},
});Verify complexity classification
Call the tool without a model turn:
bash
# Expect "complexity": "trivial"
agent-sdk tool call inspect_pr --dir . --input '{"prUrl":"https://github.com/facebook/react/pull/35623"}'
# Expect "complexity": "large" and no patch fields
agent-sdk tool call inspect_pr --dir . --input '{"prUrl":"https://github.com/facebook/react/pull/25229"}'Add the review tool
Create bot/tools/submit_review.ts:
ts
import { defineTool } from "@grok/agent-sdk/tools";
import { z } from "zod";
import { parsePrUrl } from "../lib/github.js";
export default defineTool({
description: "Approve the pull request, or comment asking for a human review.",
inputSchema: z.object({
prUrl: z.string().describe("GitHub pull request URL"),
verdict: z.enum(["approve", "request_human_review"]),
summary: z.string().describe("One or two sentences on why."),
}),
async execute({ prUrl, verdict, summary }, ctx) {
const approve = verdict === "approve";
const octokit = await ctx.host.github.getOctokit();
await octokit.rest.pulls.createReview({
...parsePrUrl(prUrl),
event: approve ? "APPROVE" : "COMMENT",
body: approve ? summary : `Human review needed. ${summary}`,
});
return { posted: true, verdict };
},
});You need GitHub write access and a pull request you didn't author.
Review a pull request
bash
agent-sdk run --dir . --message "Review https://github.com/acme/checkout/pull/42"Confirm inspect_pr runs before submit_review, then check the review on GitHub.
Trigger reviews from GitHub
Create bot/channels/github.ts:
ts
import { defaultGitHubAuth, githubChannel } from "@grok/agent-sdk/channels/github";
const REVIEW_ACTIONS = new Set(["opened", "reopened", "ready_for_review"]);
export default githubChannel({
botName: "agent-sdk-pr-reviewer",
cursorAccount: { repos: ["acme/checkout"] },
onPullRequest: (ctx, pr) => {
if (!REVIEW_ACTIONS.has(pr.action) || pr.draft) {
return null;
}
return {
auth: defaultGitHubAuth(ctx),
title: `Review ${ctx.repository.fullName}#${pr.number}`,
context: [`Review ${pr.url}.`],
};
},
});With agent-sdk dev running, replay an open pull request. Pull access is enough:
bash
agent-sdk github replay https://github.com/acme/checkout/pull/42 --dir . --action openedOpen the playground and confirm Review acme/checkout#42 shows both tool calls and the verdict.
Deploy the reviewer
Follow Deployment to run agent-sdk deploy, then manage the reviewer in Deployed Agents.
Where to go next
- Turn these two PRs into regression checks with Evals.
- Read about typed tools in Tools.
- Set up fixtures and forwarding with the GitHub guide.