Skip to main content
This guide walks you through connecting Mibyan to GitHub so it automatically fetches a pull request’s diff, analyzes the code changes, and posts a comment — triggered by a webhook event with no manual prompting. When a PR is opened or updated, GitHub sends a webhook POST to your Mibyan instance. Mibyan runs the agent with a prompt that instructs it to retrieve the diff via the gh CLI, and the response is posted back to the PR thread.
Want a simpler setup without a public endpoint?If you don’t have a public URL or just want to get started quickly, check out Build a GitHub PR Review Agent — uses cron jobs to poll for PRs on a schedule, works behind NAT and firewalls.
Reference docsFor the full webhook platform reference (all config options, delivery types, dynamic subscriptions, security model) see Webhooks.
Prompt injection riskWebhook payloads contain attacker-controlled data — PR titles, commit messages, and descriptions can contain malicious instructions. When your webhook endpoint is exposed to the internet, run the gateway in a sandboxed environment (Docker, SSH backend). See the security section below.

Prerequisites

  • Mibyan installed and running (mibyan gateway)
  • gh CLI installed and authenticated on the gateway host (gh auth login)
  • A publicly reachable URL for your Mibyan instance (see Local testing with ngrok if running locally)
  • Admin access to the GitHub repository (required to manage webhooks)

Step 1 — Enable the webhook platform

Add the following to your ~/.mibyan/config.yaml:
Key fields:
The payload does not contain codeThe GitHub webhook payload includes PR metadata (title, description, branch names, URLs) but not the diff. The prompt above instructs the agent to run gh pr diff to fetch the actual changes. The default mibyan-webhook toolset is deliberately constrained (web search/extract, vision, clarify — no terminal) because webhook payloads can carry untrusted content. To let this route run gh, add a per-route toolset grant: toolsets: ["terminal", "web"] on the route config — see Per-route toolsets.

Step 2 — Start the gateway

You should see:
Verify it’s running:

Step 3 — Register the webhook on GitHub

  1. Go to your repository → Settings → Webhooks → Add webhook
  2. Fill in:
    • Payload URL: https://your-public-url.example.com/webhooks/github-pr-review
    • Content type: application/json
    • Secret: the same value you set for secret in the route config
    • Which events? → Select individual events → check Pull requests
  3. Click Add webhook
GitHub will immediately send a ping event to confirm the connection. It is safely ignored — ping is not in your events list — and returns {"status": "ignored", "event": "ping"}. It is only logged at DEBUG level, so it won’t appear in the console at the default log level.

Step 4 — Open a test PR

Create a branch, push a change, and open a PR. Within 30–90 seconds (depending on PR size and model), Mibyan should post a review comment. To follow the agent’s progress in real time:

Local testing with ngrok

If Mibyan is running on your laptop, use ngrok to expose it:
Copy the https://...ngrok-free.app URL and use it as your GitHub Payload URL. On the free ngrok tier the URL changes each time ngrok restarts — update your GitHub webhook each session. Paid ngrok accounts get a static domain. You can smoke-test a static route directly with curl — no GitHub account or real PR needed.
Use deliver: log when testing locallyChange deliver: github_comment to deliver: log in your config while testing. Otherwise the agent will attempt to post a comment to the fake org/repo#99 repo in the test payload, which will fail. Switch back to deliver: github_comment once you’re satisfied with the prompt output.
Then watch the agent run:
mibyan webhook test <name> only works for dynamic subscriptions created with mibyan webhook subscribe. It does not read routes from config.yaml.

Filtering to specific actions

GitHub sends pull_request events for many actions: opened, synchronize, reopened, closed, labeled, etc. The events list filters by the X-GitHub-Event header value, and route-level filters can narrow by payload fields such as action. The prompt in Step 1 already handles this by instructing the agent to stop early for closed and labeled events.
The agent still runs and consumes tokensThe “stop here” instruction prevents a meaningful review, but the agent still runs to completion for every pull_request event regardless of action. Prefer filtering before the agent wakes:
For high-volume repositories, you can still filter upstream with a GitHub Actions workflow that calls your webhook URL conditionally.
There is no Jinja2 or conditional template syntax. {field} and {nested.field} are the only substitutions supported. Anything else is passed verbatim to the agent.

Using a skill for consistent review style

Load a Mibyan skill to give the agent a consistent review persona. Add skills to your route inside platforms.webhook.extra.routes in config.yaml:
Note: Only the first skill in the list that is found is loaded. Mibyan does not stack multiple skills — subsequent entries are ignored.

Sending responses to Slack or Discord instead

Replace the deliver and deliver_extra fields inside your route with your target platform:
The target platform must also be enabled and connected in the gateway. If chat_id is omitted, the response is sent to that platform’s configured home channel. Valid deliver values: log · github_comment · telegram · discord · slack · signal · sms

GitLab support

The same adapter works with GitLab. GitLab uses X-Gitlab-Token for authentication (plain string match, not HMAC) — Mibyan handles both automatically. For event filtering, GitLab sets X-GitLab-Event to values like Merge Request Hook, Push Hook, Pipeline Hook. Use the exact header value in events:
GitLab payload fields differ from GitHub’s — e.g. {object_attributes.title} for the MR title and {object_attributes.iid} for the MR number. The easiest way to discover the full payload structure is GitLab’s Test button in your webhook settings, combined with the Recent Deliveries log. Alternatively, omit prompt from your route config — Mibyan will then pass the full payload as formatted JSON directly to the agent, and the agent’s response (visible in the gateway log with deliver: log) will describe its structure.

Security notes

  • Never use INSECURE_NO_AUTH in production — it disables signature validation entirely. It is only for local development.
  • Rotate your webhook secret periodically and update it in both GitHub (webhook settings) and your config.yaml.
  • Rate limiting is 30 req/min per route by default (configurable via extra.rate_limit). Exceeding it returns 429.
  • Duplicate deliveries (webhook retries) are deduplicated via a 1-hour idempotency cache. The cache key is X-GitHub-Delivery if present, then X-Request-ID, then a random per-request ID. When neither delivery ID header is set, retries are not deduplicated.
  • Prompt injection: PR titles, descriptions, and commit messages are attacker-controlled. Malicious PRs could attempt to manipulate the agent’s actions. Run the gateway in a sandboxed environment (Docker, VM) when exposed to the public internet.

Troubleshooting

GitHub’s Recent Deliveries tab (repo → Settings → Webhooks → your webhook) shows the exact request headers, payload, HTTP status, and response body for every delivery. It is the fastest way to diagnose failures without touching your server logs.

Full config reference


What’s Next?