Buildkite Code Review Pipeline Example
This example demonstrates an AI-powered code review pipeline built with Buildkite dynamic pipelines and Claude Code. Adding a label to a GitHub PR triggers an AI agent that reviews the pull request and posts feedback.
How it works
- You add a
buildkite-reviewlabel to a GitHub PR - GitHub sends a webhook to Buildkite, which starts a build
- The first step evaluates the webhook payload — if it’s not a label event, the build exits early
- A TypeScript handler reads the payload, validates the PR, and posts an acknowledgement comment
- The handler uses the Buildkite SDK to dynamically generate a code review step and uploads it with
buildkite-agent pipeline upload - That step launches Claude Code in a Docker container to review the PR and post feedback
The handler pattern
The core of the handler is short — read the webhook payload from build metadata, evaluate whether to act, and generate a step with the Buildkite SDK:
// 1. Read the webhook payload that Buildkite stored as build metadata
const payload = JSON.parse(
execSync("buildkite-agent meta-data get buildkite:webhook").toString(),
);
// 2. Evaluate the condition — right event, right label?
if (payload.action !== "labeled" || payload.label.name !== process.env.TRIGGER_ON_LABEL) {
process.exit(0);
}
// 3. Generate a step with the Buildkite SDK and pipe it into `pipeline upload`
const pipeline = new Pipeline();
pipeline.addStep({ label: ":mag: Review the PR", command: "scripts/claude.sh" });
execSync("buildkite-agent pipeline upload", { input: pipeline.toYAML() });
The real handler also validates the PR exists and posts an acknowledgement comment between steps 2 and 3 — see scripts/handler.ts.
The key Buildkite features at play:
buildkite-agent pipeline upload— adding steps to a running build based on runtime conditionsbuildkite-agent meta-data— reading webhook payloads stored as build metadata@buildkite/buildkite-sdk— programmatically generating pipeline YAML in TypeScript- Buildkite webhooks — triggering builds from external events
- Buildkite Hosted Models — proxying LLM requests through Buildkite’s model provider endpoint
What’s interesting about this?
Like the self-healing pipeline example, this pipeline has no fixed steps. The webhook payload determines whether anything runs at all, and what runs is generated programmatically at build time. This is a different flavour of the same dynamic pipelines pattern — instead of remediating a failure, it’s performing an intelligent review.
Setup
To run this yourself, you’ll need:
- A Buildkite account
- A GitHub repository with a Buildkite pipeline configured to receive webhooks
- An Anthropic API key (or use Buildkite Hosted Models)
- Docker installed on your Buildkite agent
- Fork this repo
- Create a Buildkite pipeline pointing to your fork with webhook support enabled
- Configure a GitHub webhook to send
pull_requestevents with thelabeledaction to Buildkite - Set up the required secrets:
GITHUB_TOKENandBUILDKITE_API_TOKEN - Add the
buildkite-reviewlabel to any PR
Known limitations
- The handler assumes the Buildkite org slug and pipeline slug match the GitHub org and repo name. This won’t always be the case — you may need to configure these separately.
Credits
Originally built by Grant Colegate and Christian Nunciato as a demo for AWS re:Invent.
License
See LICENSE (MIT)



