Checklist
How to migrate CI without breaking your verdict
Moving CI should change how long you wait, never whether a change passes. This checklist moves pipelines one at a time, proves the new CI gives the same pass/fail verdicts on the same commits, and keeps a way back until you no longer need it.
Inventory what you have
You cannot prove nothing changed if you never wrote down what there was.
- List every workflow or pipeline, what triggers it (push, pull request, schedule, manual, tags) and which branches.
- Write down the exact names of required checks in branch protection or rulesets. A renamed job silently stops blocking merges, or blocks every merge forever.
- List secrets, environment variables, environments with approvals, and any cloud roles that trust your CI’s OIDC tokens.
- Note self-hosted runners, service containers, artifacts passed between jobs, caches, and anything that deploys.
- Record your baseline: p50 and p90 push-to-verdict, failure rate, flaky tests you already know about, and minutes billed, over a fixed window. How to measure it.
Decide how much has to move
The safest migration is the smallest one that solves your problem.
- If the problem is waiting time and you are on GitHub Actions, you may not need a platform move at all: a runner layer such as Graphide CI, Blacksmith or Depot changes only
runs-on. - If the problem is where builds may run (your own machines, your own cloud, a single-tenant platform), you are moving platforms: see the picks for self-hosted needs.
- Move one repository first, ideally one with a good test suite and a team willing to report problems.
- If the problem is waiting time and you are on GitHub Actions, you may not need a platform move at all: a runner layer such as Graphide CI, Blacksmith or Depot changes only
Translate pipelines one at a time
Keep the shape of the old pipeline so results can be compared job by job.
- Use an importer where one exists: GitHub Actions Importer (
gh actions-importer) audits and converts pipelines from Jenkins, CircleCI, GitLab and others into workflows. Treat its output as a draft and review every step. - Keep job and check names identical to the old ones wherever the new tool allows it.
- Pin tool and runtime versions (Node, Python, Go, JDK, container images) to what the old CI used, so the only change is the CI.
- Recreate secrets by hand in the new tool; never print them to logs to check them. Update OIDC trust policies for the new issuer.
- Leave deploy jobs on the old CI until the test pipelines have been cut over and stable.
- Use an importer where one exists: GitHub Actions Importer (
Shadow-run on the same commits
Run old and new side by side, with the old one still in charge.
- Trigger the new pipeline on the same pushes and pull requests as the old one. The old one stays the required check.
- Make the new one non-blocking, and keep it from deploying or publishing anything.
- Run for a fixed window: long enough to cover your normal mix of changes, including dependency bumps and config changes.
Compare verdicts before cutover
Speed is the reason to move; the verdict is the reason not to.
- For every commit in the window, record the old verdict and the new verdict, per required check. Count agreements and disagreements.
- Sort every disagreement into one of three causes: a flaky test (it disagrees with itself on a re-run), an environment difference (versions, time zones, network, file system), or a real miss (the new CI passed something the old one failed).
- Fix environment differences and re-run. Any real miss stops the migration until it is understood and fixed.
- Compare p50 and p90 push-to-verdict and minutes billed against your baseline, on the same commits.
- Agree the bar before you look: for example, “no unexplained disagreements and p90 no worse than today”. Decide in advance, not after seeing the numbers.
Cut over
Change what blocks merges in one deliberate step.
- Announce a time. Freeze changes to CI config for the cutover window.
- Make the new checks required in branch protection or rulesets, then make the old ones optional (not deleted).
- Move deploy jobs last, with a manual approval on the first few deploys from the new CI.
- Watch queue time, failure rate and re-run rate daily for the first two weeks.
Keep a rollback ready
A migration you cannot undo in minutes is a bet, not a migration.
- Keep the old configuration in the repository and runnable until the decommission date.
- Make rollback one action: reverting a pull request, or switching required checks back.
- Write down what triggers it: a real miss, an outage of the new CI, or queue times above an agreed limit. Whoever is on call can pull it without a meeting.
- Practise it once during the shadow period, so you know it works and how long it takes.
Decommission the old CI
Only after a full period with no rollback.
- Remove old pipeline files, runners, webhooks and integrations; revoke the old CI’s tokens and cloud trust.
- Export any build history or audit logs you are required to keep before cancelling.
- Write down the before-and-after numbers with their window and scope, so the next person can check them.
Moving GitHub Actions jobs to Graphide CI
Graphide CI is the smallest move on this site: it is a runner layer for your existing GitHub Actions jobs, so steps 3 and most of 1 shrink to almost nothing. What it involves, from Graphide’s docs:
- Before: your repository must belong to a GitHub organization (not a personal account) and its jobs must be x64 Linux. macOS, Windows, Arm and self-hosted jobs stay where they run today. Graphide checks that its run catches every failure your own run catches before your jobs move.
- The move: Graphide opens one pull request that changes each eligible job’s
runs-online tographide, and nothing else. Job names, steps and required checks stay the same, so branch protection does not change. A coding agent can do it through Graphide’s MCP server, asking you before it switches anything. - The verdict: a failing test always fails the job, and GitHub still decides pass or fail from the job’s own steps.
- Rollback: from the repository’s CI settings, Switch back to GitHub Actions opens a pull request that restores each
runs-onas it was; reverting the original pull request on GitHub works too. - Measure it: compare p50 and p90 push-to-verdict and verdict agreement on the same commits against your baseline, as in measuring against the baseline.