Switch Brief: moving CI off GitHub Actions (sample)
Back to the service. This is a worked sample on an invented brief, produced by running the Switch Brief playbook with live fetches on 2026-10-12. Your order gets the same structure for your tool and your must-haves.
Prepared 2026-10-12. AI-written from public pages fetched on 2026-10-12. Research, not security, legal or compliance advice. This is a worked sample on an invented brief, modelled on a real Ask HN question (https://news.ycombinator.com/item?id=47264080).
Sample brief. Six-person team, 25 private repositories on GitHub, GitHub Actions for lint, tests and Docker builds, about 3,500 Linux minutes a month on GitHub Team, a few scheduled jobs. Must-haves: (R1) scheduled and push-triggered CI should keep working when GitHub is having an outage; (R2) all-in cost at most $100 a month on top of what is already paid; (R3) runners we control; (R4) no more than about one working day of pipeline rewriting per ten repositories.
The answer first
- R1 cannot be met by changing the CI tool alone. Every tool that keeps the repositories on GitHub still has to clone code and receive push events from GitHub. Woodpecker documents GitHub as a forge using an OAuth app [4]. Only moving the repositories to another forge removes the dependency. That is the "big migration" the original poster hoped to avoid, so the honest choice is: accept R1 partly, or move the repositories.
- The price pressure behind many such questions is currently gone. GitHub's billing page, read today, says "GitHub Actions usage is free for self-hosted runners" [1], and The Register reported on 2025-12-17 that GitHub was "postponing the announced billing change for self-hosted GitHub Actions" [2]. Postponed is not cancelled, so this can change. Staying put is a real option, not a strawman.
- Three hosted routes fail a six-person team on size, and two on budget. Buildkite Free is "Up to 5 users" [10], CircleCI Free has "5 active users" [11], and GitLab.com Free allows "5 users per top-level group" [8]; GitLab's docs say private namespaces with more than five users "are placed in a read-only state" [14]. On budget, GitLab.com Premium for six is 6 × $29 = $174 a month [8] and Buildkite Pro is 6 × $30 = $180 [10].
- Two routes pass R1 to R3: Forgejo with its Actions runner, and self-managed GitLab on the Free tier. GitLab's pricing FAQ says the 5-user limit does not apply to "the Free tier of the self-managed offering" [8]. Suggested path: keep Actions now with self-hosted runners for the heavy builds, and run a two-week trial of Forgejo on two low-risk repos. We pick Forgejo over self-managed GitLab on R4 only, as a judgement: Forgejo falls back to reading
.github/workflows[7], while GitLab needs a rewrite to.gitlab-ci.yml[9]. Self-managed GitLab was not trialled or costed beyond what is listed below.
Your requirements as tests
| ID | Test (pass means) | Basis |
|---|---|---|
| R1 | CI runs and triggers without GitHub being up | needs the repos hosted off GitHub |
| R2 | Total added cost ≤ $100/month at 6 users, about 3,500 Linux minutes | prices below |
| R3 | You can run the runner on your own machine | vendor docs |
| R4 | Workflow files translate with limited rewriting | vendor migration docs |
Knockout matrix (read 2026-10-12)
Each cell is PASS, FAIL, PARTIAL or UNKNOWN with the source number it rests on. "By inference" means the verdict is our reasoning from the cited page, not a sentence on that page. The Result column is derived from the four cells.
| Candidate | R1 | R2 | R3 | R4 | Result |
|---|---|---|---|---|---|
| Stay: GitHub Actions + self-hosted runners | FAIL by inference: needs GitHub [1] | PASS: self-hosted usage "free" [1] | PASS [1] | PASS by inference: no change to workflows [1] | stays viable, fails R1 |
| Woodpecker CI on the GitHub forge | FAIL by inference: GitHub forge via OAuth app [4] | PASS by inference: open source, no per-user price; hosting cost unknown [5] | PASS by inference: self-hosted project [5] | UNKNOWN: own pipeline syntax, rewrite effort not measured [6] | fails R1 |
| Forgejo with Forgejo Actions (repos move) | PASS by inference: self-hosted forge, repos off GitHub [7] | PASS by inference: GPL software, no per-user price on the pages read; server cost is yours [16] | PASS [7] | PARTIAL: "not designed to be compatible", minor changes likely [7] | passes R1 to R3, R4 uncertain |
| GitLab self-managed, Free tier (repos move) | PASS by inference: self-hosted, repos off GitHub [8] | PASS: 5-user limit does not apply to self-managed Free [8]; server cost is yours | PASS: own runners "unlimited" [8] | PARTIAL: importer plus rewrite to .gitlab-ci.yml [9] | passes R1 to R3, R4 partial |
| GitLab.com Free (repos move) | PASS by inference: repos on GitLab, not GitHub [8] | FAIL: "5 users per top-level group" [8]; over five users the namespace is read-only [14] | PASS: own runners "unlimited" [8] | PARTIAL: importer plus rewrite [9] | fails R2 at six users |
| GitLab.com Premium (repos move) | PASS by inference: repos on GitLab, not GitHub [8] | FAIL: 6 × $29 = $174 [8] | PASS [8] | PARTIAL: importer plus rewrite [9] | fails R2 |
| Buildkite | FAIL by inference: code stays on GitHub; not tested [10] | FAIL: Free "Up to 5 users"; Pro 6 × $30 = $180 [10] | PASS: self-hosted agents listed [10] | UNKNOWN: no migration page read [10] | fails R2 |
| CircleCI | FAIL by inference: code stays on GitHub; not tested [11] | FAIL on Free ("5 active users"); Performance $15 + 1 extra user $15 = $30 plus credits, UNKNOWN in total [11] | PASS: self-hosted runner, no per-minute charge [11] | UNKNOWN: no migration page read [11] | fails Free; paid total unknown |
Candidate notes
- Forgejo. Forgejo says Actions "is not designed to be compatible" with GitHub Actions; it falls back to reading
.github/workflowswhen.forgejo/workflowsdoes not exist [7]. Which GitHub actions work unchanged was not established. - Woodpecker. Supports GitHub, Gitea, Forgejo, GitLab and Bitbucket as forges [4]. Cron jobs are configured in repository settings, with steps carrying
event: cron[6]. - GitLab. The docs recommend the GitHub Importer for bulk moves and then adding a
.gitlab-ci.ymlper project [9]. Self-managed and GitLab.com are separate rows because the Free-tier user limit differs [8][14]. Whether GitLab CI can run against a repo that stays on GitHub was not answered by the page read.
Licence and latest release (read 2026-10-12)
| Candidate | Licence | Latest release and date | Sources |
|---|---|---|---|
| Forgejo | GPL version 3 or any later version (README: "distributed under the terms of the GPL version 3.0 or any later version"; MIT before v9.0) | v16.0.5, 2026-09-17; forgejo.org lists the same | [16] licence; [12] and [15] release |
| Woodpecker | Apache-2.0 (LICENSE text) | v3.19.0, 2026-10-07; Docker Hub tag v3.19.0 pushed the same day | [5] licence; [13] and [21] release |
| GitLab self-managed | MIT Expat for most of the repository; content under ee/ has its own licence. Which licence covers the install you would use on the Free tier was not established | 19.4.1, 2026-09-23 (GitLab patch release feed and Docker Hub agree) | [20] licence; [18] and [19] release |
| GitHub Actions, GitLab.com, Buildkite, CircleCI | N/A (hosted SaaS; no software release to date) | N/A | [1][8][10][11] |
Cost at your scale
Billing periods as listed on each page; US dollars; per month; hosting and your time excluded.
- Stay put: 3,500 − 3,000 included Team minutes = 500 minutes × $0.006 (Linux 2-core x64) = $3.00/month if all builds ran on hosted runners; less with self-hosted runners [1].
- GitLab.com Premium: 6 × $29 = $174/month (billed annually) [8].
- GitLab.com Free: $0, but six users exceed the 5-user limit, so private repos would be read-only [8][14].
- Buildkite Pro: 6 × $30 = $180/month [10].
- CircleCI Performance: $15 includes 5 active users, +$15 for the sixth = $30/month plus credits beyond 30,000 [11]. Converting 3,500 GitHub minutes to credits needs the resource class, so the total is UNKNOWN.
- Forgejo, self-managed GitLab Free or Woodpecker: no licence fee found [8][16][5]; the cost is the server and your time (not priced here).
Switching effort (effort estimates are judgement, not facts)
- Stay + self-hosted runners: small. Runner install, labels, no YAML change.
- Forgejo move: large, once. Repos, issues, pull requests, secrets and webhooks move; workflows need review. Plan one repo first.
- Self-managed GitLab move: large. Importer helps [9]; pipelines rewritten.
- Woodpecker on GitHub: medium. New pipeline files in a different syntax per repo; does not address R1.
- How you would leave Forgejo (exit path). Repositories are plain Git, so they can be cloned or pushed to any other host. Forgejo's command-line docs list a
dumpcommand ("Dump Forgejo files and database") anddump-repo/restore-repocommands [17]. Whether issues and pull requests can be restored into a non-Forgejo tool was not established, so that part is UNKNOWN. Effort to leave: M (judgement).
Two-week trial plan (Forgejo)
- Day 1: install Forgejo and one runner on a spare machine; import two low-risk repos with the importer or mirror. Pass: both repos clone and open.
- Days 2 to 5: port each workflow; record minutes spent and the actions that did not work. Pass: all steps green with at most 4 hours of edits in total.
- Days 6 to 10: run the scheduled jobs and a real week of pushes. Pass: zero missed scheduled runs.
- Day 11: turn off outbound access to github.com on the test host and push. Pass: pipelines still run (this is R1).
- Day 12: run
forgejo dumpon the test instance, then bring up a second instance from the dump and, separately, push both repos to a plain Git host. Pass: both repos clone from each (this tests the exit path). - Day 14: decide. If the pass criteria fail, stay on Actions with self-hosted runners, or repeat steps 1 to 4 on self-managed GitLab.
What we could not establish
- Whether any listed CI tool can run with the code staying on GitHub while GitHub is down (our reading: no, from the OAuth-forge design [4]; not tested).
- Which GitHub actions run unchanged on Forgejo; whether issues and pull requests can leave Forgejo for a non-Forgejo tool.
- Which licence covers a self-managed GitLab install on the Free tier.
- Whether Buildkite and CircleCI can be driven by anything but GitHub webhooks for your repos; migration effort for both.
- CircleCI credits for your build mix; hosting costs for any self-hosted option; Codeberg's terms for private repositories (not read).
- The GitHub Team plan price (not needed: already paid).
- api.github.com was unreachable from the research environment, so release dates were read from Codeberg, forgejo.org, GitLab's feeds, Docker Hub and the Go module proxy instead.
Sources (fetched 2026-10-12 unless noted)
- https://docs.github.com/en/billing/concepts/product-billing/github-actions
- https://www.theregister.com/2025/12/17/github_charge_dev_own_hardware/ (article dated 2025-12-17)
- https://news.ycombinator.com/item?id=47264080 (2026-03-05, the question this sample is modelled on)
- https://woodpecker-ci.org/docs/administration/configuration/forges/github
- https://raw.githubusercontent.com/woodpecker-ci/woodpecker/main/LICENSE
- https://raw.githubusercontent.com/woodpecker-ci/woodpecker/main/docs/docs/20-usage/45-cron.md
- https://forgejo.org/docs/latest/user/actions/overview/
- https://about.gitlab.com/pricing/
- https://docs.gitlab.com/ci/migration/github_actions/
- https://buildkite.com/pricing
- https://circleci.com/pricing/
- https://codeberg.org/api/v1/repos/forgejo/forgejo/releases
- https://proxy.golang.org/github.com/woodpecker-ci/woodpecker/v3/@latest
- https://docs.gitlab.com/user/free_user_limit/
- https://forgejo.org/releases/
- https://codeberg.org/forgejo/forgejo/raw/branch/forgejo/README.md
- https://forgejo.org/docs/latest/admin/command-line/
- https://docs.gitlab.com/releases/patch-releases.xml
- https://hub.docker.com/v2/repositories/gitlab/gitlab-ce/tags
- https://raw.githubusercontent.com/gitlabhq/gitlabhq/master/LICENSE
- https://hub.docker.com/v2/repositories/woodpeckerci/woodpecker-server/tags/v3.19.0
QA log
All 32 matrix cells carry a verdict word and a source number; every number appears in Sources and every URL was fetched on 2026-10-12. Fetches were summarised by a tool, so figures that decide the answer were taken from page text. Double-sourced: the 5-user GitLab.com limit ([8] pricing page and FAQ, [14] docs); Forgejo v16.0.5 date ([12], [15]); Woodpecker v3.19.0 date ([13], [21]); GitLab 19.4.1 date ([18], [19]); GitHub's postponed charge ([1] current wording, [2] report). Single-sourced: Buildkite and CircleCI prices and limits ([10], [11]), GitHub Team included minutes and per-minute rate ([1]). Arithmetic recomputed: 500 × 0.006 = 3.00; 6 × 29 = 174; 6 × 30 = 180; 15 + 15 = 30. No code from the brief was run. Unknowns are listed once above, none guessed.