diff --git a/.claude/skills/document-a-feature/references/placement-guide.md b/.claude/skills/document-a-feature/references/placement-guide.md
index 4fb4d4f47d..732b653247 100644
--- a/.claude/skills/document-a-feature/references/placement-guide.md
+++ b/.claude/skills/document-a-feature/references/placement-guide.md
@@ -24,7 +24,6 @@ Top-level sections under `src/content/docs/`:
| `commands/` | GitHub comment commands (queue, dequeue, rebase, squash, backport, copy, update, refresh) |
| `ci-insights/` | CI analytics setup (GitHub Actions, Buildkite, Jenkins) |
| `test-insights/` | Test framework integrations (pytest, Jest, Go, Rust, RSpec, Cypress, …) |
-| `monorepo-ci/` | Monorepo CI guides |
| `stacks/` | Stacked PRs: concepts, setup, workflow, adoption |
| `integrations/` | Third-party integrations (GitHub, Datadog, Slack, Dependabot, Terraform, …) |
| `api/`, `cli/` | API and CLI usage + reference |
diff --git a/public/_redirects b/public/_redirects
index 7c97acf047..603c19027f 100644
--- a/public/_redirects
+++ b/public/_redirects
@@ -83,3 +83,13 @@
/test-insights/cli /cli/tests 301
/test-insights/cli/ /cli/tests 301
+
+/monorepo-ci /integrations/gha#monorepo-ci 301
+/monorepo-ci/ /integrations/gha#monorepo-ci 301
+/monorepo-ci.md /integrations/gha.md 301
+/monorepo-ci/github-actions /integrations/gha#monorepo-ci 301
+/monorepo-ci/github-actions/ /integrations/gha#monorepo-ci 301
+/monorepo-ci/github-actions.md /integrations/gha.md 301
+/monorepo-ci/buildkite /integrations/buildkite#monorepo-ci 301
+/monorepo-ci/buildkite/ /integrations/buildkite#monorepo-ci 301
+/monorepo-ci/buildkite.md /integrations/buildkite.md 301
diff --git a/src/content/docs/integrations/buildkite.mdx b/src/content/docs/integrations/buildkite.mdx
index ec4feddf52..299c325ce9 100644
--- a/src/content/docs/integrations/buildkite.mdx
+++ b/src/content/docs/integrations/buildkite.mdx
@@ -31,11 +31,233 @@ reported to GitHub can also be referenced from your Mergify
- **[CI Insights](/ci-insights/setup/buildkite)**: collect Buildkite job
metrics, detect flaky tests, and get Slack notifications for CI failures.
-- **[Monorepo CI](/monorepo-ci/buildkite)**: skip unaffected pipelines on
- pull requests to cut CI spend in monorepos.
+- **[Monorepo CI](#monorepo-ci)**: skip unaffected steps on pull requests to cut
+ CI spend in monorepos.
- **[Merge Queue Scopes](/merge-queue/scopes/others)**: run only the jobs
affected by a batch when processing the merge queue. Examples for
[Bazel](/merge-queue/scopes/bazel),
[Nx](/merge-queue/scopes/nx), and
[Turborepo](/merge-queue/scopes/turborepo) are available.
+
+## Monorepo CI
+
+Monorepo CI is [scopes](/merge-queue/scopes) applied to your pipelines. The same
+`scopes` block that lets the merge queue batch by scope also tells your pipeline
+which steps have work to do, so a pull request that only touches the frontend
+does not pay for the API and docs test suites.
+
+This section covers step skipping on pull requests. For smarter batching or
+[parallel mode](/merge-queue/queue-modes#parallel-mode) in the merge queue,
+scopes already do that on their own. See
+[Merge Queue Scopes](/merge-queue/scopes).
+
+Running GitHub Actions instead? The
+[GitHub Actions integration](/integrations/gha#monorepo-ci) covers the same
+ground. Scopes themselves are CI-agnostic, so for any other provider
+[let us know](mailto:support@mergify.com) and see
+[Merge Queue Scopes](/merge-queue/scopes/others).
+
+### Declare your scopes
+
+The plugin reads the `scopes` block of your `.mergify.yml` to know which areas
+of the repository map to each scope name:
+
+```yaml
+scopes:
+ source:
+ files:
+ frontend:
+ include:
+ - apps/web/**/*
+ api:
+ include:
+ - services/api/**/*
+ docs:
+ include:
+ - docs/**/*
+```
+
+### Pipeline outline
+
+A Buildkite pipeline driven by scopes has two parts:
+
+1. **Detect scopes** using the
+ [`mergifyio/mergify-ci`](https://github.com/Mergifyio/mergify-ci-buildkite-plugin) plugin.
+
+2. **Use a dynamic pipeline** to conditionally upload only the steps that match
+ the affected scopes.
+
+```dot class="graph"
+strict digraph {
+ fontname="sans-serif";
+ rankdir="LR";
+ nodesep=0.9;
+ ranksep=1.1;
+ splines=polyline;
+
+ node [shape=box, style="rounded,filled", fontname="sans-serif", margin="0.35,0.2", color="#165B33", fillcolor="#347D39", fontcolor="white"];
+ edge [fontname="sans-serif", color="#374151", penwidth=1.2, arrowhead=normal];
+
+ PR [label="Pull request\nchanges"];
+ Config [fillcolor="#1CB893", color="#0B7A5C", fontcolor="#063C2C", label="Scopes config\n(.mergify.yml)"];
+ Detect [fillcolor="#2563EB", color="#1E40AF", label="detect-scopes step\n(mergify-ci plugin)"];
+
+ Frontend [label="frontend-tests\n(run)"];
+ API [fillcolor="#6B7280", color="#4B5563", label="api-tests\n(skipped)"];
+ Docs [label="docs-tests\n(run)"];
+
+ PR -> Detect;
+ Config -> Detect;
+ Detect -> Frontend [label="scope: frontend"];
+ Detect -> Docs [label="scope: docs"];
+ Detect -> API [style=dashed, color="#9CA3AF", fontcolor="#9CA3AF", label="scope: api (false)"];
+}
+```
+
+### Static pipeline entry point
+
+```yaml
+# .buildkite/pipeline.yml
+steps:
+ - label: ":mag: Detect scopes"
+ key: detect-scopes
+ plugins:
+ - mergifyio/mergify-ci#@@BUILDKITE_PLUGIN_VERSION@@:
+ action: scopes
+ token: "${MERGIFY_TOKEN}"
+
+ - label: ":pipeline: Upload conditional steps"
+ depends_on: detect-scopes
+ command: .buildkite/dynamic-pipeline.sh | buildkite-agent pipeline upload
+```
+
+### Dynamic pipeline script
+
+The script below parses the scope results with
+[`jq`](https://jqlang.github.io/jq/), so install it on your Buildkite agents
+first.
+
+```bash
+#!/bin/bash
+# .buildkite/dynamic-pipeline.sh
+set -euo pipefail
+
+SCOPES=$(buildkite-agent meta-data get "mergify-ci.scopes" --default '{}')
+
+echo "steps:"
+
+if echo "$SCOPES" | jq -e '.frontend == "true"' > /dev/null 2>&1; then
+ cat <<'YAML'
+ - label: ":react: Frontend tests"
+ command: npm test
+ plugins:
+ - mergifyio/mergify-ci#@@BUILDKITE_PLUGIN_VERSION@@:
+ action: junit-process
+ report_path: "junit.xml"
+ token: "${MERGIFY_TOKEN}"
+YAML
+fi
+
+if echo "$SCOPES" | jq -e '.api == "true"' > /dev/null 2>&1; then
+ cat <<'YAML'
+ - label: ":gear: API tests"
+ command: pytest tests/api/
+ plugins:
+ - mergifyio/mergify-ci#@@BUILDKITE_PLUGIN_VERSION@@:
+ action: junit-process
+ report_path: "reports/*.xml"
+ token: "${MERGIFY_TOKEN}"
+YAML
+fi
+
+if echo "$SCOPES" | jq -e '.docs == "true"' > /dev/null 2>&1; then
+ cat <<'YAML'
+ - label: ":books: Docs build"
+ command: make docs
+YAML
+fi
+
+# Buildkite rejects a pipeline with no steps, so emit a no-op when a pull
+# request touches nothing in any scope.
+if [ "$(echo "$SCOPES" | jq '[.[] | select(. == "true")] | length')" = "0" ]; then
+ cat <<'YAML'
+ - label: ":fast_forward: No affected scopes"
+ command: "true"
+YAML
+fi
+```
+
+Make the script executable:
+
+```bash
+chmod +x .buildkite/dynamic-pipeline.sh
+```
+
+In this pipeline:
+
+- The `detect-scopes` step calls the `mergifyio/mergify-ci` plugin with the
+ `scopes` action, which inspects the pull request diff and stores a JSON map of
+ scopes (`"true"` or `"false"`) as Buildkite meta-data under the key
+ `mergify-ci.scopes`.
+
+- The dynamic pipeline script reads the scopes meta-data and only emits the
+ steps for scopes that are `"true"`, so unaffected steps are skipped entirely.
+
+- Each test step can optionally use the `junit-process` action to upload test
+ results to CI Insights.
+
+### Triggering separate pipelines
+
+If your monorepo builds live in separate Buildkite pipelines, use trigger steps
+instead:
+
+```bash
+#!/bin/bash
+# .buildkite/dynamic-pipeline.sh
+set -euo pipefail
+
+SCOPES=$(buildkite-agent meta-data get "mergify-ci.scopes" --default '{}')
+
+echo "steps:"
+
+if echo "$SCOPES" | jq -e '.frontend == "true"' > /dev/null 2>&1; then
+ cat <<'YAML'
+ - trigger: "frontend-pipeline"
+ label: ":react: Trigger frontend pipeline"
+ build:
+ branch: "${BUILDKITE_BRANCH}"
+ commit: "${BUILDKITE_COMMIT}"
+YAML
+fi
+
+if echo "$SCOPES" | jq -e '.api == "true"' > /dev/null 2>&1; then
+ cat <<'YAML'
+ - trigger: "api-pipeline"
+ label: ":gear: Trigger API pipeline"
+ build:
+ branch: "${BUILDKITE_BRANCH}"
+ commit: "${BUILDKITE_COMMIT}"
+YAML
+fi
+
+if echo "$SCOPES" | jq -e '.docs == "true"' > /dev/null 2>&1; then
+ cat <<'YAML'
+ - trigger: "docs-pipeline"
+ label: ":books: Trigger docs pipeline"
+ build:
+ branch: "${BUILDKITE_BRANCH}"
+ commit: "${BUILDKITE_COMMIT}"
+YAML
+fi
+
+if [ "$(echo "$SCOPES" | jq '[.[] | select(. == "true")] | length')" = "0" ]; then
+ cat <<'YAML'
+ - label: ":fast_forward: No affected scopes"
+ command: "true"
+YAML
+fi
+```
+
+Declare a trigger branch for every scope you define. A scope with no matching
+branch produces a pull request that silently runs no checks at all.
diff --git a/src/content/docs/integrations/gha.mdx b/src/content/docs/integrations/gha.mdx
index 19d089ca1f..a754816d90 100644
--- a/src/content/docs/integrations/gha.mdx
+++ b/src/content/docs/integrations/gha.mdx
@@ -2,7 +2,9 @@
title: Integrating GitHub Actions with Mergify
description: Run CI Insights, Monorepo CI, and Merge Queue Scopes on GitHub Actions.
---
+import { Image } from "astro:assets"
import ghaLogo from "../../images/integrations/gha/logo.png"
+import ghaSummaryScreenshot from "../../images/integrations/gha/monorepo-ci-summary.png"
import IntegrationLogo from "../../../components/IntegrationLogo.astro"
@@ -29,8 +31,8 @@ can also be referenced from your Mergify
- **[CI Insights](/ci-insights/setup/github-actions)**: collect job metrics,
detect flaky tests, and get Slack notifications for CI failures.
-- **[Monorepo CI](/monorepo-ci/github-actions)**: skip unaffected jobs on pull
- requests to cut CI spend in monorepos.
+- **[Monorepo CI](#monorepo-ci)**: skip unaffected jobs on pull requests to cut
+ CI spend in monorepos.
- **[Merge Queue Scopes](/merge-queue/scopes/others)**: run only the jobs
affected by a batch when processing the merge queue. Examples for
@@ -45,3 +47,171 @@ can also be referenced from your Mergify
To match a GitHub Actions status check with `check-success`, use the job
name only, not the workflow name.
:::
+
+## Monorepo CI
+
+Monorepo CI is [scopes](/merge-queue/scopes) applied to your workflows. The same
+`scopes` block that lets the merge queue batch by scope also tells each job
+whether it has work to do, so a pull request that only touches the frontend
+does not pay for the API and docs test suites.
+
+This section covers job skipping on pull requests. For smarter batching or
+[parallel mode](/merge-queue/queue-modes#parallel-mode) in the merge queue,
+scopes already do that on their own. See
+[Merge Queue Scopes](/merge-queue/scopes).
+
+Running Buildkite instead? The
+[Buildkite integration](/integrations/buildkite#monorepo-ci) covers the same
+ground. Scopes themselves are CI-agnostic, so for any other provider
+[let us know](mailto:support@mergify.com) and see
+[Merge Queue Scopes](/merge-queue/scopes/others).
+
+### Declare your scopes
+
+The action reads the `scopes` block of your `.mergify.yml` to know which areas
+of the repository map to each scope name:
+
+```yaml
+scopes:
+ source:
+ files:
+ frontend:
+ include:
+ - apps/web/**/*
+ api:
+ include:
+ - services/api/**/*
+ docs:
+ include:
+ - docs/**/*
+```
+
+### Workflow outline
+
+A GitHub Actions workflow driven by scopes has three parts:
+
+1. **Detect scopes** using the
+ [`gha-mergify-ci`](https://github.com/Mergifyio/gha-mergify-ci) action.
+
+2. **Reuse the scope outputs** to conditionally run jobs.
+
+3. **Publish a final status** (for example with a `ci-gate` job) if you want one
+ check that reflects all the jobs that ran.
+
+```dot class="graph"
+strict digraph {
+ fontname="sans-serif";
+ rankdir="LR";
+ nodesep=0.9;
+ ranksep=1.1;
+ splines=polyline;
+
+ node [shape=box, style="rounded,filled", fontname="sans-serif", margin="0.35,0.2", color="#165B33", fillcolor="#347D39", fontcolor="white"];
+ edge [fontname="sans-serif", color="#374151", penwidth=1.2, arrowhead=normal];
+
+ PR [label="Pull request\nchanges"];
+ Config [fillcolor="#1CB893", color="#0B7A5C", fontcolor="#063C2C", label="Scopes config\n(.mergify.yml)"];
+ Detect [fillcolor="#2563EB", color="#1E40AF", label="detect-scopes job\n(gha-mergify-ci)"];
+
+ Frontend [label="frontend-tests\n(run)"];
+ API [fillcolor="#6B7280", color="#4B5563", label="api-tests\n(skipped)"];
+ Docs [label="docs-tests\n(run)"];
+ Gate [fillcolor="#111827", color="#0B1120", label="ci-gate\n(optional)"];
+
+ PR -> Detect;
+ Config -> Detect;
+ Detect -> Frontend [label="scope: frontend"];
+ Detect -> Docs [label="scope: docs"];
+ Detect -> API [style=dashed, color="#9CA3AF", fontcolor="#9CA3AF", label="scope: api (false)"];
+ Frontend -> Gate;
+ Docs -> Gate;
+}
+```
+
+### Example workflow
+
+:::caution
+ The `scopes` action requires a pull request context. If your workflow also
+ triggers on `push` events, guard the scopes job with
+ `if: ${{ github.event_name == 'pull_request' }}` to avoid failures.
+:::
+
+```yaml
+name: Monorepo CI
+on:
+ pull_request:
+
+jobs:
+ detect-scopes:
+ runs-on: ubuntu-24.04
+ outputs:
+ frontend: ${{ fromJSON(steps.scopes.outputs.scopes).frontend }}
+ api: ${{ fromJSON(steps.scopes.outputs.scopes).api }}
+ docs: ${{ fromJSON(steps.scopes.outputs.scopes).docs }}
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Detect scopes
+ id: scopes
+ uses: Mergifyio/gha-mergify-ci@@@GHA_MERGIFY_CI_VERSION@@
+ with:
+ action: scopes
+
+ frontend-tests:
+ needs: detect-scopes
+ if: ${{ needs.detect-scopes.outputs.frontend == 'true' }}
+ uses: ./.github/workflows/frontend-tests.yaml
+ secrets: inherit
+
+ api-tests:
+ needs: detect-scopes
+ if: ${{ needs.detect-scopes.outputs.api == 'true' }}
+ uses: ./.github/workflows/api-tests.yaml
+ secrets: inherit
+
+ docs-tests:
+ needs: detect-scopes
+ if: ${{ needs.detect-scopes.outputs.docs == 'true' }}
+ uses: ./.github/workflows/docs-tests.yaml
+ secrets: inherit
+
+ ci-gate:
+ if: ${{ !cancelled() }}
+ needs:
+ - detect-scopes
+ - frontend-tests
+ - api-tests
+ - docs-tests
+ runs-on: ubuntu-24.04
+ steps:
+ - name: Report status
+ uses: Mergifyio/gha-mergify-ci@@@GHA_MERGIFY_CI_VERSION@@
+ with:
+ action: wait-jobs
+ jobs: ${{ toJSON(needs) }}
+```
+
+In this workflow:
+
+- `detect-scopes` calls `gha-mergify-ci` with the `scopes` action, which
+ inspects the pull request diff and returns a JSON map of scopes set to `true`
+ or `false`.
+
+- Each job checks the scope it cares about before running, reducing redundant
+ builds.
+
+- The final `ci-gate` job ensures that the aggregated status reflects the actual
+ CI coverage, even if some jobs were skipped. Keep `detect-scopes` in its
+ `needs`: without it, a failed scope detection skips every test job and
+ `ci-gate` still reports success.
+
+Mergify also publishes annotations that can be seen in your GitHub Actions jobs
+summary.
+
+
+
+### Protecting the branch with `ci-gate`
+
+Once `ci-gate` publishes a single status, add it as a required check in your
+GitHub branch ruleset so that only pull requests with the relevant jobs executed
+can merge.
diff --git a/src/content/docs/merge-queue/migrate-partitions-to-scopes.mdx b/src/content/docs/merge-queue/migrate-partitions-to-scopes.mdx
index 319751b80f..7f83ada856 100644
--- a/src/content/docs/merge-queue/migrate-partitions-to-scopes.mdx
+++ b/src/content/docs/merge-queue/migrate-partitions-to-scopes.mdx
@@ -170,7 +170,7 @@ jobs:
:::tip
Did you know? Scopes also work outside of the merge queue to optimize your
- CI pipelines. See the [GitHub Actions integration guide](/monorepo-ci/github-actions)
+ CI pipelines. See the [GitHub Actions integration](/integrations/gha#monorepo-ci)
for a complete setup walkthrough.
:::
diff --git a/src/content/docs/merge-queue/monorepo.mdx b/src/content/docs/merge-queue/monorepo.mdx
index 5237ee74aa..18d25d7708 100644
--- a/src/content/docs/merge-queue/monorepo.mdx
+++ b/src/content/docs/merge-queue/monorepo.mdx
@@ -47,15 +47,16 @@ With scopes, Mergify can:
build system (Nx, Bazel, Turborepo) or want to gate expensive tests on the scopes a pull request
touches.
-Need scope-aware CI without the merge queue? Explore [Monorepo CI](/monorepo-ci) for workflows that
-target GitHub Actions today.
+Need scope-aware CI without the merge queue? The [GitHub
+Actions](/integrations/gha#monorepo-ci) and [Buildkite](/integrations/buildkite#monorepo-ci)
+integrations show how to skip unaffected CI jobs with the same scopes.
### No monorepo tooling yet?
Just declare file-pattern scopes in `.mergify.yml`. Mergify evaluates them and the merge queue
batches by scope with no workflow to add, so you get scope-aware batching without introducing Nx,
-Bazel, or Turborepo first. When you also want scope-aware CI, the
-[Monorepo CI](/monorepo-ci) GitHub Actions guide ships a ready-made
+Bazel, or Turborepo first. When you also want scope-aware CI, the [GitHub Actions
+integration](/integrations/gha#monorepo-ci) ships a ready-made
[`gha-mergify-ci`](https://github.com/Mergifyio/gha-mergify-ci) workflow. As your repository grows
you can swap in more advanced tooling, and your scopes stay the same.
@@ -78,4 +79,6 @@ of how you compute them.
test and merge pull requests that touch different scopes simultaneously, reducing merge times
in monorepos.
-- [Monorepo CI](/monorepo-ci): opinionated GitHub Actions workflows if you need turnkey automation.
+- [GitHub Actions](/integrations/gha#monorepo-ci) and
+ [Buildkite](/integrations/buildkite#monorepo-ci) integrations: reuse the same scopes to skip
+ unaffected CI jobs on pull requests.
diff --git a/src/content/docs/merge-queue/scopes.mdx b/src/content/docs/merge-queue/scopes.mdx
index 897940bd81..3bc9707bc3 100644
--- a/src/content/docs/merge-queue/scopes.mdx
+++ b/src/content/docs/merge-queue/scopes.mdx
@@ -9,8 +9,9 @@ Mergify scopes describe the areas of your codebase that a pull request touches.
to pull requests, the merge queue can build smarter batches, reuse the same CI work, and avoid
mixing unrelated changes.
-Looking to use scopes outside of the merge queue? Check out [Monorepo CI](/monorepo-ci) for
-scope-driven CI workflows.
+Looking to use scopes outside of the merge queue? The same scopes can skip unaffected CI jobs on
+pull requests. See the [GitHub Actions](/integrations/gha#monorepo-ci) and
+[Buildkite](/integrations/buildkite#monorepo-ci) integrations.
Here's a quick walkthrough of how we use scopes on Mergify's own monorepo:
diff --git a/src/content/docs/merge-queue/scopes/file-patterns.mdx b/src/content/docs/merge-queue/scopes/file-patterns.mdx
index f440b61bfd..c7526b0915 100644
--- a/src/content/docs/merge-queue/scopes/file-patterns.mdx
+++ b/src/content/docs/merge-queue/scopes/file-patterns.mdx
@@ -56,8 +56,8 @@ up: declare the patterns above and the queue batches by scope.
## Conditioning CI Jobs on Scopes (Optional)
The same scopes can also drive your CI, letting you skip jobs whose scope a pull request doesn't
-touch. This is optional and independent of merge queue batching. To wire it up, follow the
-[Monorepo CI GitHub Actions guide](/monorepo-ci/github-actions). It walks through:
+touch. This is optional and independent of merge queue batching. To wire it up, follow the Monorepo
+CI section of the [GitHub Actions integration](/integrations/gha#monorepo-ci). It walks through:
- Adding the [`gha-mergify-ci`](https://github.com/Mergifyio/gha-mergify-ci)
workflow step that reads your file-pattern scopes and exposes them as outputs.
@@ -66,8 +66,10 @@ touch. This is optional and independent of merge queue batching. To wire it up,
- Waiting on the right set of jobs so required checks always report, even when work is skipped.
-That guide already includes complete workflow samples, so you do not need to duplicate the config
-here. Just reuse the same scopes you declared above.
+That section already includes complete workflow samples, so you do not need to duplicate the config
+here. Just reuse the same scopes you declared above. The
+[Buildkite integration](/integrations/buildkite#monorepo-ci) walks through the first two steps for
+Buildkite pipelines, using a dynamic pipeline instead of job conditions.
## The Merge Queue Scope
diff --git a/src/content/docs/monorepo-ci.mdx b/src/content/docs/monorepo-ci.mdx
deleted file mode 100644
index 6e4e7fdb6e..0000000000
--- a/src/content/docs/monorepo-ci.mdx
+++ /dev/null
@@ -1,116 +0,0 @@
----
-title: Monorepo CI
-description: Run the right tests for the right pull requests by combining scopes with your CI system.
----
-
-Monorepos make continuous integration expensive. Every change potentially
-touches hundreds of packages or services, and running the full test matrix for
-all of them at every pull request update quickly becomes unsustainable.
-
-Mergify Monorepo CI brings precision testing to your existing CI pipelines by
-tagging each pull request with **scopes**. Scopes are named slices of your
-repository that describe a service, package, or set of files (see
-[Merge Queue Scopes](/merge-queue/scopes) for the full specification). A scope acts as
-the contract between your codebase and your CI: if a pull request touches files
-that belong to the `frontend` scope, every workflow that cares about that scope
-knows it has work to do.
-
-With scopes in place you can:
-
-- Detect which projects or services are really impacted by a change.
-- Run only the CI jobs that matter for those scopes.
-- Reuse those scopes later in the merge queue to build smarter batches.
-
-Native support is available for GitHub Actions through our
-[`gha-mergify-ci`](https://github.com/Mergifyio/gha-mergify-ci) action and for
-Buildkite through the
-[`mergify-ci` plugin](https://github.com/Mergifyio/mergify-ci-buildkite-plugin).
-
-## How it works
-
-```dot class="graph"
-strict digraph {
- fontname="sans-serif";
- rankdir="LR";
- nodesep=0.9;
- ranksep=1.1;
- splines=polyline;
-
- node [shape=box, style="rounded,filled", fontname="sans-serif", margin="0.35,0.2", color="#165B33", fillcolor="#347D39", fontcolor="white"];
- edge [fontname="sans-serif", color="#374151", penwidth=1.2, arrowhead=normal];
-
- subgraph cluster_repo {
- label="Repository";
- style="rounded";
- color="#1CB893";
- fontcolor="#063C2C";
-
- PR [label="Pull request\nchanges"];
- ScopesConfig [fillcolor="#1CB893", fontcolor="#063C2C", color="#0B7A5C", margin="0.4,0.2", label="Scopes config\n(.mergify.yml)"];
- }
-
- Detect [fillcolor="#2563EB", color="#1E40AF", label="gha-mergify-ci\n(scopes)"];
-
- subgraph cluster_ci {
- label="GitHub Actions jobs";
- style="rounded";
- color="#1CB893";
- fontcolor="#063C2C";
-
- Frontend [label="Frontend tests"];
- API [fillcolor="#6B7280", color="#4B5563", label="API tests\n(skipped)"];
- Docs [fillcolor="#347D39", color="#165B33", label="Docs checks"];
- }
-
- Queue [fillcolor="#111827", color="#0B1120", label="Merge Queue\n(optional reuse)"];
-
- PR -> Detect;
- ScopesConfig -> Detect;
- Detect -> Frontend [label="scope: frontend"];
- Detect -> Docs [label="scope: docs"];
- Detect -> Queue [style=dashed, color="#9CA3AF", fontcolor="#9CA3AF"];
-}
-```
-
-1. **Define scopes** in your `.mergify.yml` file by mapping the areas of your repository (via file
- patterns) to scope names that matter for your CI.
-
-2. **Collect scopes in CI.** A helper such as
- [`gha-mergify-ci`](https://github.com/Mergifyio/gha-mergify-ci) inspects the
- pull request diff and dispatches only the jobs whose scopes are touched.
-
-3. **Drive your jobs conditionally.** Use the reported scopes to decide which
- workflows, test suites, or deployment steps should run for the current pull
- request.
-
-4. **(Optional) Share scopes with Merge Queue.** The very same scopes help the merge queue build
- batches that group related pull requests, reuse your CI runs, and unlock advanced strategies like
- [batch merging](/merge-queue/batches) or [two-step CI](/merge-queue/two-step).
-
-## What you can do with Monorepo CI
-
-- Gate language-specific test suites with fine-grained scope checks.
-- Trigger targeted build pipelines for individual services or packages.
-- Run nightly or specialized workflows only when relevant scopes change.
-
-## Get started
-
-Define your scopes first so every workflow speaks the same language:
-
-1. List the services, packages, or domains that deserve their own scope.
-
-2. Map each scope to file patterns inside the
- [`scopes`](/merge-queue/scopes#configuration) block of your `.mergify.yml`
- file.
-
-3. Commit the configuration and open a pull request to verify that the reported
- scopes match your expectations.
-
-Once those scopes exist, pick the workflow that matches your setup:
-
-- [Scope configuration reference](/merge-queue/scopes)
-- [GitHub Actions setup](/monorepo-ci/github-actions)
-- [Buildkite setup](/monorepo-ci/buildkite)
-- [Merge queue monorepo overview](/merge-queue/monorepo)
-
-Looking for a different CI provider? [Let us know](mailto:support@mergify.com); more platforms are on our roadmap.
diff --git a/src/content/docs/monorepo-ci/buildkite.mdx b/src/content/docs/monorepo-ci/buildkite.mdx
deleted file mode 100644
index b58eb251ae..0000000000
--- a/src/content/docs/monorepo-ci/buildkite.mdx
+++ /dev/null
@@ -1,191 +0,0 @@
----
-title: Monorepo CI with Buildkite
-description: Use the Mergify CI Buildkite plugin to run only the pipelines impacted by a pull request.
----
-
-Mergify's Buildkite integration makes scopes actionable in your CI. This
-guide shows how to wire scopes into your pipelines so that each pull request
-runs only the jobs it truly needs.
-
-## Prerequisites
-
-Before you start, make sure you have:
-
-- [`jq`](https://jqlang.github.io/jq/) installed on your Buildkite agents (used
- by the dynamic pipeline script to parse scope results)
-
-- Scopes declared in your `.mergify.yml` so the plugin knows which areas of the
- repo map to each scope name:
-
-```yaml
-scopes:
- source:
- files:
- frontend:
- include:
- - apps/web/**/*
- api:
- include:
- - services/api/**/*
- docs:
- include:
- - docs/**/*
-```
-
-## Pipeline outline
-
-A typical Buildkite pipeline with scopes consists of two parts:
-
-1. **Detect scopes** using the
- [`mergifyio/mergify-ci`](https://github.com/Mergifyio/mergify-ci-buildkite-plugin) plugin.
-
-2. **Use a dynamic pipeline** to conditionally upload only the steps that match
- the affected scopes.
-
-```dot class="graph"
-strict digraph {
- fontname="sans-serif";
- rankdir="LR";
- nodesep=0.9;
- ranksep=1.1;
- splines=polyline;
-
- node [shape=box, style="rounded,filled", fontname="sans-serif", margin="0.35,0.2", color="#165B33", fillcolor="#347D39", fontcolor="white"];
- edge [fontname="sans-serif", color="#374151", penwidth=1.2, arrowhead=normal];
-
- PR [label="Pull request\nchanges"];
- Config [fillcolor="#1CB893", color="#0B7A5C", fontcolor="#063C2C", label="Scopes config\n(.mergify.yml)"];
- Detect [fillcolor="#2563EB", color="#1E40AF", label="detect-scopes step\n(mergify-ci plugin)"];
-
- Frontend [label="frontend-tests\n(run)"];
- API [fillcolor="#6B7280", color="#4B5563", label="api-tests\n(skipped)"];
- Docs [label="docs-tests\n(run)"];
-
- PR -> Detect;
- Config -> Detect;
- Detect -> Frontend [label="scope: frontend"];
- Detect -> Docs [label="scope: docs"];
- Detect -> API [style=dashed, color="#9CA3AF", fontcolor="#9CA3AF", label="scope: api (false)"];
-}
-```
-
-## Example pipeline
-
-### Static pipeline entry point
-
-```yaml
-# .buildkite/pipeline.yml
-steps:
- - label: ":mag: Detect scopes"
- key: detect-scopes
- plugins:
- - mergifyio/mergify-ci#@@BUILDKITE_PLUGIN_VERSION@@:
- action: scopes
- token: "${MERGIFY_TOKEN}"
-
- - label: ":pipeline: Upload conditional steps"
- depends_on: detect-scopes
- command: .buildkite/dynamic-pipeline.sh | buildkite-agent pipeline upload
-```
-
-### Dynamic pipeline script
-
-```bash
-#!/bin/bash
-# .buildkite/dynamic-pipeline.sh
-set -euo pipefail
-
-SCOPES=$(buildkite-agent meta-data get "mergify-ci.scopes")
-
-echo "steps:"
-
-if echo "$SCOPES" | jq -e '.frontend == "true"' > /dev/null 2>&1; then
- cat <<'YAML'
- - label: ":react: Frontend tests"
- command: npm test
- plugins:
- - mergifyio/mergify-ci#@@BUILDKITE_PLUGIN_VERSION@@:
- action: junit-process
- report_path: "junit.xml"
- token: "${MERGIFY_TOKEN}"
-YAML
-fi
-
-if echo "$SCOPES" | jq -e '.api == "true"' > /dev/null 2>&1; then
- cat <<'YAML'
- - label: ":gear: API tests"
- command: pytest tests/api/
- plugins:
- - mergifyio/mergify-ci#@@BUILDKITE_PLUGIN_VERSION@@:
- action: junit-process
- report_path: "reports/*.xml"
- token: "${MERGIFY_TOKEN}"
-YAML
-fi
-
-if echo "$SCOPES" | jq -e '.docs == "true"' > /dev/null 2>&1; then
- cat <<'YAML'
- - label: ":books: Docs build"
- command: make docs
-YAML
-fi
-```
-
-Make the script executable:
-
-```bash
-chmod +x .buildkite/dynamic-pipeline.sh
-```
-
-### How it works
-
-- The `detect-scopes` step calls the Mergify CI plugin with the `scopes`
- action, which inspects the pull request diff and stores a JSON map of scopes
- (`"true"` or `"false"`) as Buildkite meta-data under the key
- `mergify-ci.scopes`.
-
-- The dynamic pipeline script reads the scopes meta-data and only emits the
- steps for scopes that are `"true"`, so unaffected jobs are skipped entirely.
-
-- Each test step can optionally use the `junit-process` action to upload test
- results to CI Insights.
-
-## Alternative: trigger pipelines
-
-If your monorepo jobs live in separate Buildkite pipelines, you can use
-`buildkite-agent pipeline upload` with trigger steps instead:
-
-```bash
-#!/bin/bash
-# .buildkite/dynamic-pipeline.sh
-set -euo pipefail
-
-SCOPES=$(buildkite-agent meta-data get "mergify-ci.scopes")
-
-echo "steps:"
-
-if echo "$SCOPES" | jq -e '.frontend == "true"' > /dev/null 2>&1; then
- cat <<'YAML'
- - trigger: "frontend-pipeline"
- label: ":react: Trigger frontend pipeline"
- build:
- branch: "${BUILDKITE_BRANCH}"
- commit: "${BUILDKITE_COMMIT}"
-YAML
-fi
-
-if echo "$SCOPES" | jq -e '.api == "true"' > /dev/null 2>&1; then
- cat <<'YAML'
- - trigger: "api-pipeline"
- label: ":gear: Trigger API pipeline"
- build:
- branch: "${BUILDKITE_BRANCH}"
- commit: "${BUILDKITE_COMMIT}"
-YAML
-fi
-```
-
-## Merge Queue integration
-
-To reuse the same scopes for merge queue batching, see [Merge Queue
-Scopes](/merge-queue/scopes).
diff --git a/src/content/docs/monorepo-ci/github-actions.mdx b/src/content/docs/monorepo-ci/github-actions.mdx
deleted file mode 100644
index 6f5b673a37..0000000000
--- a/src/content/docs/monorepo-ci/github-actions.mdx
+++ /dev/null
@@ -1,156 +0,0 @@
----
-title: Monorepo CI with GitHub Actions
-description: Use `gha-mergify-ci` to run only the workflows impacted by a pull request.
----
-
-import { Image } from "astro:assets"
-import ghaSummaryScreenshot from "../../images/monorepo-ci/github-actions/summary.png"
-
-Mergify's GitHub Actions integration makes scopes actionable in your CI. This
-guide shows how to wire scopes into your workflows so that each pull request
-runs only the jobs it truly needs.
-
-## Prerequisites
-
-Before you start, declare scopes in your `.mergify.yml` so the action knows
-which areas of the repo map to each scope name:
-
-```yaml
-scopes:
- source:
- files:
- frontend:
- include:
- - apps/web/**/*
- api:
- include:
- - services/api/**/*
- docs:
- include:
- - docs/**/*
-```
-
-## Workflow outline
-
-A typical GitHub Actions pipeline with scopes consists of three parts:
-
-1. **Detect scopes** using the
- [`gha-mergify-ci`](https://github.com/Mergifyio/gha-mergify-ci) action.
-
-2. **Reuse the scope outputs** to conditionally run jobs.
-
-3. **Publish a final status** (for example with a `ci-gate` job) if you want one
- check that reflects all the jobs that ran.
-
-```dot class="graph"
-strict digraph {
- fontname="sans-serif";
- rankdir="LR";
- nodesep=0.9;
- ranksep=1.1;
- splines=polyline;
-
- node [shape=box, style="rounded,filled", fontname="sans-serif", margin="0.35,0.2", color="#165B33", fillcolor="#347D39", fontcolor="white"];
- edge [fontname="sans-serif", color="#374151", penwidth=1.2, arrowhead=normal];
-
- PR [label="Pull request\nchanges"];
- Config [fillcolor="#1CB893", color="#0B7A5C", fontcolor="#063C2C", label="Scopes config\n(.mergify.yml)"];
- Detect [fillcolor="#2563EB", color="#1E40AF", label="detect-scopes job\n(gha-mergify-ci)"];
-
- Frontend [label="frontend-tests\n(run)"];
- API [fillcolor="#6B7280", color="#4B5563", label="api-tests\n(skipped)"];
- Docs [label="docs-tests\n(run)"];
- Gate [fillcolor="#111827", color="#0B1120", label="ci-gate\n(optional)"];
-
- PR -> Detect;
- Config -> Detect;
- Detect -> Frontend [label="scope: frontend"];
- Detect -> Docs [label="scope: docs"];
- Detect -> API [style=dashed, color="#9CA3AF", fontcolor="#9CA3AF", label="scope: api (false)"];
- Frontend -> Gate;
- Docs -> Gate;
-}
-```
-
-## Example workflow
-```yaml
-name: Monorepo CI
-on:
- pull_request:
-
-jobs:
- detect-scopes:
- runs-on: ubuntu-24.04
- outputs:
- frontend: ${{ fromJSON(steps.scopes.outputs.scopes).frontend }}
- api: ${{ fromJSON(steps.scopes.outputs.scopes).api }}
- docs: ${{ fromJSON(steps.scopes.outputs.scopes).docs }}
- steps:
- - uses: actions/checkout@v5
-
- - name: Detect scopes
- id: scopes
- uses: Mergifyio/gha-mergify-ci@@@GHA_MERGIFY_CI_VERSION@@
- with:
- action: scopes
-
- frontend-tests:
- needs: detect-scopes
- if: ${{ needs.detect-scopes.outputs.frontend == 'true' }}
- uses: ./.github/workflows/frontend-tests.yaml
- secrets: inherit
-
- api-tests:
- needs: detect-scopes
- if: ${{ needs.detect-scopes.outputs.api == 'true' }}
- uses: ./.github/workflows/api-tests.yaml
- secrets: inherit
-
- docs-tests:
- needs: detect-scopes
- if: ${{ needs.detect-scopes.outputs.docs == 'true' }}
- uses: ./.github/workflows/docs-tests.yaml
- secrets: inherit
-
- ci-gate:
- if: ${{ !cancelled() }}
- needs:
- - frontend-tests
- - api-tests
- - docs-tests
- runs-on: ubuntu-24.04
- steps:
- - name: Report status
- uses: Mergifyio/gha-mergify-ci@@@GHA_MERGIFY_CI_VERSION@@
- with:
- action: wait-jobs
- jobs: ${{ toJSON(needs) }}
-```
-
-### How it works
-
-- `detect-scopes` calls `gha-mergify-ci` with the `scopes` action, which
- inspects the pull request diff and returns a JSON map of scopes set to `true`
- or `false`.
-
-- Each job checks the scope it cares about before running, reducing
- redundant builds.
-
-- The final `ci-gate` job ensures that the aggregated status reflects the actual
- CI coverage, even if some jobs were skipped.
-
-Mergify also publishes annotations that can be seen in your GitHub Actions jobs
-summary.
-
-
-
-## Protecting the branch with `ci-gate`
-
-Once `ci-gate` publishes a single status, add it as a required check in your
-GitHub branch ruleset so that only pull requests with the relevant jobs executed
-can merge.
-
-## Merge Queue integration
-
-Ready to reuse the same scopes for batching? Head over to [Merge Queue
-Scopes](/merge-queue/scopes) to see how they power smarter batches.
diff --git a/src/content/images/monorepo-ci/github-actions/summary.png b/src/content/images/integrations/gha/monorepo-ci-summary.png
similarity index 100%
rename from src/content/images/monorepo-ci/github-actions/summary.png
rename to src/content/images/integrations/gha/monorepo-ci-summary.png
diff --git a/src/content/navItems.tsx b/src/content/navItems.tsx
index e2eaba2c0a..9d787ffb3b 100644
--- a/src/content/navItems.tsx
+++ b/src/content/navItems.tsx
@@ -286,24 +286,6 @@ const navItems: NavItem[] = [
},
],
},
- {
- title: 'Monorepo CI',
- path: '/monorepo-ci',
- icon: 'lucide:network',
- children: [
- { title: 'Overview', path: '/monorepo-ci', icon: 'lucide:network' },
- {
- title: 'GitHub Actions',
- path: '/monorepo-ci/github-actions',
- icon: 'simple-icons:githubactions',
- },
- {
- title: 'Buildkite',
- path: '/monorepo-ci/buildkite',
- icon: 'simple-icons:buildkite',
- },
- ],
- },
{
title: 'Rule Engine',
icon: 'lucide:book',