Skip to content
352 linesCodeBlameRaw
1---
2title: GitHub Actions
3description: Your GitHub Actions workflows run on g1t as they are. Rename .github to .g1t and push.
4---
5
6g1t runs GitHub Actions workflows. They are written exactly as on GitHub,
7and kept in `.g1t/workflows/` instead of `.github/workflows/`.
8
9## Moving from GitHub
10
11```sh
12git mv .github .g1t
13git commit -m "Run our workflows on g1t"
14git push g1t main
15```
16
17That is the whole move. Everything in the folder comes along: workflows,
18local actions under `.g1t/actions/` and anything else you keep there.
19Workflows that still say `uses: ./.github/actions/setup` find it under
20`.g1t/` once `.github` is gone.
21
22g1t never reads `.github`. A repository mirrored to both places can keep
23`.github` for GitHub and `.g1t` for g1t, side by side.
24
25Then add your [secrets and variables](#secrets-and-variables): GitHub never
26gives their values out, so they cannot be copied across.
27
28## What runs
29
30| On GitHub | On g1t |
31| --- | --- |
32| `on:` `push` (branches, tags, paths), `pull_request`, `pull_request_target`, `issues`, `issue_comment`, `pull_request_review`, `schedule`, `workflow_dispatch`, `workflow_run`, `merge_group` | The same, from g1t's own pushes, pull requests, issues, comments and [merge queue](/guides/merge-queue/). |
33| `jobs`, `needs`, `if`, `outputs`, `env`, `defaults`, `timeout-minutes`, `continue-on-error` | The same. |
34| `strategy.matrix` with `include` and `exclude`, `fail-fast`, `max-parallel`, a matrix from `fromJSON(needs.…)` | The same. |
35| `concurrency` with `cancel-in-progress` | The same. |
36| `${{ }}` expressions: every operator, function and context | The same, including `hashFiles`, `success()`, `failure()`, `always()` and `cancelled()`. |
37| `run:` with `bash`, `sh`, `python` or a custom shell | The same. |
38| JavaScript actions (`uses: owner/repo@v7`) | Fetched from GitHub and run as they are, on Node 24, the runtime current actions declare. |
39| Composite actions | The same. |
40| Reusable workflows in the repository (`jobs.<id>.uses: ./.g1t/workflows/build.yml`) | The same: `with:` inputs, `on.workflow_call` outputs, and nesting up to four deep. `./.github/workflows/…` finds the workflow under `.g1t/` after the move. Their jobs read the repository's secrets and variables. |
41| `actions/checkout` | Checks out from g1t, with `ref`, `fetch-depth`, `path`, `repository`, `token` and `submodules`. |
42| `GITHUB_OUTPUT`, `GITHUB_ENV`, `GITHUB_PATH`, `GITHUB_STATE`, `GITHUB_STEP_SUMMARY` | The same. |
43| `::error::`, `::warning::`, `::notice::`, `::group::`, `::add-mask::` | The same: errors and warnings become annotations on the run. |
44| `secrets.*`, `vars.*`, `secrets.GITHUB_TOKEN` | The same. `secrets.G1T_TOKEN` is the workspace's own token for the run; `GITHUB_TOKEN` is its alias. |
45| `environment:` on a job | The job reads each key's row for that environment, as GitHub's environment secrets work, and the run records a [deployment](/guides/deployments-api/#deployments-from-g1t-actions) to it. `url` gives the deployment its address; `deployment: false` reads the environment's values without making one. |
46| `actions/upload-artifact`, `actions/download-artifact` | Kept with the run for 14 days, passed between its jobs, and downloadable from the run's page. Up to 60 MB each. |
47| `actions/cache`, `actions/cache/restore`, `actions/cache/save` | Kept per repository, found by `key` or the newest under a `restore-keys` prefix. `path` takes globs and `!` exclusions. Up to 2 GiB each; see [the cache](#the-cache). |
48
49The **Actions** page of a workflow says, under *How this runs on g1t*,
50anything in it that runs differently.
51
52### Not yet
53
54- **Windows and macOS on g1t's machines.** g1t's own runners are Linux; a
55 job with `runs-on: windows-latest` or `macos-latest` fails, and says so.
56 [Self-hosted runners](/guides/self-hosted-runners/) of any OS run them:
57 `runs-on: [self-hosted, windows]`.
58- **Docker** container actions, `services:` containers and `container:` on
59 g1t's machines. A job's `container:` is ignored there and its steps run on
60 g1t's image; a [self-hosted runner](/guides/self-hosted-runners/#what-a-job-gets)
61 that runs jobs in Docker uses it.
62- **Reusable workflows from other repositories** (`uses: owner/repo/.github/workflows/x.yml@v1`); ones in the same repository work.
63- **The toolkit's own cache.** Actions that cache through GitHub's service
64 themselves, such as `actions/setup-node` with `cache: npm`, run without
65 it. Use `actions/cache` for the same effect.
66- **Environments' protection rules** (required reviewers, wait timers,
67 branch limits). A job with `environment:` gets that environment's
68 [values](/guides/secrets-and-variables/#a-value-per-environment), and runs
69 without waiting. It still records a
70 [deployment](/guides/deployments-api/#deployments-from-g1t-actions)
71 unless it says `deployment: false`.
72
73Why each of these is missing, and what to use instead, is on
74[What g1t can't do yet](/about/limitations/#actions-and-runners).
75
76## The runner
77
78Jobs run in a fresh sandbox each: Debian with Node 24, Python 3, Go, Rust,
79`build-essential`, `git`, `curl`, `jq` and passwordless `sudo`, in GitHub's
80layout (`/home/runner/work`, `RUNNER_TEMP`, `RUNNER_TOOL_CACHE`).
81`runner.os` is `Linux`. `ubuntu-latest`, `ubuntu-24.04` and other Linux
82labels all run here. A job whose `runs-on` names `self-hosted` waits for one
83of your [self-hosted runners](/guides/self-hosted-runners/) instead. Setup actions such as
84`actions/setup-node` and `actions/setup-python` install other versions as
85they do on GitHub.
86
87### Machine sizes
88
89A job runs on the standard machine unless its `runs-on` names a larger
90one:
91
92| `runs-on` | vCPUs | Memory | Disk |
93| --- | --- | --- | --- |
94| `ubuntu-latest`, or any other Linux label | 0.5 | 4 GiB | 8 GB |
95| `g1t-2core` | 2 | 8 GiB | 16 GB |
96| `g1t-4core` | 4 | 12 GiB | 20 GB |
97
98```yaml
99jobs:
100 build:
101 runs-on: g1t-4core
102```
103
104The label can come from the matrix or the run's inputs
105(`runs-on: ${{ matrix.big && 'g1t-4core' || 'ubuntu-latest' }}`). A
106larger machine costs what it costs g1t, plus the same margin as all
107sandbox time: see [usage and billing](/guides/usage-and-billing/#workflow-jobs-on-larger-machines).
108Builds that compile, such as Rust or a large TypeScript project, finish
109several times faster on one.
110
111A job on g1t's machines runs for at most 60 minutes, whatever its
112`timeout-minutes`; one on a self-hosted runner can run for up to 24 hours.
113A job stopped at its time cap fails saying so.
114
115### What a job can reach
116
117A job's network is restricted, as an agent's is (see
118[guardrails](/guides/guardrails/)): it reaches the hosts its project's
119guardrails allow, g1t itself, and what builds need, and nothing else.
120What builds need is the package registries (npm, PyPI, crates.io, the Go
121proxy, RubyGems, Packagist, NuGet, Maven and Gradle, Debian's mirrors),
122GitHub, where `uses:` actions and the setup actions' downloads come from,
123and the toolchains' download sites (`nodejs.org`, `go.dev`,
124`static.rust-lang.org`). A request anywhere else gets `403` with
125the reason. To reach another host, someone with the Maintain [role](/guides/access-and-roles/) or
126higher adds it to the project's
127allowed domains under **Settings → Guardrails**; a project whose guardrails
128turn the network restriction off runs its jobs with an open network.
129
130A host only workflows should reach, such as the API a deploy uploads to,
131goes in **Workflow-only domains** instead, limited to the workflows and
132environments that need it: `api.cloudflare.com | deploy.yml | production`
133lets only `deploy.yml`'s jobs with `environment: production` reach it.
134Agents never reach those hosts, and neither do runs of pull requests from
135forks. See [workflow-only domains](/guides/guardrails/#workflow-only-domains).
136
137g1t does not run cryptocurrency miners: a step that names one (`xmrig`,
138a `stratum+tcp://` pool, `--donate-level`) is not run, and a job that
139looks like it is mining is stopped. See
140[abuse and mining](/guides/guardrails/#abuse-and-mining).
141
142## The cache
143
144`actions/cache` keeps what a job saves for the repository's later jobs:
145
146| | |
147| --- | --- |
148| One entry | Up to 2 GiB, compressed. A larger one is not saved, and the job goes on. |
149| A repository's entries | Up to 10 GiB together. Saving past it removes the entries restored longest ago. |
150| How long | Until it has not been restored for 7 days, and at most 28 days after it was saved. |
151| Keys | Written once: saving under a key that exists does nothing. A restore finds its `key` exactly, else the newest entry whose key starts with one of its `restore-keys`. |
152| `path` | Files and folders; globs, `**` included; `~/` is the home folder; a line starting with `!` leaves matching paths out. |
153| Compression | zstd. |
154
155```yaml
156- uses: actions/cache@v4
157 with:
158 path: |
159 ~/.cargo/registry/cache
160 target/release
161 !target/**/incremental
162 key: cargo-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}
163 restore-keys: cargo-${{ runner.os }}-
164```
165
166Each restore and save says on the job's log how large the entry was and
167how long it took. A workspace on the plan pays for what its caches hold
168(`Actions cache storage` on its statement), at R2's price plus the margin;
169see [usage and billing](/guides/usage-and-billing/#actions-cache).
170
171## Runs and logs
172
173Open a repository's **Actions** page, in its sidebar. Pick a workflow to
174see its runs, run it by hand if it has `workflow_dispatch`, or turn it off
175without touching its file.
176
177A run's page shows its jobs, each job's steps, and their logs as they are
178written. Groups fold, errors and warnings are marked, and secrets are
179replaced with `***`. **Cancel**, **Re-run all jobs** and **Re-run failed
180jobs** do what they say.
181
182## Pull requests
183
184A pull request's workflows run on each new head: when it is opened, when
185a commit is pushed to it, and, for one g1t makes, when g1t
186marks it ready, which on g1t is when it first has code. Each head runs
187each workflow once.
188
189They also start on the activity types `labeled`, `unlabeled`,
190`milestoned`, `demilestoned`, `assigned`, `review_requested` and
191`closed`, and `edited` when the branch a pull request merges into
192changes; `issues` workflows on `labeled`, `unlabeled`, `milestoned` and
193`demilestoned` too. List them under `types:` to run on them. For
194`labeled` and `unlabeled`, `github.event.label` names the label. A pull
195request's `branches` filter, `github.base_ref` and
196`pull_request.base.ref` are the branch it merges into, which is not
197always the default branch: see
198[pull requests into other branches](/guides/base-branches/).
199
200`github.event.pull_request` reads as it does on GitHub. For a pull request
201g1t made, `pull_request.user` is g1t (`login` `g1t`, `type` `Bot`), and
202`pull_request.requested_by` names the person who asked for it; it is `null`
203on anyone else's. `github.event.issue.requested_by` does the same for an
204issue g1t's agent filed. `sender` is whoever caused the event.
205
206## Checks
207
208A pull request's checks are its workflows. Each workflow that runs on
209`pull_request` runs on every pull request's head, whoever opened it, a
210person or an agent, and its runs report a check named after the workflow:
211a workflow with `name: CI` reports `CI`, with the status context
212`CI / pull_request` (the workflow's name and the event). Each of its jobs
213is a [check run](/guides/checks/) on the commit, shown as
214`CI / test (pull_request)` beside it wherever it appears.
215
216- **Which checks a merge needs** is up to the [rules](/guides/rules/) of the branch it merges into,
217 their [required status checks](/guides/pull-requests/#required-status-checks),
218 under **Settings → Rules**. A required check that failed,
219 is still running or has not reported holds the merge. Checks that are not
220 required are shown on the pull request and never hold it.
221- **In a repository that merges through the [merge queue](/guides/merge-queue/)**,
222 workflows with `on: merge_group` run on each combined state the queue
223 builds, on the branch `g1t-queue/<entry>`, and the state lands only if
224 they and every required check pass on it. A workflow behind a required
225 check needs `merge_group` in its `on:`.
226- **A pull request g1t is working on** goes back to g1t when
227 a check fails, with the end of each failed job's log. The agent reads the
228 run and its logs with the same tools you have, fixes the cause, and
229 pushes; the workflows run again. See
230 [seeing it through](/guides/working-with-g1t/#seeing-it-through).
231
232```yaml
233name: CI
234
235on:
236 pull_request:
237 push:
238 branches: [main]
239 merge_group:
240```
241
242### Add CI
243
244A repository with no workflows has nothing that proves a change works, for
245people or for agents. Its pull requests, its **Branches and merging**
246settings and its **Actions** page say **This repository has no checks**,
247with an **Add CI** button. Anyone who can push to the repository can use it:
248
2491. Choose **Add CI**. g1t looks at the files at the repository's root and
250 writes a starter workflow with a job for each stack it finds, up to
251 three: Node (npm, pnpm, Yarn or Bun), Rust, Go, Python (pip or uv), Ruby,
252 Java (Maven or Gradle), .NET, or Make. Each job installs, lints where
253 the project says how, builds and tests. When it finds none, the job is a
254 placeholder that fails until you replace its last step with your own
255 commands.
2562. The workflow is committed as `.g1t/workflows/ci.yml` on a new branch,
257 `add-ci`, and opened as a pull request, by you. It is named `CI` and runs
258 on `pull_request`, on `push` to the default branch, and on `merge_group`.
2593. Change it on the pull request if the steps are not how your project
260 builds, and merge it.
2614. Once it has run, `CI` is offered under **Require status checks to pass
262 before merging**.
263 Require it, so that nothing merges into the default branch unless it
264 passes.
265
266## Secrets and variables
267
268Secrets are read as `${{ secrets.KEY }}` and config as `${{ vars.KEY }}`,
269from the rows under **Settings → Secrets and variables** that are
270available to Workflows. A job with `environment: production` reads each
271key's Production row; other jobs read the rows for all environments. A
272job with an `environment:` also makes a deployment to it; see
273[deployments from g1t Actions](/guides/deployments-api/#deployments-from-g1t-actions). See
274[Secrets and variables](/guides/secrets-and-variables/) for how rows,
275environments and the workspace's rows work.
276
277Every trusted job also gets `${{ secrets.G1T_TOKEN }}`, the workspace's own
278token for the run, with `GITHUB_TOKEN` as its alias. A pull request's runs
279get secrets and the token only when its author has the Write
280[role](/guides/access-and-roles/) or higher on the repository, a member or
281an outside collaborator, or is g1t working on its own. For a pull request
282g1t made, its author is g1t and the person who asked for it is the one
283whose role counts. Anyone else's, such as one
284from a fork or by someone with Read or Triage, runs without secrets and
285with an empty token. See
286[who gets secrets](/guides/secrets-and-variables/#who-gets-secrets).
287
288## Who may run workflows
289
290What you can do with a repository's workflows follows your
291[role](/guides/access-and-roles/) on it:
292
293| | Needs |
294| --- | --- |
295| See workflows, runs and their logs | Read: on a public repository, anyone |
296| Run a workflow by hand, cancel or re-run a run | Write |
297| Enable or disable a workflow | Maintain |
298| The repository's secrets and variables, seeing them included | Admin |
299
300Jobs run in g1t's sandboxes, so they need the
301[g1t plan](/guides/usage-and-billing/#the-g1t-plan) or
302[the trial](/guides/usage-and-billing/#the-trial); jobs on
303[self-hosted runners](/guides/self-hosted-runners/#billing) need neither.
304On a public repository,
305[g1t's open-source pool](/guides/usage-and-billing/#the-open-source-pool)
306runs them too, after a card check, until the month's pool is spent.
307
308Before each job starts, g1t reserves what it may cost (its time limit at
309the sandbox price) with billing, and settles what it really cost when it
310ends; each job's sandbox is charged as
311[sandbox time](/guides/usage-and-billing/#sandbox-time), from the first
312second. A job billing refuses does not start: it is recorded as failed
313with "Not started:" and the reason, such as "Workflows run in g1t's
314sandboxes, which cost real money, so they need the g1t plan ($20 a month)
315or a card check", and what to do about it. The
316Actions page tells people with Write on a repository whose workspace
317cannot run jobs before the first run.
318
319## From the API
320
321The routes follow the standard Actions REST shape, so existing scripts
322usually work once they point at `https://api.g1t.sh`.
323
324| `workflow` action | Route |
325| --- | --- |
326| `list` | `GET /repos/{owner}/{repo}/actions/workflows` |
327| `list_runs` | `GET /repos/{owner}/{repo}/actions/runs`, with `workflow`, `branch`, `event`, `pull`, `head_sha` |
328| `get_run` | `GET /repos/{owner}/{repo}/actions/runs/{id}` |
329| `job_logs` | `GET /repos/{owner}/{repo}/actions/jobs/{job}/logs?after=` |
330| `dispatch` | `POST /repos/{owner}/{repo}/actions/workflows/{workflow}/dispatches` with `ref` and `inputs` |
331| `cancel` | `POST /repos/{owner}/{repo}/actions/runs/{id}/cancel` |
332| `rerun` | `POST …/runs/{id}/rerun`, or `…/rerun-failed-jobs` |
333| `update` | `PUT …/workflows/{workflow}/enable` and `…/disable` |
334
335Secrets and variables have a tool of their own, `secret`:
336
337| `secret` action | Route |
338| --- | --- |
339| `list_secrets`, `set_secret`, `delete_secret` | `GET /repos/{owner}/{repo}/actions/secrets`, `PUT` and `DELETE …/secrets/{name}` |
340| `list_variables`, `set_variable`, `delete_variable` | `GET` and `POST /repos/{owner}/{repo}/actions/variables`, `PATCH` and `DELETE …/variables/{name}` |
341
342Workspace secrets and variables are under
343`/workspaces/{workspace}/actions/secrets` and `…/variables`. The fields
344g1t adds (environments, who reads a row, linked repositories) are in
345[Secrets and variables](/guides/secrets-and-variables/#from-the-api).
346
347```sh
348curl -X POST https://api.g1t.sh/repos/acme/web/actions/workflows/ci.yml/dispatches \
349 -H "Authorization: Bearer $G1T_TOKEN" -H "Content-Type: application/json" \
350 -d '{"ref": "main", "inputs": {"environment": "staging"}}'
351```
352