WorkflowsMCP

GitHub PR review pipeline

PR opened → the right reviewers pinged in Slack → status mirrored on the Linear issue.

@workflowsmcpMar 11, 2026Verified Aug 2026code-reviewengineeringnotificationsdeveloper-workflow

Review latency is mostly a routing problem: the PR is open, but the person who should look at it does not know. GitHub already resolves CODEOWNERS and requests those reviewers itself, so this workflow reads the reviewer set straight off the webhook payload, pings exactly those people in Slack with the diff size, and keeps the linked Linear issue in step as the PR moves from open to approved to merged.

How it flows

  1. 01

    PR opened (non-draft)

    Webhook fires with action "opened" or "ready_for_review".

  2. 02

    GitHub requests the code owners itself

    requested_reviewers and requested_teams arrive on the payload; a late review_requested event fills in what "opened" missed.

  3. 03

    Reviewers pinged in Slack

    One message with diff size and direct mentions, in #pr-review.

  4. 04

    Linked issue moves to In Review

    Matched from the branch name; the per-team review-requested automation moves it.

  5. 05

    Approval updates the same Slack message

    chat.update against the stored ts rather than a new post, so the channel stays one line per PR.

  6. 06

    Merge closes the loop

    Issue moves to Done; the Slack message gets a checkmark and stops nagging.

Set up each app

Work through these in order — later apps usually need a token or an id from an earlier one.

GitHub

Emits the PR events and owns reviewer routing

  1. 01

    Add the repository webhook

    Repo → Settings → Webhooks → Add webhook. Content type application/json, set a secret, then "Let me select individual events" → Pull requests, Pull request reviews, Pull request review comments. Do not pick "Send me everything" — that is every event type in the product, most of which you will parse only to drop.

  2. 02

    Handle the payload shape

    One event type covers many actions; branch on action first and ignore drafts. The fields you need are all top-level on pull_request — including the reviewer set, which GitHub has already filled in from CODEOWNERS. Read both requested_reviewers (people) and requested_teams (teams), and handle action "review_requested" as well as "opened": the auto-request can land a beat after the PR is created, leaving the first payload with two empty arrays.

    pull_request webhook payload (trimmed)
    {
      "action": "opened",
      "number": 482,
      "pull_request": {
        "html_url": "https://github.com/acme/web/pull/482",
        "title": "Cache invalidation for the pricing page",
        "draft": false,
        "user": { "login": "dana-w" },
        "requested_reviewers": [{ "login": "sam-k" }],
        "requested_teams": [{ "slug": "backend", "name": "Backend" }],
        "additions": 214,
        "deletions": 38,
        "changed_files": 9,
        "head": { "ref": "dana/ENG-412-pricing-cache" }
      },
      "repository": { "full_name": "acme/web" }
    }
  3. 03

    Let CODEOWNERS decide the reviewers

    Commit .github/CODEOWNERS so routing lives in the repo instead of your automation config. Last matching rule wins, so order matters. GitHub evaluates this file itself and requests the owners the moment a PR opens — do not re-match paths in your code, just read who it asked for. Two caveats that make rules disappear silently: a team must have explicit write access to the repo or its line is ignored, and code owners are not auto-requested on draft PRs.

    .github/CODEOWNERS
    *                       @acme/eng-leads
    /src/app/               @acme/frontend
    /src/lib/db/            @acme/backend @dana-w
    /infra/                 @acme/platform
    /.github/workflows/     @acme/platform
  4. 04

    Require the review you just routed

    Settings → Rules → Rulesets → New ruleset → New branch ruleset → Require a pull request before merging, then tick "Require review from Code Owners" under Additional settings. (Settings → Branches is the older branch-protection UI and does not have rulesets.) Without this the ping is advisory and will be ignored under deadline.

Slack

Where reviewers actually get pinged

  1. 01

    Create #pr-review and invite the app

    Keep it one channel per repo group, not per repo — a channel nobody has muted is worth more than a tidy taxonomy.

  2. 02

    Map GitHub logins to Slack member ids

    A literal @dana-w in Slack text is plain text, not a mention. Maintain a small map and emit <@U…> so the ping registers. Person keys are GitHub logins from requested_reviewers; team keys are the repository owner plus the requested_teams slug (repository.full_name "acme/web" + slug "backend" → "acme/backend"), and they resolve to <!subteam^S…> user-group ids.

    reviewer-map.json
    {
      "dana-w": "U02DANA",
      "sam-k":  "U03SAMK",
      "rae-m":  "U04RAEM",
      "acme/frontend": "S05FRONTEND",
      "acme/backend":  "S06BACKEND"
    }
  3. 03

    Post the review request

    Include diff size — reviewers triage by cost. Then update the same message with chat.update on approval instead of posting a second one. chat.update requires the ts of the original message, which only exists in the chat.postMessage response, so persist it keyed by PR number the moment you post; lose it and the only option left is a second message.

    chat.postMessage body
    {
      "channel": "C07PRREVIEW",
      "text": "Review requested: acme/web#482",
      "blocks": [
        { "type": "section",
          "text": { "type": "mrkdwn",
            "text": "*<https://github.com/acme/web/pull/482|#482 Cache invalidation for the pricing page>*\nby <@U02DANA> · +214 −38 across 9 files" } },
        { "type": "context",
          "elements": [{ "type": "mrkdwn", "text": "Code owners: <@U03SAMK> · <!subteam^S06BACKEND>" }] }
      ]
    }

Linear

Mirrors PR status onto the issue

  1. 01

    Enable the GitHub integration

    Linear → Settings → Features → Integrations → GitHub → Enable, then authorise the org and select the repos. This page only establishes the link; it carries no status-transition toggles.

  2. 02

    Adopt the branch naming convention

    Linear links a PR to an issue by branch name or by a magic word in the PR body. Copy the branch name from the issue (Linear offers it on the issue page) and the link is automatic.

    What Linear will match
    dana/ENG-412-pricing-cache       # branch name — preferred
    "Fixes ENG-412"                  # in the PR title or body
    "Part of ENG-412"                # links without closing
  3. 03

    Turn the PR automations on per team

    The status transitions do not live on the integration page — they are at Settings → Team → Workflows & automations → Pull request and commit automations, and they are a per-team setting. Repeat it for every team whose issues should move with a PR, or half your board will look broken.

  4. 04

    Choose the transitions deliberately

    Drive In Review from the "review requested" trigger rather than "PR opened" — the defaults move an issue to In Progress on open and Done on merge, and review-requested is the moment the work actually changes hands. There is no PR-closed-unmerged trigger at all, so an abandoned branch simply leaves the issue where it is, which is what you want: bouncing an issue back to Todo on every dead branch trains people to ignore the board.