Skip to content

Review prepared pull-request evidence

This GitHub-read-only reviewer uses host code to fetch the PR with gh and git, builds a trimmed pr/ evidence tree, then hands that tree to the model. The model reads the diff, loads a review skill, and returns at most three high-confidence findings.

Use this example when the host should control evidence collection and the model shouldn't browse or mutate the source repository.

Browse the current reviewer source.

Separate evidence preparation from review

The reviewer separates preparation from judgment:

  • Host code owns GitHub and Git access.
  • A server tool turns untrusted PR input into bounded workspace files.
  • A custom channel seeds those files before the model starts.
  • An on-demand skill defines the review procedure and output contract.
  • The model returns chat text. No path posts a GitHub review.

This architecture gives the model a purpose-built evidence package instead of a checkout.

Follow a review

The custom HTTP path runs this sequence:

  1. POST /v1/channels/review/ receives a PR reference.
  2. The handler calls prepare_pr without a model turn.
  3. Host code reads PR metadata and the unified diff.
  4. It reuses a matching checkout, force-fetching the PR ref there when the commit is missing. Without a matching checkout, it uses a temporary bare cache.
  5. It creates pr/MANIFEST.md, pr/meta.json, pr/diff.patch, and selected small files and rules.
  6. send({ workspaceFiles }) creates the model session with that evidence.
  7. The model reads the manifest and diff, then loads pr-review.
  8. The channel returns session and playground URLs while the review streams.

If a normal chat starts without evidence, the model can call prepare_pr mid-turn. That form writes the same files into the active session workspace.

Map the evidence-review files

FilePurpose
agent/agent.tsSelects the local runtime and model.
agent/instructions.mdRequires diff-first review and confines model work to pr/.
agent/tools/prepare_pr.tsExposes host preparation as a typed server tool.
agent/lib/prepare-pr.tsParses PR references, runs gh and git, and builds the evidence map.
agent/channels/review.tsProvides the loopback-only prepare-and-send HTTP route.
agent/channels/slack.tsExtracts PR references and prepares evidence for mentions and direct messages.
agent/skills/pr-review.mdSets finding limits, severities, and the machine-readable review format.
agent/lib/log.tsWrites timing logs for the host tools to stderr.
agent/storage.tsPersists sessions and events with cursorHostedStorage.
evals/evals.config.tsCaps eval run concurrency.
evals/review/smoke.eval.tsSeeds fake evidence and checks the review path without GitHub.

There is no authored GitHub channel, MCP connection, subagent, schedule, hook, A/B experiment, approval, or custom storage.

Prepare the host

You need:

  • Node 22.13 or newer.
  • An agent-runtime credential for model turns and account-linked Slack.
  • gh and git on PATH.
  • gh access to the target PR.
  • Network access to GitHub and a writable temporary directory.

The preparer can prefer a configured local checkout. Its origin must match the target repository. Otherwise the reviewer uses its bare cache. It never checks out the PR into the serve host's working tree.

Validate the surface

bash
agent-sdk validate --dir examples/bugbot
agent-sdk info --dir examples/bugbot --json

The manifest should show one server tool, one skill, and two authored channels.

Inspect evidence without a model turn

Call the preparation tool directly:

bash
agent-sdk call prepare_pr \
  --dir examples/bugbot \
  --input '{"pr":"https://github.com/owner/repo/pull/123"}'

Direct tool calls use a scratch workspace removed after the call. prepare_pr detects this path and returns the complete file map in its result. In a model session, it writes the files and returns a smaller summary.

The evidence builder applies explicit limits:

EvidenceLimit
Post-change file12,000 characters
One rule file8,000 characters
Combined rules12,000 characters
PR body in metadata2,000 characters

Large files remain visible in diff.patch. The manifest records which full files or rules were omitted.

The per-file limits aren't an aggregate context cap. Every changed file below 12,000 characters can be included. The diff command has a 12 MiB output buffer; a larger diff fails preparation instead of being truncated.

Run the HTTP review path

Start the server:

bash
agent-sdk dev examples/bugbot

From another terminal:

bash
curl -s -X POST \
  http://127.0.0.1:3000/bugbot/v1/channels/review/ \
  -H 'content-type: application/json' \
  -d '{"pr":"https://github.com/owner/repo/pull/123"}'

The route returns status: "started", a continuation token, and session and playground URLs. Open the session URL to watch the model read the evidence and produce findings.

The channel declares localDevStrict(). Direct loopback callers can use it. Proxy-forwarding headers and non-loopback hosts are rejected.

Send a follow-up by passing the returned key:

bash
curl -s -X POST \
  http://127.0.0.1:3000/bugbot/v1/channels/review/ \
  -H 'content-type: application/json' \
  -d '{"pr":"owner/repo#123","key":"<continuation-token>"}'

The follow-up resumes the session without fetching a new evidence tree.

Run the Slack path

The account-linked Slack channel handles review-bot mentions and direct messages:

Review https://github.com/owner/repo/pull/123

Slack handlers don't receive the channel callTool helper. This example calls the shared preparePrReview host function, then returns workspaceFiles in the Slack message preparation result. The model sees the same evidence and prompt as the HTTP path.

If a message contains no PR reference, the handler asks for one. Thread follow-ups keep the same session.

See how the skill constrains review

pr-review.md tells the model to:

  • read the manifest and unified diff first,
  • open at most one supporting file or rules file when a hunk is ambiguous,
  • avoid shell, network, gh, and git,
  • report no more than three findings,
  • keep each description under 120 words, and
  • emit the machine-readable review contract.

The root instructions set the evidence boundary. The skill holds the reusable review procedure. Keeping those roles separate lets another agent reuse the same skill with different intake channels.

Run the fixture-backed eval

bash
agent-sdk eval --dir examples/bugbot --list
agent-sdk eval --dir examples/bugbot review/smoke --json

The eval constructs a PreparedPrReview, seeds its file map through workspaceFiles, and checks for at least one read call with no shell call. It doesn't assert which evidence file was read or whether the skill loaded. It accepts either a formatted review or a clean result.

This case tests review behavior without GitHub credentials or network data. Add fixtures with reachable bugs when you need stricter location and severity checks.

Keep the side-effect boundary clear

The reviewer makes no remote GitHub writes. It doesn't author a GitHub channel and doesn't call a review API. Host preparation does write session evidence and force-update refs/pull/<N>/head in either its bare cache or a matching local checkout when the commit is missing. Every result ends with a note saying no GitHub review was posted.

If you add publishing later, keep it in a separate tool. This preserves a read-only preparation and review path safe to run in evals.

Reuse the evidence handoff

Use host-prepared workspaces when:

  • external APIs should stay off the model's tool surface,
  • context needs hard size limits,
  • the model should inspect a snapshot instead of a live checkout, or
  • several channels need the same preparation.

Return workspaceFiles from direct host preparation, write into ctx.workspaceDir for mid-turn recovery, and encode the reading order in both the manifest and a skill.

Where to go next