Webhook-triggered AI code review that fetches diffs, analyzes changes, and posts comments.
- Webhook triggers — GitHub webhook Impulse fires on PR open/update events
- Sequential pipeline — fetch diff, AI review, post comment in dependency order
- MCP integration — GitHub MCP server posts review comments via
create_pull_request_review - Secret injection — GitHub token and webhook secret stored in Kubernetes Secrets
flowchart LR
GH[GitHub Webhook] --> IMP[Impulse]
subgraph Pipeline["Story: pr-review-assistant"]
F[fetch-diff<br/>http-request] --> R[review-code<br/>openai-chat] --> P[post-comment<br/>mcp-adapter]
end
IMP --> F
P --> GHC[GitHub PR Comment]
- BubuStack installed on your cluster
- EngramTemplates:
http-request,openai-chat,mcp-adapter - ImpulseTemplate:
github-webhook-impulse - OpenAI API key
- GitHub personal access token with
reposcope
# 1. Create the namespace
kubectl apply -f bootstrap.yaml
# 2. Create secrets (copy and edit with your real values first)
cp secrets.yaml.example secrets.yaml
# Edit secrets.yaml with your OpenAI API key, GitHub token, and webhook secret
# 3. Deploy secrets and prompts ConfigMap
kubectl apply -f secrets.yaml -f prompts.yaml
# 4. Deploy the Engrams
kubectl apply -f engrams.yaml
# 5. Deploy the Story
kubectl apply -f story.yaml
# 6. Deploy the Impulse (starts the webhook listener)
kubectl apply -f impulse.yaml
# 7. Configure GitHub webhook
# Repository -> Settings -> Webhooks -> Add webhook
# Payload URL: your Impulse's external URL (see Verify section)
# Content type: application/json
# Secret: same as WEBHOOK_SECRET in your secrets.yaml
# Events: Pull requests# Check deployed resources
kubectl get engrams,stories,impulses -n github-pr-review
# Get the Impulse's webhook endpoint URL
kubectl get impulse pr-review-trigger -n github-pr-review -o jsonpath='{.status.endpoint}'
# Watch StoryRuns (one appears per PR event)
kubectl get storyruns -n github-pr-review -w
# Check individual StepRun phases
kubectl get stepruns -n github-pr-reviewkubectl delete namespace github-pr-review-
The Impulse CRD (
github-webhook-impulsetemplate) starts an HTTP server. It uses the controller-managed runner identity, so Bobrapet creates the namespacedServiceAccount,Role, andRoleBindingwith the normal StoryTrigger submitter baseline automatically. When GitHub sends a webhook POST, the Impulse validates the signature, extracts event data, and submits a durable StoryTrigger with the PR metadata as inputs. The controller then creates or reuses the target StoryRun. -
The
fetch-diffstep uses anhttp-requestEngram configured with GitHub API headers and bearer token from a Kubernetes Secret. It fetches the PR diff fromapi.github.com. -
The
review-codestep uses anopenai-chatEngram. The system prompt is stored in a ConfigMap (pr-review-prompts) and referenced via$bubuConfigMapRefin the Engram config. This keeps the Engram'swithblock small — the SDK resolves the ConfigMap reference at runtime inside the pod, avoiding inline size limits on StepRun inputs. -
The
post-commentstep uses the mcp-adapter Engram. It spawns the GitHub MCP server subprocess, invokescreate_pull_request_reviewwith the AI-generated review text, and captures the result. Template expressions like{{ inputs.repository | split "/" | first }}resolve owner/repo from the webhook payload. -
The Impulse's
sessionKeyStrategy: autoprevents duplicate runs for rapid webhook re-deliveries.
CRDs involved: Impulse, ImpulseTemplate (github-webhook-impulse), Story, StoryRun, StepRun, Engram, EngramTemplate (http-request, openai-chat, mcp-adapter)
