Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1 | --- |
| 2 | title: GitHub Actions | |
| 3 | description: Your GitHub Actions workflows run on g1t as they are. Rename .github to .g1t and push. | |
| 4 | --- | |
| 5 | ||
| 6 | g1t runs GitHub Actions workflows. They are written exactly as on GitHub, | |
| 7 | and kept in `.g1t/workflows/` instead of `.github/workflows/`. | |
| 8 | ||
| 9 | ## Moving from GitHub | |
| 10 | ||
| 11 | ```sh | |
| 12 | git mv .github .g1t | |
| 13 | git commit -m "Run our workflows on g1t" | |
| 14 | git push g1t main | |
| 15 | ``` | |
| 16 | ||
| 17 | That is the whole move. Everything in the folder comes along: workflows, | |
| 18 | local actions under `.g1t/actions/` and anything else you keep there. | |
| 19 | Workflows that still say `uses: ./.github/actions/setup` find it under | |
| 20 | `.g1t/` once `.github` is gone. | |
| 21 | ||
| Merge branch 'mirroring' into artifacts-mode | 22 | Otherwise g1t doesn't read `.github`, so a repository that lives in both |
| 23 | places can keep `.github` for GitHub and `.g1t` for g1t, side by side. | |
| 24 | ||
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 25 | Then add your [secrets and variables](#secrets-and-variables): GitHub never |
| 26 | gives their values out, so they cannot be copied across. | |
| 27 | ||
| 28 | ## What runs | |
| 29 | ||
| 30 | | On GitHub | On g1t | | |
| 31 | | --- | --- | | |
| Merge branch 'worktree-agent-a8b78c62188153aa3' into claude/cool-newton-7nm8r9 | 32 | | `on:` `push` (branches, tags, paths), `pull_request`, `pull_request_target`, `issues`, `issue_comment`, `pull_request_review`, `schedule`, `workflow_dispatch`, `workflow_run`, `merge_group`, `create`, `delete`, `repository_dispatch`, `release`, `deployment`, `deployment_status` | The same, from g1t's own pushes, pull requests, issues, comments, [releases](#releases), [deployments](#deployments) and [merge queue](/guides/merge-queue/). `create` starts on each new branch or tag, at its commit; `delete` on each branch or tag a push deletes, on the default branch's latest commit, with `github.event.ref` and `github.event.ref_type` naming what went. As on GitHub, neither takes `branches` or `tags` filters: a workflow on them runs for every branch and tag. `repository_dispatch` starts on [a dispatch event](#repository-dispatch). | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 33 | | `jobs`, `needs`, `if`, `outputs`, `env`, `defaults`, `timeout-minutes`, `continue-on-error` | The same. | |
| Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts | 34 | | `timeout-minutes` and `continue-on-error` on a step | The same, for `run:` and `uses:` steps alike. A `uses:` step's action is stopped at its limit, with every process it started; a step inside a composite action stops at its own limit or the `uses:` step's, whichever comes first. A step stopped this way fails, unless `continue-on-error` lets the job go on. | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 35 | | `strategy.matrix` with `include` and `exclude`, `fail-fast`, `max-parallel`, a matrix from `fromJSON(needs.…)` | The same. | |
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 36 | | `concurrency` with `cancel-in-progress`, for the workflow or for one job | The same: one run, or one job, of a group at a time. | |
| 37 | | `permissions:` for the workflow or for one job, `read-all`, `write-all` | The same: they decide what [the job's token](#the-jobs-token) may do. | | |
| success(), failure(), cancelled() and always() work only in an if:, as on GitHub. Anywhere else, such as a step's env, g1t now refuses them with GitHub's own error, "Unrecognized function: 'success'"; before, g1t accepted them everywhere, and the Conformance workflow, which read success() in its env, ran on g1t and failed on GitHub. The workflow no longer reports it, and the Actions guide says where the status functions may be called. | 38 | | `${{ }}` expressions: every operator, function and context | The same, including `hashFiles`, and `success()`, `failure()`, `always()` and `cancelled()` in `if:` (anywhere else they are an error, as on GitHub). | |
| Merge branch 'worktree-agent-a41ebf64a05c894fe' into claude/cool-newton-7nm8r9 | 39 | | `run:` with `bash`, `sh`, `python`, `pwsh` or a custom shell | The same, with GitHub's file for each: `.sh` for `bash` and `sh`, `.py` for `python`, `.ps1` for PowerShell (stopping at the first error, and exiting with the last program's code), `.cmd` for `cmd`, and no extension for another program. `python` runs `python`, or `python3` on a machine without it. | |
| 40 | | JavaScript actions (`uses: owner/repo@v7`, `owner/repo/path@v7`) | Fetched from that repository on g1t when g1t has it and your repository may use it, otherwise from GitHub, and run as they are, on Node 24, the runtime current actions declare. An action that declares `node20` runs on Node 20 where the machine has one. See [actions and workflows from other repositories](#actions-and-workflows-from-other-repositories) and [an action's pre and post](#an-actions-pre-and-post). | | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 41 | | Composite actions | The same. | |
| Merge branch 'worktree-agent-af75396ad4c6ee7a8' into claude/cool-newton-7nm8r9 | 42 | | Reusable workflows (`jobs.<id>.uses: ./.g1t/workflows/build.yml`, or `owner/repo/.g1t/workflows/build.yml@v1` in another repository) | The same: `with:` inputs checked against their `type`, `secrets:` by name or `secrets: inherit`, `on.workflow_call` outputs, `strategy.matrix` on the calling job (one call for each combination), `concurrency` on the calling job, and up to ten levels of workflows with at most 50 different reusable workflows in a run. `.github/workflows/…` finds the workflow under `.g1t/` after the move. See [actions and workflows from other repositories](#actions-and-workflows-from-other-repositories). | |
| Merge GitHub pull request #8 (claude/cool-newton-7nm8r9): Docker deployments on g1t.page behind a switch that stays off until Cloudflare's container APIs are checked live, workflows a workspace manages in its repositories, tarball and zipball downloads, refs/pull/* kept to g1t alone, framework detection for g1t.page builds, and a workflow's event payload matching GitHub's. | 43 | | `actions/checkout` | The action itself, at the version the step names, fetching from g1t with the job's token: every input and output, its post step that removes the credential, and a pull request's [test merge commit](#what-a-pull-requests-run-builds), which g1t keeps in the repository. In a job container without git it downloads the commit as a tarball from [`GET /repos/{owner}/{repo}/tarball/{ref}`](/reference/api/repositories/download-tarball-archive/), as on GitHub, up to 10,000 files and 24 MB. `lfs` finds no Git LFS files: g1t keeps none. | |
| Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009) | 44 | | `GITHUB_OUTPUT`, `GITHUB_ENV`, `GITHUB_PATH`, `GITHUB_STATE`, `GITHUB_STEP_SUMMARY` | The same. Step summaries show on the run's page; see [job summaries](#job-summaries). | |
| Merge branch 'worktree-agent-a41ebf64a05c894fe' into claude/cool-newton-7nm8r9 | 45 | | `::error::`, `::warning::`, `::notice::`, `::group::`, `::add-mask::`, `::echo::on` | The same: errors and warnings become annotations on the run, with their `file`, `line`, `col`, `endLine` and `endColumn`, and [masked](#masking-secrets) values stay hidden. | |
| 46 | | Problem matchers (`::add-matcher::`, `::remove-matcher::`) | The same, so `actions/setup-node`, `setup-go` and `setup-python` turn compiler and linter output into annotations. See [problem matchers](#problem-matchers). | | |
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 47 | | `secrets.*`, `vars.*`, `secrets.GITHUB_TOKEN` | The same. `secrets.G1T_TOKEN` is [the job's own token](#the-jobs-token); `GITHUB_TOKEN` is its alias. | |
| 48 | | `environment:` on a job | The job waits for the environment's [protection rules](#environments), then reads each key's row for that environment, as 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. The name may be an expression. | | |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 49 | | `actions/upload-artifact`, `actions/download-artifact`, `actions/upload-artifact/merge` | The same inputs and outputs as version 4: `retention-days`, `overwrite`, `compression-level`, `include-hidden-files`, `!` exclusions, download by `pattern` with `merge-multiple`, and from another run with `run-id` and `github-token`. Up to 5 GiB each; see [artifacts](#artifacts). | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' | 50 | | `actions/cache`, `actions/cache/restore`, `actions/cache/save` | The actions themselves, at the version the step names, saving to and restoring from the repository's cache: kept per repository and branch, found by `key` or the newest under a `restore-keys` prefix. Up to 2 GiB each; see [the cache](#the-cache). | |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 51 | | Actions that cache through the toolkit, such as `actions/setup-node` with `cache: npm` or `Swatinem/rust-cache` | The same: they save to and restore from the repository's cache. See [actions built on the toolkit](#actions-built-on-the-toolkit). | |
| Merge remote-tracking branch 'origin/main' into workspace-chat | 52 | | sccache with `SCCACHE_GHA_ENABLED` | The same: its entries go to the repository's cache. See [caching Rust builds](#caching-rust-builds). | |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 53 | | `permissions: id-token: write` | The job can ask for an OIDC token, and trade it for a cloud provider's credentials. See [OIDC tokens](#oidc-tokens). | |
| Merge branch 'main' into actions-toolkit-oidc-artifacts | 54 | | `docker build`, `push`, `run`, `login`, `compose`, Buildx | The same, with a Docker Engine of the job's own. See [Docker](#docker). | |
| 55 | | `services:` | The same: each service starts before the steps, health checks are waited for, and it is reached at `localhost` on its port and by its name. | | |
| 56 | | `container:` | The same: every step runs inside the image. | | |
| 57 | | `uses: docker://image`, Docker actions (`runs.using: docker`) | The same: built from the action's Dockerfile or pulled, and run with GitHub's `/github/workspace` layout. | | |
| 58 | | `docker/setup-buildx-action`, `docker/build-push-action`, `docker/login-action` | The same. `setup-buildx-action` picks the job's own Engine as the builder. | | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 59 | |
| 60 | The **Actions** page of a workflow says, under *How this runs on g1t*, | |
| 61 | anything in it that runs differently. | |
| 62 | ||
| 63 | ### Not yet | |
| 64 | ||
| 65 | - **Windows and macOS on g1t's machines.** g1t's own runners are Linux; a | |
| 66 | job with `runs-on: windows-latest` or `macos-latest` fails, and says so. | |
| 67 | [Self-hosted runners](/guides/self-hosted-runners/) of any OS run them: | |
| 68 | `runs-on: [self-hosted, windows]`. | |
| Merge branch 'main' into actions-toolkit-oidc-artifacts | 69 | - **Docker's `type=gha` build cache.** Buildx skips it on g1t, and the |
| 70 | build runs without a cache. Use a registry cache instead; see | |
| 71 | [caching image builds](#caching-image-builds). | |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 72 | - **Actions that upload artifacts with the toolkit's artifact library |
| 73 | themselves.** The library refuses to run against any server but | |
| 74 | github.com. `actions/upload-artifact`, `actions/download-artifact` and | |
| 75 | `actions/upload-artifact/merge` work, because g1t runs them itself. See | |
| 76 | [actions built on the toolkit](#actions-built-on-the-toolkit). | |
| Merge branch 'worktree-agent-a8b78c62188153aa3' into claude/cool-newton-7nm8r9 | 77 | - **`on: label`, and some activity types.** Creating, editing or deleting |
| 78 | a label starts no workflows yet, and the workflow's page says so. Nor do | |
| 79 | the `pull_request` types `unassigned`, `locked` and `unlocked`, `edited` | |
| 80 | for a new title or description, or the `issues` types `unassigned`, | |
| 81 | `locked`, `unlocked`, `pinned` and `unpinned`. | |
| Merge branch 'worktree-agent-a641fa0e2e4fffccb' into claude/cool-newton-7nm8r9 | 82 | - **Background steps.** A step with `background: true`, or a `wait`, |
| 83 | `wait-all`, `cancel` or `parallel` step, is refused: g1t does not run | |
| 84 | them yet. | |
| 85 | - **`timezone` on a schedule, `concurrency.queue`, `cancel-timeout-minutes` | |
| 86 | and `snapshot`.** The workflow runs without them, and its page says so: | |
| 87 | a schedule runs in UTC, a group keeps one run waiting, a cancelled job | |
| 88 | stops in its usual time, and no runner image is made. | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 89 | |
| 90 | Why each of these is missing, and what to use instead, is on | |
| 91 | [What g1t can't do yet](/about/limitations/#actions-and-runners). | |
| 92 | ||
| What runs differently on g1t's machines is said before it surprises anyone, and four things now behave as on GitHub. A commit whose message says `[skip ci]`, `[ci skip]`, `[no ci]`, `[skip actions]` or `[actions skip]`, or ends with `skip-checks: true`, starts no `push` or `pull_request` workflows. A `pull_request_review` event's `review.state` is `approved` or `changes_requested`, not `approve` or `requestchanges`. A self-hosted job that names no `timeout-minutes` runs for 360 minutes, not 60. A JavaScript action's `::debug::` lines show on a debug run, as `run:` steps' do. The workflow's page now warns when a job asks for more than the 60 minutes g1t's machines give it, when an Arm label will run on x64, and when a matrix on a job that calls a reusable workflow will run it once; it no longer says artifacts are kept up to 60 MB (they are kept up to 5 GiB), nor that `setup-node` with `cache:` runs without its cache (the toolkit's cache works). The desktop release's two hosted jobs ask for the 60 minutes they get. The Actions and self-hosted runners guides say so. | 93 | ## Skipping a run |
| 94 | ||
| 95 | A commit can ask not to start the `push` and `pull_request` workflows it | |
| 96 | would, as on GitHub: put `[skip ci]`, `[ci skip]`, `[no ci]`, | |
| 97 | `[skip actions]` or `[actions skip]` anywhere in its message, or end the | |
| 98 | message with a `skip-checks: true` trailer. For a push, the message read | |
| 99 | is the pushed head's; for a pull request, its head commit's. Other | |
| 100 | events, such as `pull_request_target`, `workflow_dispatch` and | |
| 101 | `schedule`, still start their workflows. | |
| 102 | ||
| 103 | ```sh | |
| 104 | git commit -m "Fix a typo in the README [skip ci]" | |
| 105 | ``` | |
| 106 | ||
| 107 | A required check that a skipped workflow would have reported stays | |
| 108 | pending, so a pull request whose merge needs it waits for a push that | |
| 109 | runs it. | |
| 110 | ||
| Merge branch 'worktree-agent-a641fa0e2e4fffccb' into claude/cool-newton-7nm8r9 | 111 | ## How g1t checks a workflow |
| 112 | ||
| 113 | g1t reads a workflow as GitHub does, from GitHub's own schema for workflow | |
| 114 | files, so a workflow GitHub refuses is refused on g1t too, and one GitHub | |
| 115 | runs reads on g1t. When a workflow can't be read, its page says what is | |
| 116 | wrong, with the job and step, and no run starts from it. | |
| 117 | ||
| 118 | | You write | g1t says | | |
| 119 | | --- | --- | | |
| 120 | | A key GitHub doesn't have, at any level, such as `runs_on:` or `with:` on a `run:` step | It is unexpected, and lists the keys that place can have. | | |
| 121 | | A job without `runs-on` | The job has no `runs-on`. A job that calls a reusable workflow with `uses:` has no `runs-on` or `steps`. | | |
| 122 | | A job id that doesn't start with a letter or `_`, has characters other than letters, digits, `-` and `_`, or starts with `__` | It is not a job id GitHub accepts. Step ids follow the same rule. Two jobs, or two steps of a job, whose ids differ only in case are the same id. | | |
| 123 | | An event GitHub doesn't have, or a filter the event doesn't take, such as `types` on `push` | GitHub has no such event, or the event doesn't take that key. `branches` and `branches-ignore` (and `tags`, `paths`) can't both be on one event. | | |
| 124 | | A YAML merge key (`<<: *defaults`) | GitHub doesn't read merge keys. Anchors and aliases (`&steps` and `*steps`) work, as on GitHub, for a whole value. | | |
| 125 | | A `permissions` name GitHub's token doesn't have, such as `metadata` | It is unexpected. A name GitHub has that g1t has nothing behind yet reads, and grants nothing. | | |
| 126 | ||
| 127 | ### g1t's own settings | |
| 128 | ||
| 129 | A `g1t:` mapping can go at the top of a workflow, on a job and on a step. | |
| 130 | GitHub refuses a workflow with `g1t:` in it, so use it only in | |
| 131 | `.g1t/workflows`. It follows two rules: | |
| 132 | ||
| 133 | - It only adds to a workflow. It never changes what a GitHub key means. | |
| 134 | - Each setting in it has a GitHub equivalent, written here, so that a | |
| 135 | workflow can be moved back to GitHub without it. | |
| 136 | ||
| 137 | | Setting | Where | What it does | On GitHub | | |
| 138 | | --- | --- | --- | --- | | |
| 139 | | `deployment: false` | A job | The job reads its `environment:` values without the run recording a deployment. | `environment: { name: ..., deployment: false }` | | |
| 140 | ||
| 141 | g1t keeps any other key under `g1t:` as written, and does nothing with it | |
| 142 | yet. | |
| 143 | ||
| A project can build with a workflow. Turning on **Build with a workflow** under Settings, Deployments installs a managed workflow named `g1t` that calls g1t's reusable deploy workflow (`g1t/workflows/.g1t/workflows/deploy.yml@v1`, published from `workflows/` by the actions release) with the project's settings, and pushes and pull requests then start it rather than a build of Deployments' own: the same previews and production, at the same addresses, reported as `g1t / deploy`, now the check of the workflow's job, listed on the Actions page with its runs and logs. A pull request from a fork runs it with a read-only token, as on GitHub, and still gets its preview without the project's build secrets: a read-only job token may open a preview build only from a run of a managed workflow. Fork pull requests run the repository's managed workflows too. Its jobs are Actions time, at cost plus 20% on g1t's machines and free on a self-hosted runner. A workflow named `g1t` in `.g1t/workflows/` takes its place. The deployments and Actions guides say so. | 144 | ## Managed workflows |
| 145 | ||
| 146 | Some workflows run in a repository without a file in it: g1t installs | |
| 147 | them for a feature you turn on, such as a project's | |
| 148 | [build with a workflow](/guides/deployments/#build-with-a-workflow). A | |
| 149 | managed workflow runs like any other: on the **Actions** page, with its | |
| 150 | runs, logs, re-runs and checks, on g1t's machines or your | |
| 151 | [self-hosted runners](/guides/self-hosted-runners/). Its page says it is | |
| 152 | managed by g1t. | |
| 153 | ||
| 154 | A workflow of the same `name:` in `.g1t/workflows/` runs in its place, so | |
| 155 | to change one, commit your own version of it. | |
| 156 | ||
| Merge GitHub pull request #8 (claude/cool-newton-7nm8r9): Docker deployments on g1t.page behind a switch that stays off until Cloudflare's container APIs are checked live, workflows a workspace manages in its repositories, tarball and zipball downloads, refs/pull/* kept to g1t alone, framework detection for g1t.page builds, and a workflow's event payload matching GitHub's. | 157 | ## Workflows a workspace manages |
| 158 | ||
| 159 | A workspace's owners can run a workflow in the workspace's repositories | |
| 160 | without committing it to each one, as GitHub's required workflows do. It | |
| 161 | runs in each repository it targets as that repository's own workflow: on | |
| 162 | the repository's events, with the repository's job token, secrets and | |
| 163 | variables, and reporting the repository's checks. Its path is | |
| 164 | `managed/<name>.yml`, and the repository's **Actions** page lists it as | |
| 165 | managed by the workspace, with the file it came from. | |
| 166 | ||
| 167 | To add one: | |
| 168 | ||
| 169 | 1. Commit the workflow to one of the workspace's repositories, such as | |
| 170 | `acme/policies/.g1t/workflows/scan.yml`. | |
| 171 | 2. Open **Workspace → Code → Actions**, `g1t.sh/<workspace>/-/actions`, and | |
| 172 | under **Workflows this workspace manages** choose **Add workflow**. | |
| 173 | 3. Give it a name, its source as `owner/repo/path@ref` (for example | |
| 174 | `acme/policies/.g1t/workflows/scan.yml@main`), a mode, and the | |
| 175 | repositories it runs in, then choose **Add workflow**. | |
| 176 | ||
| 177 | | Setting | Options | | |
| 178 | | --- | --- | | |
| 179 | | Mode | **Required**: it runs in every repository it targets. A workflow of the same `name:` in the repository does not run while it is required, and nobody in the repository can turn it off. **Default**: it runs where the repository has no workflow of the same `name:`, which runs in its place, and the repository's admins can turn it off on its Actions page. | | |
| 180 | | Repositories | **All repositories**, or names and patterns, one per line: `*` matches any characters, and `!name` leaves out what an earlier line took in. The last line that matches decides, without regard to case; only `!` lines means every repository but those. | | |
| 181 | | Visibility | Public and private repositories, public only, or private only. | | |
| 182 | ||
| 183 | g1t copies the source file when you save, at the commit its ref names | |
| 184 | then, and that copy runs until you copy it again with **Copy again** (or | |
| 185 | save it with another source). So someone who can push to the source | |
| 186 | repository cannot change what runs with every repository's secrets: only | |
| 187 | an owner can, by copying it. The workflows list shows the commit each was | |
| 188 | copied at. | |
| 189 | ||
| 190 | - The source must be a workflow file in one of the workspace's own | |
| 191 | repositories. | |
| 192 | - A source in a private repository runs in private repositories only, as a | |
| 193 | public repository's workflows cannot use a private repository's: choose | |
| 194 | **Private repositories only**, or g1t refuses it. A repository made | |
| 195 | public later stops running it. | |
| 196 | - `uses: ./…` in the copy names the repository it runs in, as it would in a | |
| 197 | file committed there. To call a reusable workflow of the source | |
| 198 | repository, name it in full: | |
| 199 | `uses: acme/policies/.g1t/workflows/build.yml@main`, which follows the | |
| 200 | [rules for other repositories](#actions-and-workflows-from-other-repositories). | |
| 201 | - A required workflow runs for pull requests from forks and in the | |
| 202 | [merge queue](/guides/merge-queue/) too, whatever the fork's files say. | |
| 203 | - When it changes, up to 20 repositories' workflow lists are brought up to | |
| 204 | date at once. In a larger workspace the rest follow within minutes, or | |
| 205 | as soon as someone opens their Actions page; their runs read the | |
| 206 | workflows as they are meanwhile. | |
| 207 | ||
| 208 | To make a pull request wait for a required workflow, require its check in | |
| 209 | a [ruleset](/guides/rules/): its `name:` as the context, with | |
| 210 | `integration: actions`. A failure of the workflow fails the check whatever | |
| 211 | else reports a check of that name. | |
| 212 | ||
| 213 | Through the API and MCP: | |
| 214 | ||
| 215 | | Route | MCP | | | |
| 216 | | --- | --- | --- | | |
| 217 | | [`GET /workspaces/{workspace}/actions/managed-workflows`](/reference/api/run-protection/list-workspace-managed-workflows/) | `workflow` `list_managed_workflows` | Each with its source, the commit it was copied at, its mode, repositories, visibility and the copy that runs. | | |
| 218 | | [`POST /workspaces/{workspace}/actions/managed-workflows`](/reference/api/run-protection/create-workspace-managed-workflow/) | `workflow` `add_managed_workflow` | `name`, `source`, `mode` (`required` or `default`), `repositories`, `visibility` (`all`, `public` or `private`). | | |
| 219 | | [`PATCH /workspaces/{workspace}/actions/managed-workflows/{workflow}`](/reference/api/run-protection/update-workspace-managed-workflow/) | `workflow` `update_managed_workflow` | Any of those; `refresh: true` copies the source again. | | |
| 220 | | [`DELETE /workspaces/{workspace}/actions/managed-workflows/{workflow}`](/reference/api/run-protection/delete-workspace-managed-workflow/) | `workflow` `remove_managed_workflow` | Its runs stay. | | |
| 221 | ||
| 222 | Only owners can see and change them; a token needs `workspace:read` to | |
| 223 | list them and `workspace:admin` to change them. | |
| 224 | ||
| Merge branch 'worktree-agent-ab9543c492a7ed481' into spend-guardrails | 225 | ## Schedules |
| 226 | ||
| 227 | A workflow with `on: schedule` runs on the default branch's latest commit, | |
| 228 | at each time its cron lines name, in UTC: | |
| 229 | ||
| 230 | ```yaml | |
| 231 | on: | |
| 232 | schedule: | |
| 233 | - cron: "0 9 * * mon" # Mondays at 09:00 UTC | |
| 234 | - cron: "*/30 * * * *" # every 30 minutes | |
| 235 | ``` | |
| 236 | ||
| 237 | Each line has five fields: minute, hour, day of month, month and day of | |
| 238 | the week. A field takes `*`, a number, a range `1-5`, a list `1,15` and a | |
| 239 | step `*/10`; days take `mon` to `sun`, and months `jan` to `dec`. | |
| 240 | ||
| 241 | | Rule | What happens | | |
| 242 | | --- | --- | | |
| 243 | | Every 5 minutes at most | A schedule more frequent than every 5 minutes, such as `* * * * *` or `*/2 * * * *`, runs every 5 minutes instead, on the five-minute marks (:00, :05, :10 and so on), at each mark that ends five minutes in which it would have run. A mark outside the hours, days or months the schedule names never runs: `* 9 * * *` runs from 09:00 to 09:55. | | |
| 244 | | No push for 60 days | Schedules pause in a repository that has had no push for 60 days. The next push to any branch resumes them. Other events and `workflow_dispatch` still start the workflow. | | |
| 245 | | Actions not paid for | When a scheduled run's job could not start because the workspace's plan, spend limit or the open-source pool does not cover it, that run fails and says why, and the workflow's schedule waits an hour before it tries again. | | |
| 246 | | Archived repository | Schedules wait until the repository is unarchived. | | |
| 247 | ||
| Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts | 248 | ## Actions and workflows from other repositories |
| 249 | ||
| 250 | A step's `uses: owner/repo@ref` (or `owner/repo/path@ref`) and a job's | |
| 251 | `uses: owner/repo/.g1t/workflows/build.yml@ref` name another repository. | |
| A workflow's `uses: actions/setup-node@v4` means GitHub's `actions` again, whoever is on g1t. g1t looked for a repository on g1t before GitHub, and anyone could make a public workspace called `actions`, `docker` or `aws-actions` and have its `setup-node` run in every workflow that names GitHub's, with that job's secrets. Now another workspace's public repository answers only for a name GitHub has no public repository of; the caller's own workspace and g1t's own `g1t/…` still answer from g1t, and when GitHub can't be asked, GitHub's is used. The names of the GitHub accounts whose actions workflows use most can no longer be registered, renamed to, or taken by signing up with GitHub (which suggests the name with `-gh`); an account that has one keeps it, and mentions and invitations still find it. The Actions, authentication and workspaces guides say so. | 252 | g1t looks for it on g1t first, but a name means what it means on GitHub |
| 253 | whenever GitHub has it: | |
| Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts | 254 | |
| 255 | | The repository | What happens | | |
| 256 | | --- | --- | | |
| Merge workspace aliases through Actions and tokens: uses: g1t/deploy@v1 resolves to flagon-io/deploy, a token scoped to a repository reaches it under the alias, a g1t/ action is never taken from GitHub, and the Actions release creates g1t's action repositories when they are missing. | 257 | | On g1t and public: in your workspace, under `g1t/` (g1t's own), or with a name GitHub has no public repository of | Your workflows use it, from any workspace. | |
| Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts | 258 | | On g1t, private, in your workspace, with **Access** set to *Accessible from repositories in* the workspace | Your private repositories' workflows use it. A job reads it with a read-only token for that repository alone, which ends with the job. | |
| 259 | | On g1t, private, and not shared that way | The step or job fails, and says why. A private repository's actions are never used by a public repository's workflows, whose logs anyone can read, nor from another workspace. | | |
| Merge workspace aliases through Actions and tokens: uses: g1t/deploy@v1 resolves to flagon-io/deploy, a token scoped to a repository reaches it under the alias, a g1t/ action is never taken from GitHub, and the Actions release creates g1t's action repositories when they are missing. | 260 | | Under `g1t/`, and not one of g1t's own public repositories | The step or job fails, and says so. A `g1t/` name is never looked for on GitHub. | |
| Merge remote-tracking branch 'origin/claude/peaceful-franklin-7qtkwx' | 261 | | Not on g1t, or private in a workspace you cannot see | An action comes from GitHub, at the commit its ref names there (see [actions from GitHub](#actions-from-github)); a reusable workflow is read from a public repository on GitHub. | |
| A workflow's `uses: actions/setup-node@v4` means GitHub's `actions` again, whoever is on g1t. g1t looked for a repository on g1t before GitHub, and anyone could make a public workspace called `actions`, `docker` or `aws-actions` and have its `setup-node` run in every workflow that names GitHub's, with that job's secrets. Now another workspace's public repository answers only for a name GitHub has no public repository of; the caller's own workspace and g1t's own `g1t/…` still answer from g1t, and when GitHub can't be asked, GitHub's is used. The names of the GitHub accounts whose actions workflows use most can no longer be registered, renamed to, or taken by signing up with GitHub (which suggests the name with `-gh`); an account that has one keeps it, and mentions and invitations still find it. The Actions, authentication and workspaces guides say so. | 262 | | On g1t, public, in another workspace, with a name GitHub has a public repository of | GitHub's is used, as on GitHub: anyone can make a workspace, so a workspace called `actions` never answers for `actions/setup-node`. When g1t can't reach GitHub to tell, GitHub's is used too. | |
| Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts | 263 | |
| Merge workspace aliases through Actions and tokens: uses: g1t/deploy@v1 resolves to flagon-io/deploy, a token scoped to a repository reaches it under the alias, a g1t/ action is never taken from GitHub, and the Actions release creates g1t's action repositories when they are missing. | 264 | An owner that is a [workspace alias](/guides/workspaces/#workspace-aliases) |
| 265 | is looked for under its workspace's slug, by the same rules, as if you had | |
| 266 | written that slug: the alias decides where g1t looks, never who may use | |
| 267 | what it finds. | |
| 268 | ||
| Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts | 269 | `ref` is a branch, a tag or a commit. A reusable workflow may be under |
| 270 | `.g1t/workflows/` or `.github/workflows/`; a `.github/workflows/` path | |
| 271 | also finds the file under `.g1t/workflows/` in a repository moved to | |
| 272 | g1t. A `./.g1t/workflows/…` call inside a workflow from another | |
| 273 | repository reads from that repository, at the same ref. | |
| 274 | ||
| 275 | To share a private repository's actions and workflows with the rest of its | |
| 276 | workspace, an admin chooses **Settings → Actions → Access → Accessible from | |
| 277 | repositories in** the workspace, or calls | |
| 278 | `PUT /repos/{owner}/{repo}/actions/permissions/access` with | |
| 279 | `{"access_level": "organization"}` (`none` to stop). | |
| 280 | ||
| Merge remote-tracking branch 'origin/claude/peaceful-franklin-7qtkwx' | 281 | ### Actions from GitHub |
| 282 | ||
| 283 | g1t keeps the actions your workflows use from GitHub, so a job downloads | |
| 284 | them from g1t rather than from GitHub: | |
| 285 | ||
| 286 | 1. Before the first step, the job downloads every action its steps name, | |
| 287 | as GitHub's runner does in **Set up job**, and fails there if one can't | |
| 288 | be had. Its log names each one's commit: | |
| 289 | `Download action repository 'actions/setup-node@v4' (SHA:…) from g1t`. | |
| 290 | 2. g1t reads which commit the ref (`v4`, a branch, or a commit) names on | |
| 291 | GitHub, a tag before a branch of the same name, and looks again at | |
| 292 | most every 5 minutes, so a tag that moves is followed within minutes. | |
| 293 | 3. The first job to use an action at a commit has g1t fetch that commit's | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' | 294 | archive from GitHub and keep it, which can take up to two minutes. |
| 295 | While it waits, **Set up job** says so every 5 seconds | |
| 296 | (`Waiting for g1t to fetch 'actions/setup-node@v4' (10s)`). Every | |
| 297 | later job, in any workspace, downloads the same bytes from g1t. | |
| Merge remote-tracking branch 'origin/claude/peaceful-franklin-7qtkwx' | 298 | |
| 299 | While GitHub doesn't answer, a ref reads as the commit it last named, and | |
| 300 | the job says so in a warning; an action g1t keeps still downloads. An | |
| 301 | action whose archive is larger than 32 MB, or from a private repository | |
| 302 | on GitHub, is downloaded from GitHub by the job itself. An archive no job | |
| 303 | has used for 30 days is deleted, and fetched again when next used. | |
| 304 | Kept archives are g1t's and count toward no workspace's storage. | |
| 305 | ||
| 306 | Actions that a composite action uses are downloaded when it runs. | |
| 307 | ||
| Merge branch 'worktree-agent-a4d35ee70c50683d0' into claude/cool-newton-7nm8r9 | 308 | ### g1t's own actions |
| 309 | ||
| Merge workspace aliases through Actions and tokens: uses: g1t/deploy@v1 resolves to flagon-io/deploy, a token scoped to a repository reaches it under the alias, a g1t/ action is never taken from GitHub, and the Actions release creates g1t's action repositories when they are missing. | 310 | g1t's own actions live under `g1t/` on g1t.sh, public, with a `v1` tag |
| 311 | that moves with each compatible release. `g1t` is a | |
| 312 | [workspace alias](/guides/workspaces/#workspace-aliases) of `flagon-io`, | |
| 313 | the workspace of Flagon, Inc., which builds g1t: `g1t/deploy@v1` is the | |
| 314 | repository `flagon-io/deploy`, and its page and the job's log name it | |
| 315 | that way. Write `g1t/`; it keeps working wherever g1t's actions are kept. | |
| Merge branch 'worktree-agent-a4d35ee70c50683d0' into claude/cool-newton-7nm8r9 | 316 | |
| 317 | | Action | What it does | | |
| 318 | | --- | --- | | |
| 319 | | [`g1t/deploy@v1`](https://g1t.sh/g1t/deploy) | Builds the checkout and puts it on [g1t.page](/guides/deployments/): production from the project's production branch, a preview from a pull request or another branch. The job needs `deployments: write`. See [deploying from a workflow](/guides/deployments/#deploying-from-a-workflow). | | |
| Merge GitHub pull request #8 (claude/cool-newton-7nm8r9): Docker deployments on g1t.page behind a switch that stays off until Cloudflare's container APIs are checked live, workflows a workspace manages in its repositories, tarball and zipball downloads, refs/pull/* kept to g1t alone, framework detection for g1t.page builds, and a workflow's event payload matching GitHub's. | 320 | | [`g1t/detect@v1`](https://g1t.sh/g1t/detect) | Says what that build would find (`kind`, `install`, `build`, `output-dir`, `framework`) without building anything. | |
| Merge branch 'worktree-agent-a4d35ee70c50683d0' into claude/cool-newton-7nm8r9 | 321 | |
| Merge workspace aliases through Actions and tokens: uses: g1t/deploy@v1 resolves to flagon-io/deploy, a token scoped to a repository reaches it under the alias, a g1t/ action is never taken from GitHub, and the Actions release creates g1t's action repositories when they are missing. | 322 | g1t's reusable workflows are in `g1t/workflows` the same way, such as |
| 323 | `g1t/workflows/.g1t/workflows/deploy.yml@v1`, which a | |
| 324 | [project's](/guides/projects/) deployments run. | |
| 325 | ||
| 326 | A `g1t/` name always means g1t's own: it answers even where GitHub has a | |
| 327 | repository of the same name, only its public repositories answer for it, | |
| 328 | and a `g1t/` name that is not one of them fails rather than being looked | |
| 329 | for on GitHub. | |
| 330 | ||
| 331 | Both actions are composite actions around `g1t-runner`, which g1t's machines | |
| Merge branch 'worktree-agent-a4d35ee70c50683d0' into claude/cool-newton-7nm8r9 | 332 | have; on a [self-hosted runner](/guides/self-hosted-runners/) they use |
| 333 | the one on `PATH` or download the newest release. | |
| 334 | ||
| Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts | 335 | ### Secrets for a called workflow |
| 336 | ||
| 337 | A called workflow gets only the secrets its caller passes, plus | |
| 338 | `G1T_TOKEN` (`GITHUB_TOKEN`): | |
| 339 | ||
| 340 | ```yaml | |
| 341 | jobs: | |
| 342 | build: | |
| 343 | uses: acme/shared/.g1t/workflows/build.yml@v2 | |
| 344 | with: | |
| 345 | node-version: 24 | |
| 346 | secrets: | |
| 347 | npm-token: ${{ secrets.NPM_TOKEN }} | |
| 348 | ||
| 349 | deploy: | |
| 350 | uses: ./.g1t/workflows/deploy.yml | |
| 351 | secrets: inherit | |
| 352 | ``` | |
| 353 | ||
| 354 | - `secrets:` with names passes each as the called workflow names it, | |
| 355 | read from the caller's `secrets`, `needs`, `inputs`, `matrix`, | |
| 356 | `github` and `vars`. | |
| 357 | - `secrets: inherit` passes every secret the caller has. | |
| 358 | - A job in the called workflow with its own `environment:` also reads that | |
| 359 | environment's secrets, over what was passed. | |
| 360 | - A secret the called workflow marks `required: true` under | |
| 361 | `on.workflow_call.secrets` that the caller does not pass fails the | |
| 362 | calling job before anything runs. | |
| 363 | ||
| 364 | `vars` are the calling repository's, and a called workflow's jobs run | |
| 365 | with the calling run's `github` context: `actions/checkout` checks out the | |
| 366 | calling repository. | |
| 367 | ||
| Merge branch 'worktree-agent-af75396ad4c6ee7a8' into claude/cool-newton-7nm8r9 | 368 | A secret passed by name that the called workflow does not declare under |
| 369 | `on.workflow_call.secrets` fails the calling job: `Invalid secret: … is | |
| 370 | not defined in …`. | |
| 371 | ||
| 372 | ### Inputs for a called workflow | |
| 373 | ||
| 374 | The values under `with:` are checked against the `type` each input has | |
| 375 | under `on.workflow_call.inputs`, before anything runs: | |
| 376 | ||
| 377 | - A `boolean` input takes `true` or `false`, and a `number` input a | |
| 378 | number. Text such as `'true'` or a job's output (outputs are always | |
| 379 | text) fails the calling job: pass `${{ fromJSON(needs.build.outputs.count) }}` | |
| 380 | to give its value. | |
| 381 | - A `string` input takes text; a number or a boolean becomes its text. | |
| 382 | - An input you leave out takes its `default`, else `false`, `0` or `''` | |
| 383 | by its type. A `required: true` input you leave out fails the calling | |
| 384 | job. | |
| 385 | - A name under `with:` that the called workflow does not declare fails the | |
| 386 | calling job: `Invalid input: … is not defined in …`. | |
| 387 | ||
| 388 | ### A matrix of calls | |
| 389 | ||
| 390 | A job that calls a reusable workflow may have a `strategy`. Each | |
| 391 | combination of its matrix calls the workflow once, with `matrix` read in | |
| 392 | `with:` and `secrets:`: | |
| 393 | ||
| 394 | ```yaml | |
| 395 | jobs: | |
| 396 | test: | |
| 397 | strategy: | |
| 398 | matrix: | |
| 399 | node: [20, 22] | |
| 400 | max-parallel: 1 | |
| 401 | uses: ./.g1t/workflows/test.yml | |
| 402 | with: | |
| 403 | node-version: ${{ matrix.node }} | |
| 404 | ``` | |
| 405 | ||
| 406 | The called workflow's jobs are named under the combination's call: | |
| 407 | `test (20) / unit`, `test (22) / unit`. `max-parallel` limits how many | |
| 408 | calls run at a time, and with `fail-fast` (the default) a call that fails | |
| 409 | cancels the calls still running or waiting. `concurrency` on the calling | |
| 410 | job holds its group while the called workflow runs, as a job's own does. | |
| 411 | ||
| 412 | A run connects at most ten levels of workflows: the workflow it started | |
| 413 | from and nine levels of reusable workflows below it. It calls at most 50 | |
| 414 | different reusable workflows; a workflow called again, as by each | |
| 415 | combination of a matrix, counts once. A call past either limit fails the | |
| 416 | calling job and says why. | |
| 417 | ||
| Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts | 418 | ## Releases |
| 419 | ||
| 420 | Workflows with `on: release` start when a release changes, at the commit | |
| 421 | its tag names (`GITHUB_REF` is `refs/tags/<tag>`). Each change is one or | |
| 422 | more activity types, which `types:` chooses among: | |
| 423 | ||
| 424 | | Change | Activity types | | |
| 425 | | --- | --- | | |
| 426 | | A draft made | `created` | | |
| 427 | | A release made and published | `created`, `published`, and `released` (or `prereleased` for a prerelease) | | |
| 428 | | A draft published | `published`, and `released` or `prereleased` | | |
| 429 | | A prerelease made a full release | `edited` and `released` | | |
| 430 | | Made a draft again | `unpublished` | | |
| 431 | | Title, notes or prerelease changed | `edited`, with `github.event.changes` holding the old title and notes | | |
| 432 | | Deleted (the tag stays) | `deleted` | | |
| 433 | ||
| 434 | ```yaml | |
| 435 | on: | |
| 436 | release: | |
| 437 | types: [published] | |
| 438 | ``` | |
| 439 | ||
| 440 | `github.event.release` has `tag_name`, `name`, `body`, `draft`, | |
| 441 | `prerelease`, `target_commitish`, `author` and `html_url`. A release a | |
| 442 | job's own token makes or changes starts no workflows. | |
| 443 | ||
| 444 | ## Deployments | |
| 445 | ||
| 446 | `on: deployment` starts when a deployment is made, and | |
| 447 | `on: deployment_status` when one has a new status: one reported through | |
| 448 | the [deployments API](/guides/deployments-api/) or a | |
| 449 | [g1t.page](/guides/deployments/) build. The run is at the commit deployed; | |
| 450 | `GITHUB_REF` is the branch or tag deployed, and empty for a bare commit. | |
| 451 | ||
| 452 | ```yaml | |
| 453 | on: deployment_status | |
| 454 | ||
| 455 | jobs: | |
| 456 | smoke: | |
| 457 | if: github.event.deployment_status.state == 'success' | |
| 458 | runs-on: ubuntu-latest | |
| 459 | steps: | |
| 460 | - run: curl -fsS "${{ github.event.deployment_status.environment_url }}" | |
| 461 | ``` | |
| 462 | ||
| 463 | `github.event.deployment` has `environment`, `ref`, `sha`, `task` and | |
| 464 | `payload`; `github.event.deployment_status` has `state`, `environment_url` | |
| 465 | and `log_url`. Deployments a workflow makes, with `environment:` or with | |
| 466 | its job's token, start no workflows, so a workflow cannot set itself off. | |
| 467 | ||
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 468 | ## The runner |
| 469 | ||
| 470 | Jobs run in a fresh sandbox each: Debian with Node 24, Python 3, Go, Rust, | |
| Merge runner image: Java 21, .NET 8, Ruby 3.3 | 471 | Java 21, .NET 8, Ruby 3.3, `build-essential`, `git`, `curl`, `jq`, Docker |
| 472 | (with Buildx and Compose) and passwordless `sudo`, in GitHub's layout | |
| Merge branch 'worktree-agent-a41ebf64a05c894fe' into claude/cool-newton-7nm8r9 | 473 | (`/home/runner/work`, `RUNNER_WORKSPACE`, `RUNNER_TEMP`, `RUNNER_TOOL_CACHE`). |
| 474 | `runner.os` is `Linux`. Each step's `GITHUB_ACTION` is its `id`, or | |
| 475 | GitHub's name for it: `__run`, `__run_2` and on for `run:` steps, | |
| 476 | `__actions_checkout` for `uses: actions/checkout`. `ImageOS` and | |
| 477 | `ImageVersion` are set when the machine's image sets them. `ubuntu-latest`, `ubuntu-24.04` and other Linux | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 478 | labels all run here. A job whose `runs-on` names `self-hosted` waits for one |
| 479 | of your [self-hosted runners](/guides/self-hosted-runners/) instead. Setup actions such as | |
| 480 | `actions/setup-node` and `actions/setup-python` install other versions as | |
| 481 | they do on GitHub. | |
| 482 | ||
| Merge runner image: Java 21, .NET 8, Ruby 3.3 | 483 | ### Languages and their setup actions |
| 484 | ||
| 485 | Each language below is on `PATH` from the job's first step, so a workflow | |
| 486 | that only runs `java`, `dotnet` or `ruby` needs no setup step. When it has | |
| 487 | one, the setup action finds the version that is already there and | |
| 488 | downloads nothing. | |
| 489 | ||
| 490 | | Language | Version | Where | Setup action | | |
| 491 | | --- | --- | --- | --- | | |
| 492 | | Java | Eclipse Temurin 21 (LTS), JDK | `JAVA_HOME` (also `JAVA_HOME_21_X64`), in `RUNNER_TOOL_CACHE` | `actions/setup-java` with `distribution: temurin` and `java-version: 21` uses it. Other versions and distributions are downloaded. | | |
| 493 | | .NET | SDK 8 (LTS) | `DOTNET_ROOT`, `/usr/share/dotnet` | `actions/setup-dotnet` with `dotnet-version: 8.0.x` keeps it when it is the newest 8.0 SDK, and installs other SDKs beside it. | | |
| 494 | | Ruby | 3.3, with Bundler | in `RUNNER_TOOL_CACHE` | `ruby/setup-ruby` with `ruby-version: '3.3'` (or a `.ruby-version` naming 3.3) uses it. | | |
| 495 | | Node | 24 | `/usr/local/bin` | `actions/setup-node` installs other versions. | | |
| 496 | | Python | 3.11 | `/usr/bin/python3` | `actions/setup-python` installs other versions. | | |
| 497 | | Go | 1.27 | `/usr/local/go` | `actions/setup-go` installs other versions. | | |
| 498 | | Rust | stable, with `rustfmt`, `clippy` and the `wasm32-unknown-unknown` target | `~/.cargo/bin` | `rustup` is there to add toolchains and targets. | | |
| 499 | ||
| 500 | ```yaml | |
| 501 | steps: | |
| 502 | - uses: actions/checkout@v5 | |
| 503 | - uses: actions/setup-java@v5 | |
| 504 | with: | |
| 505 | distribution: temurin | |
| 506 | java-version: 21 | |
| 507 | - run: ./gradlew build | |
| 508 | ``` | |
| 509 | ||
| 510 | Because the sandbox runs Debian, `ruby/setup-ruby` treats it as a | |
| 511 | self-hosted runner and uses only the Rubies in `RUNNER_TOOL_CACHE`. A version other than 3.3 fails at that step; install | |
| 512 | it in a `run` step instead (for example with `ruby-build`) or run the job | |
| 513 | in a `container:` with the Ruby you need, such as `ruby:3.4`. | |
| 514 | ||
| 515 | The headers that gems and .NET need to build native code (`libyaml`, | |
| 516 | `libffi`, `zlib`, OpenSSL, ICU) are installed too. | |
| 517 | ||
| 518 | ### Calling g1t's API from a job | |
| 519 | ||
| 520 | The `gh` command is not installed: it needs a GraphQL API, and g1t's API | |
| 521 | is REST. Call it with `curl`, using the job's token and the API's address, | |
| 522 | which every job has as `GITHUB_API_URL`: | |
| 523 | ||
| 524 | ```yaml | |
| 525 | - name: Comment on the pull request | |
| 526 | env: | |
| 527 | TOKEN: ${{ github.token }} | |
| 528 | run: | | |
| 529 | curl -fsS -X POST "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/issues/${{ github.event.number }}/comments" \ | |
| 530 | -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ | |
| 531 | -d '{"body": "Built."}' | |
| 532 | ``` | |
| 533 | ||
| 534 | The token reaches this repository and does what the job's `permissions:` | |
| 535 | say; see [the job's token](#the-jobs-token). The | |
| 536 | [API reference](/reference/api/) lists every endpoint. | |
| 537 | ||
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 538 | ### Machine sizes |
| 539 | ||
| 540 | A job runs on the standard machine unless its `runs-on` names a larger | |
| 541 | one: | |
| 542 | ||
| 543 | | `runs-on` | vCPUs | Memory | Disk | | |
| 544 | | --- | --- | --- | --- | | |
| Every sandbox on g1t's runners has 20 GB of disk, the most Cloudflare Containers give one, as much or more than a GitHub-hosted ubuntu-latest's 14 GB: the standard machine (ubuntu-latest and every other hosted label, and all other work) becomes a custom instance type of 1 vCPU, 4 GiB and 20 GB, where standard-1 had half a vCPU and 8 GB, and g1t-2core a custom 2 vCPU, 8 GiB and 20 GB, where standard-3 had 16 GB; g1t-4core stays standard-4, which already had 20 GB. 1 vCPU is the smallest a custom type may have, and Cloudflare bills CPU only as it is used, so the doubled vCPU costs only what a job uses of it. The contracts' instance table, its TypeScript mirror and the billing keeper's standard sandbox say the same sizes; the price scales, worked out as before from Cloudflare's list prices with every vCPU busy and the Durable Object behind each, are now 1.9 for g1t-2core and 3.4 for g1t-4core, against the larger standard machine, and the fallbacks for a sandbox second (33 millionths of a dollar with its vCPU busy) and a build second (16) follow it. A test holds wrangler.jsonc's sizes to the contracts', and another the scales to the list prices. The docs' machine tables, the larger machines' prices and the Cloudflare deploy guide say so. | 545 | | `ubuntu-latest`, or any other Linux label | 1 | 4 GiB | 20 GB | |
| 546 | | `g1t-2core` | 2 | 8 GiB | 20 GB | | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 547 | | `g1t-4core` | 4 | 12 GiB | 20 GB | |
| 548 | ||
| 549 | ```yaml | |
| 550 | jobs: | |
| 551 | build: | |
| 552 | runs-on: g1t-4core | |
| 553 | ``` | |
| 554 | ||
| 555 | The label can come from the matrix or the run's inputs | |
| 556 | (`runs-on: ${{ matrix.big && 'g1t-4core' || 'ubuntu-latest' }}`). A | |
| 557 | larger machine costs what it costs g1t, plus the same margin as all | |
| 558 | sandbox time: see [usage and billing](/guides/usage-and-billing/#workflow-jobs-on-larger-machines). | |
| 559 | Builds that compile, such as Rust or a large TypeScript project, finish | |
| 560 | several times faster on one. | |
| 561 | ||
| 562 | A job on g1t's machines runs for at most 60 minutes, whatever its | |
| What runs differently on g1t's machines is said before it surprises anyone, and four things now behave as on GitHub. A commit whose message says `[skip ci]`, `[ci skip]`, `[no ci]`, `[skip actions]` or `[actions skip]`, or ends with `skip-checks: true`, starts no `push` or `pull_request` workflows. A `pull_request_review` event's `review.state` is `approved` or `changes_requested`, not `approve` or `requestchanges`. A self-hosted job that names no `timeout-minutes` runs for 360 minutes, not 60. A JavaScript action's `::debug::` lines show on a debug run, as `run:` steps' do. The workflow's page now warns when a job asks for more than the 60 minutes g1t's machines give it, when an Arm label will run on x64, and when a matrix on a job that calls a reusable workflow will run it once; it no longer says artifacts are kept up to 60 MB (they are kept up to 5 GiB), nor that `setup-node` with `cache:` runs without its cache (the toolkit's cache works). The desktop release's two hosted jobs ask for the 60 minutes they get. The Actions and self-hosted runners guides say so. | 563 | `timeout-minutes`, and the workflow's page warns about a job that asks |
| 564 | for more. One on a self-hosted runner runs for 360 minutes when it names | |
| 565 | no `timeout-minutes`, as on GitHub, and can ask for up to 24 hours. A job | |
| 566 | stopped at its time cap fails saying so. | |
| 567 | ||
| 568 | g1t's machines are x64. A job whose `runs-on` names an Arm label, such | |
| 569 | as `ubuntu-24.04-arm`, runs on x64, and the workflow's page says so; a | |
| 570 | self-hosted Arm runner runs it on Arm. | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 571 | |
| 572 | ### What a job can reach | |
| 573 | ||
| The docs describe g1t as the place your coding agents work, not as an agent of its own. The guides to g1t's hosted agents are gone: agents, their abilities, access, budgets, memory, routines, sessions and skills, talking to agents, working with g1t, Customize, model providers, the AI Gateway, the context hub, spend, plans and the chat app's agent pages. Each old address redirects to the page that now covers what is left of it. | 574 | A job's network is restricted by its project's |
| 575 | [guardrails](/guides/guardrails/): it reaches the hosts its project's | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 576 | guardrails allow, g1t itself, and what builds need, and nothing else. |
| 577 | What builds need is the package registries (npm, PyPI, crates.io, the Go | |
| 578 | proxy, RubyGems, Packagist, NuGet, Maven and Gradle, Debian's mirrors), | |
| 579 | GitHub, where `uses:` actions and the setup actions' downloads come from, | |
| Merge branch 'main' into actions-toolkit-oidc-artifacts | 580 | the toolchains' download sites (`nodejs.org`, `go.dev`, |
| 581 | `static.rust-lang.org`), and the public container registries (Docker Hub, | |
| 582 | GitHub's, Quay, and `mirror.gcr.io`, the mirror of Docker Hub that a job's | |
| Merge branch 'runner-egress-reset' | 583 | Engine asks first). A request anywhere else gets `403`, and its status |
| 584 | line names the host (`403 Forbidden by g1t guardrails: example.com is not | |
| 585 | an allowed domain`), so even a tool that reports only the status says which | |
| 586 | host to allow. To reach another host, someone with the Maintain [role](/guides/access-and-roles/) or | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 587 | higher adds it to the project's |
| 588 | allowed domains under **Settings → Guardrails**; a project whose guardrails | |
| 589 | turn the network restriction off runs its jobs with an open network. | |
| 590 | ||
| Merge branch 'worktree-agent-af070177ded5baf00' | 591 | A request to an allowed host that fails on the way is handled for the job. |
| 592 | A `GET` or `HEAD` with no body is sent again, twice, after a short wait; one | |
| 593 | that still fails gets `502` with `x-g1t-egress: upstream-failed` and a body | |
| 594 | naming the host and the error, which npm, pip and most tools retry. A | |
| 595 | request with a body is never sent twice. An answer up to 8 MB that breaks | |
| 596 | off partway is fetched again whole, and a larger one, such as a 50 MB | |
| 597 | package tarball, is resumed from where it stopped with a `Range` request | |
| 598 | when its host takes ranges, so the job receives one unbroken answer. | |
| 599 | ||
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 600 | A host only workflows should reach, such as the API a deploy uploads to, |
| 601 | goes in **Workflow-only domains** instead, limited to the workflows and | |
| 602 | environments that need it: `api.cloudflare.com | deploy.yml | production` | |
| 603 | lets only `deploy.yml`'s jobs with `environment: production` reach it. | |
| The docs describe g1t as the place your coding agents work, not as an agent of its own. The guides to g1t's hosted agents are gone: agents, their abilities, access, budgets, memory, routines, sessions and skills, talking to agents, working with g1t, Customize, model providers, the AI Gateway, the context hub, spend, plans and the chat app's agent pages. Each old address redirects to the page that now covers what is left of it. | 604 | Runs of pull requests from forks never reach those hosts. See [workflow-only domains](/guides/guardrails/#workflow-only-domains). |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 605 | |
| Merge brokered secrets: a secret a job uses only to call an API can be tied to the hosts it is for, and the job gets a stand-in in its place, which g1t fills in on the way out to those hosts and nowhere else, so the value never enters the sandbox; and a request to an allowed host that fails upstream is retried when it can be, or answered with a 502 that says why, rather than reset. | 606 | ### Brokered secrets |
| 607 | ||
| 608 | A secret a job uses only to call an API can be brokered: the job gets a | |
| 609 | stand-in (`g1tsec_…`) in place of `${{ secrets.KEY }}`, and g1t puts the | |
| 610 | real value on the job's requests to the hosts the secret names as they | |
| 611 | leave its sandbox, in headers (Basic auth included) and the query string. | |
| 612 | The value never enters the job, so neither its steps nor a compromised | |
| 613 | dependency can read it. A stand-in sent to any other host goes as it is, | |
| 614 | and the log says so once. This works on g1t's machines, whether the | |
| Merge branch 'main' into rm-agents | 615 | project's network is restricted or open, and on self-hosted runners whose |
| 616 | jobs run on Linux or macOS, which pass the job's requests to those hosts | |
| 617 | through g1t so the value never reaches the runner's computer. A job on | |
| 618 | Windows gets the stand-in too, never the value, and its log warns that it | |
| 619 | will not work there yet. A secret the job must read itself (a database | |
| Merge brokered secrets: a secret a job uses only to call an API can be tied to the hosts it is for, and the job gets a stand-in in its place, which g1t fills in on the way out to those hosts and nowhere else, so the value never enters the sandbox; and a request to an allowed host that fails upstream is retried when it can be, or answered with a 502 that says why, rather than reset. | 620 | password over raw TCP, a signing key, a key to files it decrypts) cannot |
| 621 | be brokered. See | |
| 622 | [brokered secrets](/guides/secrets-and-variables/#brokered-secrets). | |
| 623 | ||
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 624 | g1t does not run cryptocurrency miners: a step that names one (`xmrig`, |
| 625 | a `stratum+tcp://` pool, `--donate-level`) is not run, and a job that | |
| 626 | looks like it is mining is stopped. See | |
| 627 | [abuse and mining](/guides/guardrails/#abuse-and-mining). | |
| 628 | ||
| Merge branch 'main' into actions-toolkit-oidc-artifacts | 629 | ## Docker |
| 630 | ||
| 631 | Each job on g1t's machines has a Docker Engine of its own, inside the | |
| 632 | job's sandbox. Nothing runs until the job uses it: the first `docker` | |
| 633 | command, or a job's `services:` or `container:`, starts it, in a second | |
| 634 | or two, and the log says so. It ends with the job, with every image, | |
| 635 | container and build cache in it. No other job, repository or workspace | |
| 636 | ever shares it. | |
| 637 | ||
| 638 | ```yaml | |
| 639 | jobs: | |
| 640 | test: | |
| 641 | runs-on: ubuntu-latest | |
| 642 | services: | |
| 643 | postgres: | |
| 644 | image: postgres:17 | |
| 645 | env: | |
| 646 | POSTGRES_PASSWORD: ${{ secrets.DB_PASSWORD }} | |
| 647 | ports: ["5432:5432"] | |
| 648 | options: >- | |
| 649 | --health-cmd pg_isready --health-interval 5s --health-retries 10 | |
| 650 | steps: | |
| 651 | - uses: actions/checkout@v5 | |
| 652 | - run: docker compose up -d --wait | |
| 653 | - run: npm test | |
| 654 | env: | |
| 655 | DATABASE_URL: postgres://postgres:${{ secrets.DB_PASSWORD }}@localhost:5432/postgres | |
| 656 | ``` | |
| 657 | ||
| 658 | ### What works | |
| 659 | ||
| 660 | | | On g1t's machines | | |
| 661 | | --- | --- | | |
| 662 | | `docker build`, `buildx build`, `run`, `exec`, `pull`, `push`, `login`, `compose` | Work as they do on GitHub's runners. The Engine, Buildx and Compose are current releases. | | |
| 663 | | `services:` | Pulled and started before the first step, with `env`, `ports`, `volumes`, `options` and `credentials`. Services with a health check are waited for; one that turns unhealthy fails the job with its log. Each service's log is printed when the job ends. `job.services.<id>.id`, `.network` and `.ports` are set. | | |
| 664 | | `container:` | Every `run` step and JavaScript action runs inside the image, with its `env`, `options`, `volumes` and `credentials`. The workspace, `RUNNER_TEMP` and the tool cache are mounted at the same paths as on g1t's runner. | | |
| 665 | | `uses: docker://image` | Pulled and run, with `with.args` and `with.entrypoint`. | | |
| 666 | | Docker actions | Built from the action's Dockerfile (or pulled, for `image: docker://…`), and run with its `args`, `env` and `entrypoint`, its inputs as `INPUT_*` variables, and `pre-entrypoint` and `post-entrypoint`. | | |
| 667 | | `docker/setup-buildx-action` | Selects the job's own Engine as the builder (BuildKit). Its `name`, `driver`, `platforms` and `nodes` outputs are set. `driver`, `driver-opts` and `buildkitd-*` are not used, and the log says so. | | |
| 668 | | `docker/build-push-action` | Works, with `push`, `load`, `tags`, `labels`, `build-args`, `secrets`, `target`, `provenance` and `sbom`. | | |
| 669 | | `docker/login-action` | Works, for g1t's registry, Docker Hub, GitHub's registry, Cloudflare's (`registry.cloudflare.com`) and any registry the job can reach. | | |
| 670 | ||
| 671 | ### Services and the network | |
| 672 | ||
| 673 | Every container a job starts shares the job's own network, the one its | |
| 674 | [guardrails](/guides/guardrails/) apply to. So: | |
| 675 | ||
| 676 | - **A service is at `localhost`** on its port, from steps and from other | |
| 677 | containers. `ports: ["5432:5432"]` and `ports: ["5432"]` both mean | |
| 678 | `localhost:5432`. | |
| 679 | - **A port mapped to another number** (`ports: ["6543:5432"]`, or | |
| 680 | `docker run -p 8080:80`) is forwarded: `localhost:6543` reaches the | |
| 681 | service's 5432. `job.services.<id>.ports` says which port to use, and | |
| 682 | `docker inspect` and `docker port` report it. | |
| 683 | - **A service is also reached by its name**, as it is from a job | |
| 684 | container on GitHub: `postgres:5432` works from steps, from the job's | |
| 685 | container and from any container started later. So do the names of | |
| 686 | containers and Compose services, and their network aliases. | |
| 687 | - **Two containers cannot listen on the same port.** A job with a | |
| 688 | `redis` service and a Compose file that starts another Redis on 6379 | |
| 689 | gets an error from the second; give one of them another port. | |
| 690 | ||
| 691 | A container that asks for `--network none` gets none, and | |
| 692 | `--network container:<name>` shares that container's. | |
| 693 | ||
| 694 | ### Job containers | |
| 695 | ||
| 696 | With `container:`, the steps run inside the image as its default user, | |
| 697 | usually `root`. A few things differ from GitHub's runner: | |
| 698 | ||
| 699 | - The workspace is at the same path as on g1t's runner | |
| 700 | (`/home/runner/work/…`), not `/__w`. `github.workspace` is correct | |
| 701 | either way. | |
| 702 | - JavaScript actions run inside the container with g1t's Node 24, which | |
| 703 | needs an image with glibc and `libstdc++` (Debian, Ubuntu and most | |
| 704 | language images have both). In an image without them, such as Alpine, | |
| 705 | they run beside the container, on g1t's runner, with the same files, | |
| 706 | and the log says so. | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' | 707 | - The artifact actions run on g1t's runner, with the same files. |
| Merge branch 'main' into actions-toolkit-oidc-artifacts | 708 | |
| 709 | ### Building and pushing images | |
| 710 | ||
| 711 | On g1t's machines, a job is signed in to g1t's container registry from | |
| 712 | the start, with its own `G1T_TOKEN`, so it can push to and pull from its | |
| Merge packages: roles, Actions access, source label, soft delete, API | 713 | repository's images without a login step; images of other repositories |
| 714 | need this one added under their | |
| 715 | [Manage Actions access](/guides/packages/#manage-actions-access). A run that gets no secrets is | |
| Merge branch 'main' into actions-toolkit-oidc-artifacts | 716 | not signed in. See [container registry](/guides/containers/#in-workflows). |
| 717 | ||
| 718 | ```yaml | |
| 719 | jobs: | |
| 720 | image: | |
| 721 | runs-on: g1t-4core | |
| 722 | steps: | |
| 723 | - uses: actions/checkout@v5 | |
| 724 | - uses: docker/setup-buildx-action@v3 | |
| 725 | - uses: docker/build-push-action@v6 | |
| 726 | with: | |
| 727 | push: true | |
| 728 | tags: g1t.sh/${{ github.repository }}:${{ github.sha }} | |
| 729 | cache-from: type=registry,ref=g1t.sh/${{ github.repository }}:buildcache | |
| 730 | cache-to: type=registry,ref=g1t.sh/${{ github.repository }}:buildcache,mode=max | |
| 731 | ``` | |
| 732 | ||
| 733 | For other registries, sign in with `docker/login-action` or | |
| 734 | `docker login`, as on GitHub. Docker Hub's images are pulled through its | |
| 735 | public mirror first, so jobs are rarely held up by Docker Hub's limits on | |
| 736 | anonymous pulls. | |
| 737 | ||
| 738 | #### Caching image builds | |
| 739 | ||
| 740 | The Engine starts empty in every job, so a build's layers are rebuilt | |
| 741 | unless the job brings a cache: | |
| 742 | ||
| 743 | - **A registry cache** (`cache-to: type=registry,ref=…,mode=max`), in g1t's | |
| 744 | registry or any other, is the simplest and is shared by every branch. | |
| 745 | - **A local cache** (`cache-to: type=local,dest=/tmp/buildx-cache`) saved | |
| 746 | and restored with `actions/cache`, within [the cache's limits](#the-cache). | |
| 747 | - **`type=gha`** is not used on g1t yet: Buildx skips it, and the build | |
| 748 | runs without a cache. | |
| 749 | ||
| 750 | ### Limits | |
| 751 | ||
| 752 | - **Machine.** Containers share the job's machine: its vCPUs, memory and | |
| 753 | disk ([machine sizes](#machine-sizes)). Image builds and databases want | |
| 754 | `g1t-2core` or `g1t-4core`. `--cpus` and `--memory` limit a container | |
| 755 | within that. | |
| 756 | - **Disk.** Images take room on the job's disk. On a machine whose disk | |
| 757 | cannot hold layered images, the Engine stores plain copies, which take | |
| 758 | more room; the log says when it does. | |
| 759 | - **Linux, amd64.** Images for other platforms need QEMU's emulators, | |
| 760 | which g1t's machines do not have set up; `docker/setup-qemu-action` is | |
| 761 | not supported there yet. | |
| 762 | - **Privileged containers** (`--privileged`) run, with no more reach than | |
| 763 | the job itself has: the job's sandbox is the boundary. | |
| 764 | ||
| 765 | ### How Docker is kept safe | |
| 766 | ||
| 767 | - **One Engine per job.** It runs inside the job's own sandbox, a virtual | |
| 768 | machine of its own, and is gone with it. No Docker socket of g1t's, or of | |
| 769 | any machine, is shared with a job. | |
| 770 | - **The job's guardrails hold.** Containers use the job's network, so a | |
| 771 | container, a build step or an image pull reaches only what the job may | |
| 772 | reach. A host off the list gets `403` with the reason, as any step does. | |
| 773 | - **HTTPS keeps working.** In a job whose network is restricted, every | |
| 774 | container and build step is given the certificate the job's HTTPS is | |
| 775 | checked with, in `/dev/g1t-egress`, and `SSL_CERT_FILE`, | |
| 776 | `NODE_EXTRA_CA_CERTS`, `REQUESTS_CA_BUNDLE`, `CURL_CA_BUNDLE`, `PIP_CERT`, | |
| 777 | `GIT_SSL_CAINFO` and `CARGO_HTTP_CAINFO` pointing at it, unless the | |
| 778 | container sets them itself. None of it is written into an image's layers. | |
| 779 | Tools that keep their own list of certificates, such as Java's, need it | |
| 780 | added in the build that uses them. | |
| 781 | - **Short-lived credentials.** The registry sign-in uses the run's own | |
| 782 | token, which ends with the run; `credentials:` for a service or a job | |
| 783 | container are used for that pull only. | |
| 784 | - **No miners.** A container whose image or command names a miner is not | |
| 785 | created, as a step's script is not run. | |
| 786 | ||
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 787 | ## The cache |
| 788 | ||
| 789 | `actions/cache` keeps what a job saves for the repository's later jobs: | |
| 790 | ||
| 791 | | | | | |
| 792 | | --- | --- | | |
| 793 | | One entry | Up to 2 GiB, compressed. A larger one is not saved, and the job goes on. | | |
| 794 | | A repository's entries | Up to 10 GiB together. Saving past it removes the entries restored longest ago. | | |
| Merge main into rm-agents: mirroring removal, open signups, free-tier limits, the g1t CLI and runner fixes, with the agent removal kept. The CLI's table of operations is regenerated from the API without the agent, customize and AI credit operations; no CLI command used them. | 795 | | A free workspace | Its cache and [artifacts](#artifacts), in every repository, up to 2 GiB together. Past it, a save is refused (the job goes on) until old entries expire or artifacts are deleted; on the g1t plan there is no such cap. | |
| Merge branch 'worktree-agent-a63425cb2d4935c5f' | 796 | | How long | Until it has not been restored for 7 days, and at most 28 days after it was saved. A lookup (`lookup-only: true`) counts as a restore. | |
| 797 | | Which branch | An entry belongs to the branch, tag or pull request whose run saved it. A run restores from its own, then from the branch its pull request merges into, then from the default branch. A tag's run reads its own tag's entries and the default branch's, never another tag's. | | |
| 798 | | Keys | Written once on each branch: saving under a key that exists there does nothing, and the step says the key is already cached. On each branch in turn, a restore finds its `key` exactly, else the newest entry whose key starts with its `key`, else the newest whose key starts with each of its `restore-keys` in order. | | |
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 799 | | `path` | Files and folders; globs, `**` included; `~/` is the home folder; a line starting with `!` leaves matching paths out. The same key saved for other paths is another entry. | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 800 | | Compression | zstd. | |
| 801 | ||
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 802 | So a feature branch can read what `main` saved, but `main` never reads |
| 803 | what a feature branch saved, and a pull request from outside the | |
| 804 | repository saves where nothing else ever reads it: nobody can plant an | |
| Merge branch 'worktree-agent-a63425cb2d4935c5f' | 805 | entry that the default branch's builds restore. For the same reason, a |
| 806 | release built from a tag finds only what the default branch saved: have | |
| 807 | a workflow on the default branch save what your releases restore. Actions that cache through the | |
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 808 | toolkit, such as `actions/setup-node` with `cache: npm`, follow the same |
| 809 | rules. | |
| 810 | ||
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 811 | ```yaml |
| 812 | - uses: actions/cache@v4 | |
| 813 | with: | |
| 814 | path: | | |
| 815 | ~/.cargo/registry/cache | |
| 816 | target/release | |
| 817 | !target/**/incremental | |
| 818 | key: cargo-${{ runner.os }}-${{ hashFiles('Cargo.lock') }} | |
| 819 | restore-keys: cargo-${{ runner.os }}- | |
| 820 | ``` | |
| 821 | ||
| 822 | Each restore and save says on the job's log how large the entry was and | |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 823 | how long it took. A workspace on the plan pays for what its caches and |
| 824 | [artifacts](#artifacts) hold (`Actions cache storage` on its statement), | |
| 825 | at R2's price plus the margin; see | |
| 826 | [usage and billing](/guides/usage-and-billing/#actions-cache). | |
| 827 | ||
| Merge branch 'worktree-agent-a3b9b1f730f55b5bf' | 828 | ### Seeing and deleting entries |
| 829 | ||
| 830 | To see what a repository's cache holds against its 10 GiB, and which | |
| 831 | entries take the most: | |
| 832 | ||
| 833 | ```sh | |
| 834 | g1t cache usage | |
| 835 | g1t cache list --sort size-in-bytes --limit 10 | |
| 836 | g1t cache list --key cargo- --ref refs/heads/main | |
| 837 | ``` | |
| 838 | ||
| 839 | Each entry shows its id, key, the ref whose run saved it (a pull request | |
| 840 | from outside the repository saves under `untrusted:<ref>`), its size, and | |
| 841 | when it was saved and last restored. To delete one, or every entry with a | |
| 842 | key (on one ref with `--ref`): | |
| 843 | ||
| 844 | ```sh | |
| 845 | g1t cache delete 9184 | |
| 846 | g1t cache delete cargo-test-Linux-1.99.0-5f1c3a9e7b2d --ref refs/pull/412/merge | |
| 847 | ``` | |
| 848 | ||
| 849 | A deleted entry's bytes go at once, and a run that restores its key finds | |
| 850 | nothing until one saves it again. Listing needs the Read role, deleting | |
| 851 | the Write role. | |
| 852 | ||
| 853 | | `workflow` action | Route | | |
| 854 | | --- | --- | | |
| 855 | | `list_caches` | `GET /repos/{owner}/{repo}/actions/caches`, with `key` (a prefix), `ref`, `sort` (`last_accessed_at`, `created_at` or `size_in_bytes`), `direction`, `page`, `per_page` | | |
| 856 | | `cache_usage` | `GET /repos/{owner}/{repo}/actions/cache/usage`: `active_caches_size_in_bytes`, `active_caches_count`, and `quota_bytes` | | |
| 857 | | `delete_caches` | `DELETE /repos/{owner}/{repo}/actions/caches?key=…`, with `ref`: answers with the entries deleted | | |
| 858 | | `delete_cache` | `DELETE /repos/{owner}/{repo}/actions/caches/{id}`: `204` | | |
| 859 | ||
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 860 | ## Artifacts |
| 861 | ||
| 862 | `actions/upload-artifact` keeps files a job made with its run, for later | |
| 863 | jobs, other runs and people: | |
| 864 | ||
| 865 | | | | | |
| 866 | | --- | --- | | |
| 867 | | One artifact | Up to 5 GiB, zipped. | | |
| 868 | | A run's artifacts | Up to 10 GiB together. | | |
| Merge main into rm-agents: mirroring removal, open signups, free-tier limits, the g1t CLI and runner fixes, with the agent removal kept. The CLI's table of operations is regenerated from the API without the agent, customize and AI credit operations; no CLI command used them. | 869 | | A free workspace | Its artifacts and [cache](#the-cache), in every repository, up to 2 GiB together. Past it, an upload fails and says so, until some expire or are deleted; on the g1t plan there is no such cap. | |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 870 | | How long | The repository's setting: 14 days unless someone with the Maintain role changes it under **Settings → Repository → Artifacts**, from 1 to 90 days. `retention-days` asks for fewer days, never more. | |
| 871 | | Names | One artifact per name in a run. Uploading a name again fails, unless the upload says `overwrite: true`, which replaces it. A name is up to 256 characters, none of `" : < > \| * ? \ /`. | | |
| 872 | | `path` | Files, folders and globs, `**` included; a line starting with `!` leaves matching paths out. Files and folders whose names start with `.` are left out unless `include-hidden-files: true`. | | |
| 873 | | Compression | `compression-level` 0 (stored) to 9; 6 unless you say. | | |
| 874 | | Outputs | `artifact-id` (a number), `artifact-url` (its run's page) and `artifact-digest` (the SHA-256 of its zip). | | |
| 875 | ||
| 876 | ```yaml | |
| 877 | - uses: actions/upload-artifact@v4 | |
| 878 | with: | |
| 879 | name: web-dist | |
| 880 | path: | | |
| 881 | dist/ | |
| 882 | !dist/**/*.map | |
| 883 | retention-days: 5 | |
| 884 | compression-level: 9 | |
| 885 | ``` | |
| 886 | ||
| 887 | `actions/download-artifact` downloads one by `name` into `path`, or every | |
| 888 | artifact of the run, each into a folder of its name; `pattern` picks them | |
| 889 | by name, and `merge-multiple: true` puts them all in one folder. | |
| 890 | `artifact-ids` picks them by number. With `github-token` and `run-id`, it | |
| 891 | downloads from another run of the same repository, such as the one a | |
| 892 | `workflow_run` workflow follows: | |
| 893 | ||
| 894 | ```yaml | |
| 895 | - uses: actions/download-artifact@v4 | |
| 896 | with: | |
| 897 | name: web-dist | |
| 898 | github-token: ${{ secrets.GITHUB_TOKEN }} | |
| 899 | run-id: ${{ github.event.workflow_run.id }} | |
| 900 | ``` | |
| 901 | ||
| 902 | `actions/upload-artifact/merge` downloads the run's artifacts that match | |
| 903 | `pattern`, uploads them as one artifact (`name`, `merged-artifacts` unless | |
| 904 | you say), and deletes them with `delete-merged: true`. | |
| 905 | ||
| A run opens on its summary: what triggered it, its status, duration and artifacts, a graph of its jobs (what needs what, matrices folded, called workflows boxed, deploys with their address), annotations, and each job's summary; the job list groups the same way | 906 | A run's summary lists its artifacts with their size and when they expire. |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 907 | Anyone who can see the run downloads them there; someone with the Write |
| 908 | role can delete one before it expires. | |
| 909 | ||
| 910 | ## Actions built on the toolkit | |
| 911 | ||
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' | 912 | `actions/cache` and many other actions save to the cache with GitHub's |
| 913 | toolkit, `@actions/cache`: `actions/setup-node`, `actions/setup-python`, | |
| 914 | `actions/setup-go` and `actions/setup-java` with `cache:`, | |
| 915 | `Swatinem/rust-cache`, and others. They work on g1t as they are: every job gets `ACTIONS_RUNTIME_TOKEN`, `ACTIONS_CACHE_URL` and | |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 916 | `ACTIONS_RESULTS_URL`, and g1t answers the toolkit's requests from the |
| 917 | repository's cache. | |
| 918 | ||
| 919 | - Their entries are the repository's, under [the cache's](#the-cache) | |
| 920 | limits, and are deleted the same way. | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' | 921 | - An entry is found by its key and by the version the toolkit names for |
| 922 | it, from its paths and compression, as on GitHub: an entry `setup-node` | |
| 923 | saved is restored by `actions/cache` with the same key and paths, and | |
| 924 | the other way round. | |
| Merge branch 'worktree-agent-a63425cb2d4935c5f' | 925 | - Against any server but github.com, the toolkit uses the cache's older |
| 926 | protocol, which sends an entry in 32 MB chunks, so an entry up to the | |
| 927 | cache's 2 GiB is saved. A client of the newer protocol that sends an | |
| 928 | entry whole in one request is held to 100 MB there; past it, the step | |
| 929 | warns and the job goes on. | |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 930 | - The toolkit's artifact library refuses to run against any server but |
| 931 | github.com, so an action that uploads artifacts with it directly fails | |
| 932 | with its own message. `actions/upload-artifact`, | |
| 933 | `actions/download-artifact` and `actions/upload-artifact/merge` work: | |
| 934 | g1t runs those itself. | |
| 935 | ||
| Merge branch 'worktree-agent-a41ebf64a05c894fe' into claude/cool-newton-7nm8r9 | 936 | ## An action's pre and post |
| 937 | ||
| 938 | A JavaScript action's `pre` runs before the job's first step, as on | |
| 939 | GitHub: each one is a step of its own, *Pre* and the step's name, in the | |
| 940 | order of the steps, when its `pre-if` holds (`always()` when it has | |
| 941 | none). Its `post` runs after the last step, *Post* and the step's name, | |
| 942 | last first. What `pre` saves with `GITHUB_STATE` or `::save-state::` | |
| 943 | reaches the step's main as `STATE_<name>`, and what either saves reaches | |
| 944 | `post`. | |
| 945 | ||
| 946 | An action in your repository (`uses: ./…`) is not checked out when the | |
| 947 | job starts, so its `pre` is not run and the step warns, as on GitHub. An | |
| 948 | action inside a composite action runs its `pre` right before its main. | |
| 949 | ||
| 950 | A step that gives an input the action does not declare is warned of: | |
| 951 | *Unexpected input(s) 'foo', valid inputs are ['token', 'path']*. The | |
| 952 | step still runs. | |
| 953 | ||
| 954 | ## Problem matchers | |
| 955 | ||
| 956 | `::add-matcher::path/to/matcher.json` adds the matchers in a file of | |
| 957 | GitHub's format, and they read every line of output from then on, for | |
| 958 | the rest of the job. A line one matches becomes an error, warning or | |
| 959 | notice annotation, with the file, line, column and message it found, in | |
| 960 | place of the line in the log. | |
| 961 | ||
| 962 | ```json | |
| 963 | { | |
| 964 | "problemMatcher": [ | |
| 965 | { | |
| 966 | "owner": "my-linter", | |
| 967 | "pattern": [ | |
| 968 | { | |
| 969 | "regexp": "^(.+):(\\d+):(\\d+): (error|warning) (.*)$", | |
| 970 | "file": 1, "line": 2, "column": 3, "severity": 4, "message": 5 | |
| 971 | } | |
| 972 | ] | |
| 973 | } | |
| 974 | ] | |
| 975 | } | |
| 976 | ``` | |
| 977 | ||
| 978 | - A pattern of several lines matches them in order. The last one can | |
| 979 | set `loop` to match each issue after a header line, as ESLint's | |
| 980 | stylish output has. | |
| 981 | - `severity` is the matcher's own default, `error` when it gives none. | |
| 982 | A severity other than `error`, `warning` or `notice` is no annotation. | |
| 983 | - A file is kept when it exists in a repository in the workspace, as a | |
| 984 | path inside it; `fromPath` names the file a relative path is from. | |
| 985 | - A matcher added with an owner already there takes its place. | |
| 986 | `::remove-matcher owner=my-linter::` removes it. | |
| 987 | - Patterns are regular expressions as Rust's `regex` reads them, which | |
| 988 | has no lookaround or backreferences. A file whose patterns do not | |
| 989 | read is refused, with an error in the log. | |
| 990 | ||
| 991 | `::echo::on` shows each workflow command in the log as it is read, | |
| 992 | until `::echo::off`; with [debug logging](#debug-logging) they are shown | |
| 993 | from the start. | |
| 994 | ||
| Merge remote-tracking branch 'origin/main' into workspace-chat | 995 | ## Caching Rust builds |
| 996 | ||
| 997 | A checkout gives every file a new modification time, so Cargo compiles | |
| 998 | your workspace's own crates again even when `target/` was restored from | |
| 999 | the cache. [sccache](https://github.com/mozilla/sccache) caches each | |
| 1000 | compiler call by what it compiles (the source, the flags, the toolchain | |
| 1001 | and the dependencies), so a crate that did not change comes back from the | |
| 1002 | cache instead. Its GitHub Actions backend works on g1t as it is: it keeps | |
| 1003 | its entries in the repository's cache, under [the cache's](#the-cache) | |
| 1004 | limits and branch rules. | |
| 1005 | ||
| 1006 | 1. Install sccache, pinned to a release and checked against its checksum. | |
| 1007 | 2. Set `RUSTC_WRAPPER: sccache` and `SCCACHE_GHA_ENABLED: "true"`. The | |
| 1008 | job's `ACTIONS_RUNTIME_TOKEN` and `ACTIONS_CACHE_URL` are already in | |
| 1009 | every step's environment; no step needs to export them. | |
| 1010 | 3. Set `CARGO_INCREMENTAL: "0"`: sccache does not cache incremental | |
| 1011 | builds, and a fresh checkout gains nothing from them. | |
| 1012 | ||
| 1013 | ```yaml | |
| 1014 | name: CI | |
| 1015 | on: | |
| 1016 | pull_request: | |
| 1017 | push: | |
| 1018 | branches: [main] | |
| 1019 | ||
| 1020 | jobs: | |
| 1021 | test: | |
| 1022 | runs-on: ubuntu-latest | |
| 1023 | env: | |
| 1024 | RUSTC_WRAPPER: sccache | |
| 1025 | SCCACHE_GHA_ENABLED: "true" | |
| 1026 | CARGO_INCREMENTAL: "0" | |
| 1027 | steps: | |
| 1028 | - uses: actions/checkout@v5 | |
| 1029 | - name: Install sccache | |
| 1030 | env: | |
| 1031 | VERSION: v0.18.0 | |
| 1032 | SHA256: 45f1447fbe231e3037bde351ef70677dd212216c8d62ae7ca409fecc4d6acc89 | |
| 1033 | run: | | |
| 1034 | name="sccache-$VERSION-x86_64-unknown-linux-musl" | |
| 1035 | curl -fsSL -o "$RUNNER_TEMP/sccache.tar.gz" \ | |
| 1036 | "https://github.com/mozilla/sccache/releases/download/$VERSION/$name.tar.gz" | |
| 1037 | echo "$SHA256 $RUNNER_TEMP/sccache.tar.gz" | sha256sum -c - | |
| 1038 | tar -xzf "$RUNNER_TEMP/sccache.tar.gz" -C "$RUNNER_TEMP" | |
| 1039 | install -m 0755 "$RUNNER_TEMP/$name/sccache" "$HOME/.cargo/bin/sccache" | |
| 1040 | - run: cargo test --workspace --locked | |
| 1041 | - name: sccache's hits and misses | |
| 1042 | if: always() | |
| 1043 | run: | | |
| 1044 | echo '```' >> "$GITHUB_STEP_SUMMARY" | |
| 1045 | sccache --show-stats | tee -a "$GITHUB_STEP_SUMMARY" | |
| 1046 | echo '```' >> "$GITHUB_STEP_SUMMARY" | |
| 1047 | ``` | |
| 1048 | ||
| 1049 | What to expect: | |
| 1050 | ||
| 1051 | | | | | |
| 1052 | | --- | --- | | |
| 1053 | | What is cached | Every library crate (`rlib`): your workspace's crates and their dependencies. | | |
| 1054 | | What is compiled each time | What rustc links: binaries, `cdylib` crates, proc macros, build scripts and test harnesses. | | |
| 1055 | | Its entries | One per compiled crate, often thousands for a workspace, each a few KB to a few MB. They count toward the repository's 10 GiB like any other entry, and the ones not restored for 7 days are deleted. | | |
| 1056 | | Branches | A pull request reads what the default branch saved. Run the workflow on pushes to the default branch too, as above, or each pull request's first run starts with an empty cache. | | |
| Merge branch 'worktree-agent-a3b9b1f730f55b5bf' | 1057 | | Releases from tags | A tag's run reads the default branch's entries, but what it saves only that tag would ever read. Set `SCCACHE_GHA_RW_MODE: READ_ONLY` on a tag's run (`if [ "$GITHUB_REF_TYPE" = tag ]`) so it saves nothing: it still looks every crate up. | |
| Merge remote-tracking branch 'origin/main' into workspace-chat | 1058 | | Starting over | Set `SCCACHE_GHA_VERSION` to any new value. A new sccache release starts over by itself. | |
| 1059 | | If the cache cannot be reached | sccache refuses to start. Set `SCCACHE_IGNORE_SERVER_IO_ERROR: "1"` to have rustc run without it instead. | | |
| 1060 | ||
| 1061 | sccache adds to `actions/cache` rather than replacing it: keep caching | |
| 1062 | `~/.cargo/registry/cache` and `target/` keyed by `Cargo.lock`, so Cargo | |
| 1063 | does not call rustc at all for dependencies that did not change, and | |
| 1064 | sccache answers the calls it still makes for your own crates. | |
| 1065 | `Swatinem/rust-cache` works the same way. | |
| 1066 | ||
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 1067 | ## OIDC tokens |
| 1068 | ||
| 1069 | A job can prove which repository, branch and environment it runs for with | |
| 1070 | a short-lived OpenID Connect token signed by g1t, and trade it for a cloud | |
| 1071 | provider's credentials. Nothing long-lived needs to sit in a secret. | |
| 1072 | ||
| 1073 | 1. Give the job, or the workflow, `permissions: id-token: write`. A job | |
| 1074 | without it gets no token, and neither does a run of a pull request from | |
| 1075 | outside the repository. | |
| 1076 | 2. Tell your cloud to trust g1t's issuer for your repository (below). | |
| 1077 | 3. Use the provider's own login action, which asks for the token. | |
| 1078 | ||
| 1079 | ```yaml | |
| 1080 | permissions: | |
| 1081 | id-token: write | |
| 1082 | contents: read | |
| 1083 | ||
| 1084 | jobs: | |
| 1085 | deploy: | |
| 1086 | runs-on: ubuntu-latest | |
| 1087 | environment: production | |
| 1088 | steps: | |
| 1089 | - uses: aws-actions/configure-aws-credentials@v4 | |
| 1090 | with: | |
| 1091 | role-to-assume: arn:aws:iam::123456789012:role/acme-web-deploy | |
| 1092 | aws-region: us-east-1 | |
| 1093 | ``` | |
| 1094 | ||
| 1095 | The job gets `ACTIONS_ID_TOKEN_REQUEST_URL` and | |
| 1096 | `ACTIONS_ID_TOKEN_REQUEST_TOKEN`, which `core.getIDToken()` reads. To ask | |
| 1097 | for a token yourself, name its audience: | |
| 1098 | ||
| 1099 | ```sh | |
| 1100 | curl -sS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ | |
| 1101 | "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://deploy.example.com" | jq -r .value | |
| 1102 | ``` | |
| 1103 | ||
| 1104 | | | | | |
| 1105 | | --- | --- | | |
| 1106 | | Issuer | `https://api.g1t.sh/actions/oidc` | | |
| 1107 | | Discovery | `https://api.g1t.sh/actions/oidc/.well-known/openid-configuration` | | |
| 1108 | | Keys | `https://api.g1t.sh/actions/oidc/.well-known/jwks`, RS256, each with its `kid` | | |
| 1109 | | Lifetime | 5 minutes | | |
| 1110 | | Audience | What the job asks for; `https://g1t.sh/<owner>` when it asks for none | | |
| 1111 | ||
| Merge the OIDC docs: deploying to AWS, Google Cloud or Azure with a job's short-lived identity token now says which of the cloud's hosts to allow under Workflow-only domains, for the deploying workflow and environment, since a job on g1t's machines reaches only the hosts its project allows; and tests for the audience a job asks for and for the token variables reaching each step. | 1112 | A job without `id-token: write` has no `ACTIONS_ID_TOKEN_REQUEST_URL`, so |
| 1113 | a login action says it cannot find one; a token asked for anyway is | |
| 1114 | refused with `403` and `This job has no OIDC token`. | |
| 1115 | ||
| 1116 | ### Reaching your cloud | |
| 1117 | ||
| 1118 | Asking for the token goes to `api.g1t.sh`, which every job reaches. Trading | |
| 1119 | it for credentials goes to your cloud's token service, which a job reaches | |
| 1120 | only when its project allows it (see [what a job can reach](#what-a-job-can-reach)). | |
| 1121 | Add the hosts under **Settings → Guardrails → Workflow-only domains**, | |
| The docs describe g1t as the place your coding agents work, not as an agent of its own. The guides to g1t's hosted agents are gone: agents, their abilities, access, budgets, memory, routines, sessions and skills, talking to agents, working with g1t, Customize, model providers, the AI Gateway, the context hub, spend, plans and the chat app's agent pages. Each old address redirects to the page that now covers what is left of it. | 1122 | limited to the workflow and environment that deploy, so other workflows |
| 1123 | never reach them: | |
| Merge the OIDC docs: deploying to AWS, Google Cloud or Azure with a job's short-lived identity token now says which of the cloud's hosts to allow under Workflow-only domains, for the deploying workflow and environment, since a job on g1t's machines reaches only the hosts its project allows; and tests for the audience a job asks for and for the token variables reaching each step. | 1124 | |
| 1125 | ```text | |
| 1126 | sts.us-east-1.amazonaws.com | deploy.yml | production | |
| 1127 | s3.us-east-1.amazonaws.com | deploy.yml | production | |
| 1128 | sts.googleapis.com | deploy.yml | production | |
| 1129 | iamcredentials.googleapis.com | deploy.yml | production | |
| 1130 | login.microsoftonline.com | deploy.yml | production | |
| 1131 | management.azure.com | deploy.yml | production | |
| 1132 | ``` | |
| 1133 | ||
| 1134 | | Cloud | Token exchange | Then | | |
| 1135 | | --- | --- | --- | | |
| 1136 | | AWS | `sts.<region>.amazonaws.com`, the region `aws-region` names | Each service the job uses, such as `s3.<region>.amazonaws.com`, or `*.amazonaws.com` for all of them | | |
| 1137 | | Google Cloud | `sts.googleapis.com`, `iamcredentials.googleapis.com` | Each API the job uses, such as `run.googleapis.com` | | |
| 1138 | | Azure | `login.microsoftonline.com` | `management.azure.com`, and each service the job uses | | |
| 1139 | ||
| 1140 | Without them, the login step fails with `403` and a line naming the host | |
| 1141 | that is not allowed. | |
| 1142 | ||
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 1143 | ### Claims |
| 1144 | ||
| 1145 | Each token carries the claims GitHub's do, so trust policies written for | |
| 1146 | those read g1t's the same way. | |
| 1147 | ||
| 1148 | | Claim | Example | | |
| 1149 | | --- | --- | | |
| 1150 | | `sub` | `repo:acme/web:environment:production` for a job with an `environment:`; `repo:acme/web:pull_request` for a pull request's run; otherwise `repo:acme/web:ref:refs/heads/main` (or `refs/tags/v1.2.0`) | | |
| 1151 | | `repository`, `repository_owner` | `acme/web`, `acme` | | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' | 1152 | | `repository_id`, `repository_owner_id` | g1t's ids for them, such as `rep_01kpw0…` (not the numbers `github.repository_id` and `github.repository_owner_id` give, so trust policies already written keep matching) | |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 1153 | | `repository_visibility` | `public` or `private` | |
| 1154 | | `ref`, `ref_type`, `ref_protected`, `sha` | `refs/heads/main`, `branch`, `"true"`, the commit | | |
| 1155 | | `head_ref`, `base_ref` | A pull request's branches | | |
| 1156 | | `environment` | The job's environment, when it has one | | |
| 1157 | | `event_name` | `push`, `pull_request`, `workflow_dispatch`, … | | |
| 1158 | | `workflow`, `workflow_ref`, `workflow_sha` | `Deploy`, `acme/web/.g1t/workflows/deploy.yml@refs/heads/main`, the commit | | |
| 1159 | | `job_workflow_ref`, `job_workflow_sha` | The workflow that defines the job: a called workflow's own file | | |
| 1160 | | `run_id`, `run_number`, `run_attempt` | `run_01kq9c…`, `"12"`, `"1"` | | |
| 1161 | | `actor`, `actor_id` | Who started the run | | |
| 1162 | | `runner_environment` | `github-hosted` on g1t's machines, `self-hosted` on yours | | |
| 1163 | | `iss`, `aud`, `jti`, `iat`, `nbf`, `exp` | As in any OIDC token | | |
| 1164 | ||
| 1165 | ### AWS | |
| 1166 | ||
| 1167 | 1. Add g1t as an identity provider, under **IAM → Identity providers**: | |
| 1168 | provider type **OpenID Connect**, provider URL | |
| 1169 | `https://api.g1t.sh/actions/oidc`, audience `sts.amazonaws.com`. Or: | |
| 1170 | ||
| 1171 | ```sh | |
| 1172 | aws iam create-open-id-connect-provider \ | |
| 1173 | --url https://api.g1t.sh/actions/oidc \ | |
| 1174 | --client-id-list sts.amazonaws.com | |
| 1175 | ``` | |
| 1176 | ||
| 1177 | 2. Give the role a trust policy for your repository: | |
| 1178 | ||
| 1179 | ```json | |
| 1180 | { | |
| 1181 | "Version": "2012-10-17", | |
| 1182 | "Statement": [{ | |
| 1183 | "Effect": "Allow", | |
| 1184 | "Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/api.g1t.sh/actions/oidc" }, | |
| 1185 | "Action": "sts:AssumeRoleWithWebIdentity", | |
| 1186 | "Condition": { | |
| 1187 | "StringEquals": { | |
| 1188 | "api.g1t.sh/actions/oidc:aud": "sts.amazonaws.com", | |
| 1189 | "api.g1t.sh/actions/oidc:sub": "repo:acme/web:environment:production" | |
| 1190 | } | |
| 1191 | } | |
| 1192 | }] | |
| 1193 | } | |
| 1194 | ``` | |
| 1195 | ||
| Merge the OIDC docs: deploying to AWS, Google Cloud or Azure with a job's short-lived identity token now says which of the cloud's hosts to allow under Workflow-only domains, for the deploying workflow and environment, since a job on g1t's machines reaches only the hosts its project allows; and tests for the audience a job asks for and for the token variables reaching each step. | 1196 | 3. Allow `sts.<region>.amazonaws.com`, and what the job deploys to, as |
| 1197 | [workflow-only domains](#reaching-your-cloud). | |
| 1198 | 4. Use `aws-actions/configure-aws-credentials@v4` with `role-to-assume`, | |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 1199 | as above. |
| 1200 | ||
| 1201 | ### Google Cloud | |
| 1202 | ||
| 1203 | 1. Make a workload identity pool and a provider for g1t: | |
| 1204 | ||
| 1205 | ```sh | |
| 1206 | gcloud iam workload-identity-pools create g1t --location=global | |
| 1207 | gcloud iam workload-identity-pools providers create-oidc g1t \ | |
| 1208 | --location=global --workload-identity-pool=g1t \ | |
| 1209 | --issuer-uri=https://api.g1t.sh/actions/oidc \ | |
| 1210 | --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository" \ | |
| 1211 | --attribute-condition="assertion.repository_owner == 'acme'" | |
| 1212 | ``` | |
| 1213 | ||
| 1214 | 2. Let the repository act as a service account: | |
| 1215 | ||
| 1216 | ```sh | |
| 1217 | gcloud iam service-accounts add-iam-policy-binding deploy@acme-prod.iam.gserviceaccount.com \ | |
| 1218 | --role=roles/iam.workloadIdentityUser \ | |
| 1219 | --member="principalSet://iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/g1t/attribute.repository/acme/web" | |
| 1220 | ``` | |
| 1221 | ||
| Merge the OIDC docs: deploying to AWS, Google Cloud or Azure with a job's short-lived identity token now says which of the cloud's hosts to allow under Workflow-only domains, for the deploying workflow and environment, since a job on g1t's machines reaches only the hosts its project allows; and tests for the audience a job asks for and for the token variables reaching each step. | 1222 | 3. Allow `sts.googleapis.com` and `iamcredentials.googleapis.com`, and |
| 1223 | the APIs the job uses, as [workflow-only domains](#reaching-your-cloud). | |
| 1224 | 4. Use `google-github-actions/auth@v2` with | |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 1225 | `workload_identity_provider: projects/123456789/locations/global/workloadIdentityPools/g1t/providers/g1t` |
| 1226 | and `service_account`. It asks for the provider's own name as the | |
| 1227 | audience, which the provider accepts unless you change its allowed | |
| 1228 | audiences. | |
| 1229 | ||
| 1230 | ### Azure | |
| 1231 | ||
| 1232 | 1. On the app registration or user-assigned managed identity, add a | |
| 1233 | federated credential with the scenario **Other issuer**: issuer | |
| 1234 | `https://api.g1t.sh/actions/oidc`, subject identifier | |
| 1235 | `repo:acme/web:environment:production`, audience | |
| 1236 | `api://AzureADTokenExchange`. Or: | |
| 1237 | ||
| 1238 | ```sh | |
| 1239 | az ad app federated-credential create --id <application id> --parameters '{ | |
| 1240 | "name": "g1t-acme-web-production", | |
| 1241 | "issuer": "https://api.g1t.sh/actions/oidc", | |
| 1242 | "subject": "repo:acme/web:environment:production", | |
| 1243 | "audiences": ["api://AzureADTokenExchange"] | |
| 1244 | }' | |
| 1245 | ``` | |
| 1246 | ||
| 1247 | 2. Give it a role on what it deploys to, as for any identity. | |
| Merge the OIDC docs: deploying to AWS, Google Cloud or Azure with a job's short-lived identity token now says which of the cloud's hosts to allow under Workflow-only domains, for the deploying workflow and environment, since a job on g1t's machines reaches only the hosts its project allows; and tests for the audience a job asks for and for the token variables reaching each step. | 1248 | 3. Allow `login.microsoftonline.com` and `management.azure.com` as |
| 1249 | [workflow-only domains](#reaching-your-cloud). | |
| 1250 | 4. Use `azure/login@v2` with `client-id`, `tenant-id` and | |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 1251 | `subscription-id`, and no secret. |
| 1252 | ||
| 1253 | A federated credential matches the subject exactly: add one per | |
| 1254 | environment or branch that deploys. | |
| 1255 | ||
| 1256 | ### Cloudflare | |
| 1257 | ||
| 1258 | Cloudflare's API takes API tokens, not OIDC tokens. Keep a token scoped | |
| 1259 | to what the workflow deploys in a secret, available to that workflow only | |
| 1260 | (see [workflow-only domains](/guides/guardrails/#workflow-only-domains) | |
| 1261 | for limiting where it can be sent). | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1262 | |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 1263 | A Worker of your own can trust g1t's jobs directly, by checking the token |
| 1264 | a job sends it against g1t's keys: | |
| 1265 | ||
| 1266 | ```ts | |
| 1267 | import { createRemoteJWKSet, jwtVerify } from "jose"; | |
| 1268 | ||
| 1269 | const keys = createRemoteJWKSet(new URL("https://api.g1t.sh/actions/oidc/.well-known/jwks")); | |
| 1270 | ||
| 1271 | export async function fromG1tJob(request: Request): Promise<boolean> { | |
| 1272 | const token = request.headers.get("authorization")?.replace(/^Bearer /, "") ?? ""; | |
| 1273 | const { payload } = await jwtVerify(token, keys, { | |
| 1274 | issuer: "https://api.g1t.sh/actions/oidc", | |
| 1275 | audience: "https://deploy.example.com", | |
| 1276 | }); | |
| 1277 | return payload.sub === "repo:acme/web:environment:production"; | |
| 1278 | } | |
| 1279 | ``` | |
| 1280 | ||
| 1281 | ### npm | |
| 1282 | ||
| 1283 | npm's trusted publishing and provenance accept OIDC tokens only from the | |
| 1284 | CI services npm lists, and g1t is not one of them yet. Publish with a | |
| 1285 | granular access token in a secret instead: | |
| 1286 | ||
| 1287 | ```yaml | |
| 1288 | - uses: actions/setup-node@v4 | |
| 1289 | with: | |
| 1290 | node-version: 24 | |
| 1291 | registry-url: https://registry.npmjs.org | |
| 1292 | - run: npm publish | |
| 1293 | env: | |
| 1294 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| 1295 | ``` | |
| 1296 | ||
| 1297 | See [What g1t can't do yet](/about/limitations/#no-npm-trusted-publishing-or-provenance). | |
| 1298 | ||
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1299 | ## Runs and logs |
| 1300 | ||
| 1301 | Open a repository's **Actions** page, in its sidebar. Pick a workflow to | |
| 1302 | see its runs, run it by hand if it has `workflow_dispatch`, or turn it off | |
| Merge branch 'worktree-agent-a4db4b523bb973765' | 1303 | without touching its file. From a terminal, [`g1t workflow`](/guides/cli/#workflows) |
| 1304 | does the same. | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1305 | |
| A run opens on its summary: what triggered it, its status, duration and artifacts, a graph of its jobs (what needs what, matrices folded, called workflows boxed, deploys with their address), annotations, and each job's summary; the job list groups the same way | 1306 | A run's page opens on its **Summary**. Its sidebar lists **All jobs**; |
| 1307 | pick one to see its steps and their logs as they are written. Groups | |
| 1308 | fold, errors and warnings are marked, and secrets are replaced with | |
| 1309 | `***`. The page keeps itself up to date while the run goes on. | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1310 | |
| Merge main into rm-agents: mirroring removal, open signups, free-tier limits, the g1t CLI and runner fixes, with the agent removal kept. The CLI's table of operations is regenerated from the API without the agent, customize and AI credit operations; no CLI command used them. | 1311 | A job's log is kept for **90 days** after the job finished. After that its |
| 1312 | lines are deleted; the run, its jobs, their steps and conclusions, | |
| 1313 | annotations, job summaries and artifacts (for their own retention) stay. | |
| 1314 | Download a log you need to keep longer. On an installation of your own, | |
| 1315 | `LOG_RETENTION_DAYS` in the actions service's settings changes the 90 days, | |
| 1316 | and `0` keeps logs for good. | |
| 1317 | ||
| A running job's log is live, as on GitHub. A step's output reaches its run's page within about two seconds: the runner sends what is printed every second, and the page asks every second while a step runs, every three while none does; an answer that fails (a 429, a 5xx, the network) is asked again after a wait that doubles to half a minute, or as long as Retry-After says, where before one such answer stopped the log for good and the step said "No output yet." until the page was reloaded, and a signed-out viewer's run page, refreshing beside its log, ran into the 30-a-minute limit within a minute; the live log now counts as a page, and only log downloads as costly. A hidden tab stops asking and catches up when shown, and the page says when it is reconnecting. The running step opens by itself, its timer counts, its log follows the newest line while its end is on screen and offers Jump to latest once the viewer scrolls up, a step that has printed nothing for a while says "Running · no output for 2m 10s", and the job's header names the step it is on. Colour that tools print (bold, dim, italic, underline, the 16 colours as theme tokens for light and dark, 256 colours and 24-bit colour, text and background) is drawn as printed, other escape codes are dropped and links keep their text, and search reads the plain text and keeps the colours around what it marks. Every line is stamped with the time it was printed, as GitHub's raw logs are, so log.txt and the run's zip have a time at the start of each line, and a clock button beside Search logs shows the times, remembered by the browser. Set up job now gives the runner's version and name, the operating system, the runner image, the machine's architecture, CPUs and memory, the token's permissions under G1T_TOKEN Permissions, the secret source and the actions it downloads; each run step opens with GitHub's folded Run group, the script in cyan, the shell's whole path and the step's env, each uses step with its with inputs (an action's defaults among them) and env; cache and artifact transfers say how far they have got every five seconds; and a last Complete job step sets the job's outputs and stops what the steps left running, found by RUNNER_TRACKING_ID as GitHub's runner finds it. Two batches of a job's log written at once can no longer reach for the same seq and lose one. The Actions guide and the rate limits page say so. | 1318 | ### Live logs |
| 1319 | ||
| 1320 | While a job runs, its log reaches the page within about two seconds of | |
| 1321 | being printed: the runner sends what a step prints every second, and the | |
| 1322 | page asks for more every second while a step is running. | |
| 1323 | ||
| 1324 | - The running step opens by itself, and its timer counts up. Its log | |
| Merge the run page fixes: Cancel run shows on every view of a run that is still going, including an earlier attempt's and job links, and pages refresh when a run is re-run from anywhere; a job's log follows to its true end, above anything covering the bottom of the window, and Jump to latest lands there. | 1325 | follows the newest line while the end of it is on screen, with the last |
| 1326 | line wholly in view (above the tab bar on a phone). Scroll up and it | |
| 1327 | stays where you are, with **Jump to latest** to go back to the end and | |
| 1328 | follow it again. | |
| A running job's log is live, as on GitHub. A step's output reaches its run's page within about two seconds: the runner sends what is printed every second, and the page asks every second while a step runs, every three while none does; an answer that fails (a 429, a 5xx, the network) is asked again after a wait that doubles to half a minute, or as long as Retry-After says, where before one such answer stopped the log for good and the step said "No output yet." until the page was reloaded, and a signed-out viewer's run page, refreshing beside its log, ran into the 30-a-minute limit within a minute; the live log now counts as a page, and only log downloads as costly. A hidden tab stops asking and catches up when shown, and the page says when it is reconnecting. The running step opens by itself, its timer counts, its log follows the newest line while its end is on screen and offers Jump to latest once the viewer scrolls up, a step that has printed nothing for a while says "Running · no output for 2m 10s", and the job's header names the step it is on. Colour that tools print (bold, dim, italic, underline, the 16 colours as theme tokens for light and dark, 256 colours and 24-bit colour, text and background) is drawn as printed, other escape codes are dropped and links keep their text, and search reads the plain text and keeps the colours around what it marks. Every line is stamped with the time it was printed, as GitHub's raw logs are, so log.txt and the run's zip have a time at the start of each line, and a clock button beside Search logs shows the times, remembered by the browser. Set up job now gives the runner's version and name, the operating system, the runner image, the machine's architecture, CPUs and memory, the token's permissions under G1T_TOKEN Permissions, the secret source and the actions it downloads; each run step opens with GitHub's folded Run group, the script in cyan, the shell's whole path and the step's env, each uses step with its with inputs (an action's defaults among them) and env; cache and artifact transfers say how far they have got every five seconds; and a last Complete job step sets the job's outputs and stops what the steps left running, found by RUNNER_TRACKING_ID as GitHub's runner finds it. Two batches of a job's log written at once can no longer reach for the same seq and lose one. The Actions guide and the rate limits page say so. | 1329 | - A step that prints nothing for a while says so under its last line: |
| 1330 | **Running · no output for 2m 10s**, or **no output yet** before its | |
| 1331 | first line. The job's header names the step it is on. | |
| 1332 | - Colour that tools print is shown as they print it: bold, dim, italic, | |
| 1333 | underline, the 16 terminal colours, 256 colours and 24-bit colour, for | |
| 1334 | text and background, in both the light and the dark theme. Tools built | |
| 1335 | on chalk or supports-color colour their output because the job has | |
| 1336 | `GITHUB_ACTIONS=true`, as on GitHub; others need asking, such as | |
| 1337 | `CARGO_TERM_COLOR: always` in the step's `env` for cargo. Other escape codes (moving the cursor, clearing a | |
| 1338 | line) are left out, and a link keeps its text. Search reads the text | |
| 1339 | without the colour codes. | |
| 1340 | - Every line is stamped with the time it was printed, as GitHub stamps | |
| 1341 | it (`2026-10-12T09:41:07.1234567Z`). The clock button beside **Search | |
| 1342 | logs** shows or hides the times; your browser remembers which. | |
| 1343 | - A download (the job's `log.txt` and the run's zip) has the time at the | |
| 1344 | start of every line, as GitHub's downloaded logs do. | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' | 1345 | - Each line's number links to it, as on GitHub: `#step:3:12` is line 12 |
| 1346 | of step 3 (0 is **Set up job**). Opening the link opens the step and | |
| 1347 | any group the line is in, scrolls to the line and marks it. | |
| 1348 | - A long step's log stays fast. Each new piece of a running step's log is | |
| 1349 | read once as it arrives, and a step of more than 2,000 lines draws only | |
| 1350 | the lines on screen and a few around them. Search, groups, line links, | |
| 1351 | following the newest line and **Jump to latest** work as they do on a | |
| 1352 | short log. Your browser's own find (Ctrl+F) only sees the lines that are | |
| 1353 | drawn, so use **Search logs** in a long log. | |
| 1354 | - The runner numbers each batch of the log it sends. When it sends a | |
| 1355 | batch again because g1t's answer didn't reach it, g1t keeps the batch | |
| 1356 | once, so a line never shows twice. | |
| A running job's log is live, as on GitHub. A step's output reaches its run's page within about two seconds: the runner sends what is printed every second, and the page asks every second while a step runs, every three while none does; an answer that fails (a 429, a 5xx, the network) is asked again after a wait that doubles to half a minute, or as long as Retry-After says, where before one such answer stopped the log for good and the step said "No output yet." until the page was reloaded, and a signed-out viewer's run page, refreshing beside its log, ran into the 30-a-minute limit within a minute; the live log now counts as a page, and only log downloads as costly. A hidden tab stops asking and catches up when shown, and the page says when it is reconnecting. The running step opens by itself, its timer counts, its log follows the newest line while its end is on screen and offers Jump to latest once the viewer scrolls up, a step that has printed nothing for a while says "Running · no output for 2m 10s", and the job's header names the step it is on. Colour that tools print (bold, dim, italic, underline, the 16 colours as theme tokens for light and dark, 256 colours and 24-bit colour, text and background) is drawn as printed, other escape codes are dropped and links keep their text, and search reads the plain text and keeps the colours around what it marks. Every line is stamped with the time it was printed, as GitHub's raw logs are, so log.txt and the run's zip have a time at the start of each line, and a clock button beside Search logs shows the times, remembered by the browser. Set up job now gives the runner's version and name, the operating system, the runner image, the machine's architecture, CPUs and memory, the token's permissions under G1T_TOKEN Permissions, the secret source and the actions it downloads; each run step opens with GitHub's folded Run group, the script in cyan, the shell's whole path and the step's env, each uses step with its with inputs (an action's defaults among them) and env; cache and artifact transfers say how far they have got every five seconds; and a last Complete job step sets the job's outputs and stops what the steps left running, found by RUNNER_TRACKING_ID as GitHub's runner finds it. Two batches of a job's log written at once can no longer reach for the same seq and lose one. The Actions guide and the rate limits page say so. | 1357 | - If the page cannot reach g1t for a moment, it says **Reconnecting to the |
| 1358 | log** and tries again, waiting longer each time up to half a minute. | |
| 1359 | A tab you are not looking at stops asking, and catches up when you come | |
| 1360 | back to it. | |
| 1361 | ||
| 1362 | A cache restore, an artifact upload or download, and other transfers say | |
| 1363 | how far they have got every few seconds | |
| 1364 | (`Received 46137344 of 523190823 (8.8%), 43.9 MBs/sec`). | |
| 1365 | ||
| 1366 | A [self-hosted runner](/guides/self-hosted-runners/) stamps its lines and | |
| 1367 | writes these headers once it has updated itself to a release that does; | |
| 1368 | until then its logs show without times. | |
| 1369 | ||
| 1370 | ### What a job's log says | |
| 1371 | ||
| 1372 | Each job's log reads as GitHub's does: | |
| 1373 | ||
| 1374 | | Step | What it shows | | |
| 1375 | | --- | --- | | |
| 1376 | | **Set up job** | The runner's version and name; the operating system; the runner image (`ImageOS` and `ImageVersion` when the machine's image sets them, and the software g1t's machines have); the machine (hosted or self-hosted, its architecture, CPUs and memory); what the job's [token](#the-jobs-token) may do, under **G1T_TOKEN Permissions**; the secret source; each action the job uses as it is downloaded, with the commit it resolved to (`Download action repository 'actions/setup-node@v4' (SHA:…)`); and the job's matrix. | | |
| 1377 | | A `run:` step | A folded group, `Run` and the script's first line, holding the whole script, the shell it ran in (`shell: /usr/bin/bash -e {0}`) and its variables under `env:`, secrets masked. Then what it printed. | | |
| 1378 | | A `uses:` step | A folded group, `Run owner/repo@ref`, holding its inputs under `with:` (an action's defaults among them) and its variables under `env:`. | | |
| 1379 | | **Post** steps and **Stop containers** | An action's `post`, saving the cache, then the job's containers stopped, as on GitHub. | | |
| 1380 | | **Complete job** | The job's outputs as they are set (`Set output 'version'`), and **Cleaning up orphan processes**: anything the steps started and left running is stopped (`Terminate orphan process: pid (1234) (node)`). The runner finds those processes by `RUNNER_TRACKING_ID`, as GitHub's does, so a process that unsets it is not found. Only on Linux. | | |
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 1381 | |
| A run opens on its summary: what triggered it, its status, duration and artifacts, a graph of its jobs (what needs what, matrices folded, called workflows boxed, deploys with their address), annotations, and each job's summary; the job list groups the same way | 1382 | ### The run's summary |
| 1383 | ||
| 1384 | The summary holds, top to bottom: | |
| 1385 | ||
| 1386 | | Part | What it shows | | |
| 1387 | | --- | --- | | |
| 1388 | | The run | What triggered it and when, who, the commit and its branch (or pull request), how the run stands, how long it took in all, and how many artifacts it kept. | | |
| 1389 | | The jobs graph | The workflow file and its event (`deploy.yml · on: push`), then every job and how they depend on each other. See [the jobs graph](#the-jobs-graph). | | |
| 1390 | | Annotations | Every job's errors, warnings and notices, counted by kind, each with the job it came from. Folds away. | | |
| 1391 | | Job summaries | What each job's steps wrote to `$GITHUB_STEP_SUMMARY`, under `<job> summary`. See [job summaries](#job-summaries). | | |
| 1392 | | Artifacts | What the run kept, to download. The count in the run's card jumps here. | | |
| 1393 | ||
| 1394 | Under **Run details** in the sidebar, **Workflow file** opens the | |
| 1395 | workflow as it was at the run's commit. | |
| 1396 | ||
| 1397 | ### The jobs graph | |
| 1398 | ||
| 1399 | Jobs are laid out left to right by their `needs:`: a job that needs | |
| 1400 | nothing starts a row on the left, and each job sits one column to the | |
| 1401 | right of the furthest job it needs. Within a column, jobs are ordered so | |
| 1402 | that as few connectors as possible cross. | |
| 1403 | ||
| 1404 | | Node | How it shows | | |
| 1405 | | --- | --- | | |
| 1406 | | A job | Its status, its name and how long it took. Click it to open its steps and logs. | | |
| 1407 | | A job that deploys | Its environment's address (`environment.url`), as a link, under its name. | | |
| 1408 | | A matrix | One node with how many jobs it made (`test · 6 jobs`) and how they stand together. Click it to list each combination; click one to open it. | | |
| Merge branch 'worktree-agent-af75396ad4c6ee7a8' into claude/cool-newton-7nm8r9 | 1409 | | A reusable workflow | A box under the job that calls it, named with the called file, holding the called workflow's jobs laid out the same way; a matrix of calls shares one box, each call's jobs named with its combination. The jobs that need the calling job connect to the box. | |
| A run opens on its summary: what triggered it, its status, duration and artifacts, a graph of its jobs (what needs what, matrices folded, called workflows boxed, deploys with their address), annotations, and each job's summary; the job list groups the same way | 1410 | |
| 1411 | Connectors run from a job to each job that needs it. They are red from a | |
| 1412 | job that failed, and move while the job they lead to is running (they | |
| 1413 | stay still if your system asks for reduced motion). | |
| 1414 | ||
| 1415 | A wide graph scrolls sideways inside its card, on a phone as on a desktop. | |
| 1416 | ||
| 1417 | The sidebar groups jobs the same way: a matrix's jobs, and a called | |
| 1418 | workflow's jobs, fold under their name. | |
| 1419 | ||
| Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009) | 1420 | ### Job summaries |
| 1421 | ||
| A run opens on its summary: what triggered it, its status, duration and artifacts, a graph of its jobs (what needs what, matrices folded, called workflows boxed, deploys with their address), annotations, and each job's summary; the job list groups the same way | 1422 | Markdown a step appends to the file in `$GITHUB_STEP_SUMMARY` shows on |
| 1423 | the run's summary, below the graph, a card per job, in the order its | |
| 1424 | steps wrote it. The card's title opens the job: | |
| Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009) | 1425 | |
| 1426 | ```yaml | |
| 1427 | - name: Report the tests | |
| 1428 | if: always() | |
| 1429 | run: | | |
| 1430 | echo "### Test results" >> "$GITHUB_STEP_SUMMARY" | |
| 1431 | echo "| Suite | Passed | Failed |" >> "$GITHUB_STEP_SUMMARY" | |
| 1432 | echo "| --- | ---: | ---: |" >> "$GITHUB_STEP_SUMMARY" | |
| 1433 | echo "| unit | 41 | 0 |" >> "$GITHUB_STEP_SUMMARY" | |
| 1434 | ``` | |
| 1435 | ||
| 1436 | | What | How it works | | |
| 1437 | | --- | --- | | |
| 1438 | | Formatting | GitHub-flavoured Markdown: tables, task lists, alerts such as `> [!WARNING]`, code blocks, and the HTML GitHub allows. Scripts, styles and event handlers are removed. | | |
| 1439 | | Secrets | Masked like the log, before the summary leaves the runner. | | |
| 1440 | | Size | Up to 1 MiB a step. A larger summary is refused with an error in the step's log, as on GitHub. | | |
| 1441 | | Steps | Up to 20 steps of a job keep a summary; later ones are dropped. | | |
| 1442 | | Actions | A JavaScript action's `core.summary` writes to the same file, so it works unchanged. | | |
| 1443 | ||
| 1444 | Summaries belong to their attempt: an earlier attempt keeps its own. | |
| 1445 | ||
| 1446 | ### Re-running | |
| 1447 | ||
| 1448 | When a run has finished, someone with the Write role can run it again: | |
| 1449 | ||
| 1450 | | Button | Runs again | | |
| 1451 | | --- | --- | | |
| 1452 | | **Re-run all jobs** | Every job. | | |
| 1453 | | **Re-run failed jobs** | Jobs that did not succeed (failed, cancelled or skipped), and every job that needs one of them. | | |
| 1454 | | The re-run button beside a job's name | That job, and every job that needs it. A job of a matrix runs again with the rest of its matrix; a job of a reusable workflow runs again with the job that calls it. | | |
| 1455 | ||
| 1456 | Jobs that are not run again keep how they ended, and their outputs reach | |
| 1457 | the jobs that need them. | |
| 1458 | ||
| 1459 | Each re-run is a new **attempt**. The run keeps its number, `github.run_attempt` | |
| 1460 | goes up by one, and the attempt before is kept as it ended: its jobs, | |
| 1461 | their steps, logs and summaries. Pick one from **Attempt #** at the top of | |
| 1462 | the page to read it. Its jobs have ids of their own, so a link to an | |
| 1463 | earlier attempt's job keeps showing that job's log. | |
| 1464 | ||
| Merge main into rm-agents: mirroring removal, open signups, free-tier limits, the g1t CLI and runner fixes, with the agent removal kept. The CLI's table of operations is regenerated from the API without the agent, customize and AI credit operations; no CLI command used them. | 1465 | A job that runs again has its whole time limit from when it starts: the |
| 1466 | time cap of the attempt before it never stops it. | |
| 1467 | ||
| Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009) | 1468 | #### Debug logging |
| 1469 | ||
| 1470 | Each re-run asks whether to **Enable debug logging**. The new attempt's | |
| 1471 | jobs then run with: | |
| 1472 | ||
| 1473 | | Set | Effect | | |
| 1474 | | --- | --- | | |
| 1475 | | `RUNNER_DEBUG=1`, and `runner.debug` is `1` | Actions that check it, such as the toolkit's `core.isDebug()`, log more. | | |
| 1476 | | `ACTIONS_STEP_DEBUG=true` | `::debug::` lines are shown in the log. | | |
| 1477 | | `ACTIONS_RUNNER_DEBUG=true` | Set for actions that read it. | | |
| 1478 | ||
| 1479 | With debug logging, each step's log also says how its `if:` read: | |
| 1480 | `Evaluating condition for step`, the expression, and the result. Setting a | |
| 1481 | secret or variable named `ACTIONS_STEP_DEBUG` to `true` shows `::debug::` | |
| 1482 | lines on every run instead. The attempt picker marks attempts that ran | |
| 1483 | with debug logging. | |
| 1484 | ||
| 1485 | ### Cancelling | |
| 1486 | ||
| Merge the run page fixes: Cancel run shows on every view of a run that is still going, including an earlier attempt's and job links, and pages refresh when a run is re-run from anywhere; a job's log follows to its true end, above anything covering the bottom of the window, and Jump to latest lands there. | 1487 | **Cancel run** is at the top of the run's page while any job of its latest |
| 1488 | attempt has not finished: waiting for the jobs it needs, held for an | |
| 1489 | environment's approval, queued for a runner (a self-hosted job waits | |
| 1490 | until a runner with its labels takes it), or running. It is there on an | |
| 1491 | earlier attempt's page too, and on a job's, and the re-run buttons appear | |
| 1492 | only once the run has finished. A page left open on a finished run hears | |
| 1493 | when it is re-run, from anywhere, and offers Cancel run. | |
| 1494 | ||
| 1495 | It cancels jobs that have not started at once. A job that is running is | |
| 1496 | stopped the way GitHub stops one: | |
| Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009) | 1497 | |
| 1498 | 1. The step it is on gets `SIGINT`, then `SIGTERM` 7.5 seconds later, and | |
| 1499 | is killed 2.5 seconds after that. Signals reach the processes the step | |
| 1500 | started too; in a [job container](#job-containers) they reach only the | |
| 1501 | `docker exec` that runs the step. The step ends **cancelled**. | |
| 1502 | 2. Its remaining steps run only if they ask to: `if: always()` or | |
| 1503 | `if: cancelled()`. Steps without an `if:`, or with `success()` or | |
| 1504 | `failure()`, are skipped. | |
| 1505 | 3. Post steps (an action's `post`, saving the cache) run, as their | |
| 1506 | `post-if` is `always()` unless the action says otherwise. | |
| 1507 | 4. The job ends **cancelled**, whatever those steps came to. | |
| 1508 | ||
| 1509 | While that happens the run says **Cancelling**. A job still going 5 | |
| 1510 | minutes after it was cancelled is stopped outright. **Force cancel** | |
| 1511 | (shown while a run is cancelling) stops every job at once, without | |
| 1512 | waiting for its cleanup steps. | |
| 1513 | ||
| 1514 | A step learns of a cancellation within about 10 seconds, even when it | |
| 1515 | prints nothing. A job on a [self-hosted runner](/guides/self-hosted-runners/) | |
| 1516 | is stopped the same way. | |
| 1517 | ||
| 1518 | ### Searching and downloading logs | |
| 1519 | ||
| 1520 | The **Search logs** box above a job's steps shows only the lines that hold | |
| 1521 | what you type, in any case, with each match marked and every step that has | |
| 1522 | one opened. Lines inside folded groups are searched too. | |
| 1523 | ||
| 1524 | | Download | Where | | |
| 1525 | | --- | --- | | |
| 1526 | | One job's whole log, as text | The download button beside the job's name. | | |
| 1527 | | Every job's log of an attempt, as a zip | **Download logs** at the top of the run. The zip holds `1_<job>.txt` with each job's whole log, and a `<job>/` folder with `<step>_<step name>.txt` for each step. | | |
| 1528 | ||
| 1529 | A zip holds up to 24 MiB of logs; jobs past that are listed with a note | |
| 1530 | to download them on their own. Each job keeps up to 4 MB of log. | |
| 1531 | ||
| 1532 | ### Status badges | |
| 1533 | ||
| 1534 | A badge shows how a workflow's latest finished run went: **passing**, | |
| 1535 | **failing**, **cancelled**, or **no status** before it has finished one. | |
| 1536 | ||
| 1537 | 1. Open the repository's **Actions** page and pick the workflow. | |
| 1538 | 2. Click **Create status badge**. | |
| 1539 | 3. Choose a branch and an event, if you want them, and copy the Markdown. | |
| 1540 | ||
| 1541 | ```markdown | |
| 1542 | [](https://g1t.sh/acme/web/actions?workflow=ci.yml) | |
| 1543 | ``` | |
| 1544 | ||
| 1545 | The address is `https://g1t.sh/{workspace}/{repo}/actions/workflows/{file}/badge.svg`, | |
| 1546 | where `{file}` is the workflow's file name in `.g1t/workflows/`. It takes: | |
| 1547 | ||
| 1548 | | Parameter | Shows | | |
| 1549 | | --- | --- | | |
| 1550 | | `branch` | Runs on that branch. Without it, the default branch's runs, or any branch's when the default branch has none. | | |
| 1551 | | `event` | Runs started by that event, such as `push` or `pull_request`. | | |
| 1552 | ||
| 1553 | A public repository's badge loads for anyone and is cached for a minute. | |
| 1554 | A private repository's loads only for someone who can see the repository, | |
| 1555 | so it does not show in a README read anywhere else. | |
| 1556 | ||
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 1557 | ### Masking secrets |
| 1558 | ||
| 1559 | Every secret's value is replaced with `***` wherever a job prints it, and | |
| 1560 | so is every value a step masks with `::add-mask::`. Each is masked in the | |
| 1561 | forms it shows up in: | |
| 1562 | ||
| 1563 | | Form | Example | | |
| 1564 | | --- | --- | | |
| 1565 | | As it is | `echo $API_KEY` | | |
| 1566 | | Each of its lines on its own | `cat key.pem`, which prints a private key a line at a time | | |
| 1567 | | Base64 | `echo -n $API_KEY \| base64`, or an `Authorization: Basic` header | | |
| 1568 | | JSON-escaped | A secret holding quotes or newlines printed inside JSON | | |
| 1569 | ||
| 1570 | Annotations' titles and messages, and step names, are masked the same way. | |
| 1571 | A job output that holds a secret in any of those forms is left out, with | |
| 1572 | a warning in the log, since outputs go to other jobs and to the run's page. | |
| 1573 | A value of one character is not masked: it would hide that character | |
| 1574 | everywhere. | |
| 1575 | ||
| Merge brokered secrets: a secret a job uses only to call an API can be tied to the hosts it is for, and the job gets a stand-in in its place, which g1t fills in on the way out to those hosts and nowhere else, so the value never enters the sandbox; and a request to an allowed host that fails upstream is retried when it can be, or answered with a 502 that says why, rather than reset. | 1576 | A [brokered secret](#brokered-secrets)'s stand-in is masked the same way. |
| 1577 | Its real value never reaches the job, so the job cannot mask it; g1t | |
| 1578 | masks it in the log as the log arrives, should an answer have carried it | |
| 1579 | in. | |
| 1580 | ||
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1581 | ## Pull requests |
| 1582 | ||
| The docs describe g1t as the place your coding agents work, not as an agent of its own. The guides to g1t's hosted agents are gone: agents, their abilities, access, budgets, memory, routines, sessions and skills, talking to agents, working with g1t, Customize, model providers, the AI Gateway, the context hub, spend, plans and the chat app's agent pages. Each old address redirects to the page that now covers what is left of it. | 1583 | A pull request's workflows run on each new head: when it is opened and |
| 1584 | when a commit is pushed to it. Each head runs each workflow once. | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1585 | |
| Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts | 1586 | They also start on the activity types `reopened` (also run by |
| 1587 | default, as `opened` and `synchronize` are), `converted_to_draft`, | |
| 1588 | `ready_for_review`, `labeled`, `unlabeled`, `milestoned`, `demilestoned`, | |
| 1589 | `assigned`, `review_requested` and `closed`, and `edited` when the branch | |
| 1590 | a pull request merges into changes; `issue_comment` workflows on | |
| Merge branch 'worktree-agent-a8b78c62188153aa3' into claude/cool-newton-7nm8r9 | 1591 | `created`, `edited` (with `github.event.changes.body.from`) and `deleted`; `issues` workflows on `assigned`, `labeled`, `unlabeled`, `milestoned` and |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 1592 | `demilestoned` too. List them under `types:` to run on them. For |
| Merge branch 'worktree-agent-a8b78c62188153aa3' into claude/cool-newton-7nm8r9 | 1593 | `labeled` and `unlabeled`, `github.event.label` names the label; for |
| 1594 | `assigned`, `github.event.assignee` names who was assigned. Assigning | |
| 1595 | several people at once starts one run, which names the first of them. A pull | |
| Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar | 1596 | request's `branches` filter, `github.base_ref` and |
| 1597 | `pull_request.base.ref` are the branch it merges into, which is not | |
| 1598 | always the default branch: see | |
| 1599 | [pull requests into other branches](/guides/base-branches/). | |
| 1600 | ||
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' | 1601 | ### What a pull request's run builds |
| 1602 | ||
| 1603 | As on GitHub, a `pull_request` run builds the pull request merged into | |
| 1604 | its base branch, not its head alone: | |
| 1605 | ||
| 1606 | | | Is | | |
| 1607 | | --- | --- | | |
| 1608 | | `github.ref`, `GITHUB_REF` | `refs/pull/<number>/merge` | | |
| 1609 | | `github.sha`, `GITHUB_SHA` | The test merge commit at `refs/pull/<number>/merge`: the head merged into the base branch's latest commit, its parents the base's commit and then the head, with the message `Merge <head> into <base>` | | |
| 1610 | | `github.event.pull_request.head.sha` | The head commit | | |
| 1611 | | `github.event.pull_request.merge_commit_sha` | The test merge commit | | |
| 1612 | | `actions/checkout` with no `ref` | The test merge commit, fetched from the repository itself as `+<sha>:refs/remotes/pull/<number>/merge` | | |
| 1613 | ||
| 1614 | The workflow files the run uses are read from the test merge commit too. | |
| 1615 | Its status, its check runs and the run itself stay on the pull request's | |
| 1616 | head, so required checks hold the merge as before. `pull_request_review` | |
| 1617 | runs build the same commit. `pull_request_target` runs are unchanged: they | |
| 1618 | build the base branch, never the pull request's code. | |
| 1619 | ||
| 1620 | g1t keeps two refs in the repository for every open pull request, from a | |
| The docs describe g1t as the place your coding agents work, not as an agent of its own. The guides to g1t's hosted agents are gone: agents, their abilities, access, budgets, memory, routines, sessions and skills, talking to agents, working with g1t, Customize, model providers, the AI Gateway, the context hub, spend, plans and the chat app's agent pages. Each old address redirects to the page that now covers what is left of it. | 1621 | branch or a fork: `refs/pull/<number>/head` at |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' | 1622 | its head (a fork's head commit is copied into the repository), and |
| 1623 | `refs/pull/<number>/merge` at its test merge commit. Both move each time | |
| 1624 | the head is pushed to, the pull request is opened or reopened, or its | |
| 1625 | base branch changes, and both can be fetched like any branch: | |
| 1626 | ||
| 1627 | ```sh | |
| 1628 | git fetch origin refs/pull/12/head refs/pull/12/merge | |
| 1629 | ``` | |
| 1630 | ||
| 1631 | The merge commit moves when the head does. When only the base branch | |
| 1632 | moves, it moves at the pull request's next event, as on GitHub, where | |
| 1633 | workflows do not run again because the base branch moved. | |
| 1634 | ||
| 1635 | **A pull request with conflicts runs no `pull_request` workflows**, as on | |
| 1636 | GitHub: it has no merge commit to build. Its checks box says so, and the | |
| 1637 | runs start once the conflicts are resolved and the head is pushed again. | |
| 1638 | g1t merges the two the way git does: a file only one side changed is | |
| 1639 | taken from it, and changes both made to the same file merge unless they | |
| 1640 | change the same or neighbouring lines differently, or the file is binary. | |
| 1641 | When g1t cannot make the merge itself (a file one side renamed or deleted | |
| 1642 | while the other changed it, a file where the other side has a directory, | |
| 1643 | more than 300 changed files, or a file over 1 MB that both changed), the | |
| 1644 | run builds the head commit instead, as it did before. | |
| 1645 | ||
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 1646 | A pull request from outside the workspace may wait for approval before |
| 1647 | its workflows run: see [pull requests from outside](#pull-requests-from-outside). | |
| 1648 | ||
| The docs describe g1t as the place your coding agents work, not as an agent of its own. The guides to g1t's hosted agents are gone: agents, their abilities, access, budgets, memory, routines, sessions and skills, talking to agents, working with g1t, Customize, model providers, the AI Gateway, the context hub, spend, plans and the chat app's agent pages. Each old address redirects to the page that now covers what is left of it. | 1649 | `github.event.pull_request` reads as it does on GitHub. `sender` is |
| 1650 | whoever caused the event. | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1651 | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' | 1652 | ## The event payload |
| 1653 | ||
| 1654 | `github.event`, and the file at `GITHUB_EVENT_PATH`, hold the webhook | |
| 1655 | payload GitHub would send for the event, with the same keys and types. | |
| 1656 | ||
| 1657 | - **Ids are numbers.** `repository.id`, `pull_request.id`, `issue.id`, | |
| 1658 | `review.id`, `sender.id`, every `user.id` and `owner.id` are whole | |
| 1659 | numbers, the same for an object wherever it appears and below 2^53, so | |
| 1660 | JavaScript reads them exactly. `node_id` is g1t's own id, such as | |
| 1661 | `rep_01kpw0…`. A person's or workspace's number comes from their name, | |
| 1662 | so it changes when they are renamed. `github.repository_id`, | |
| 1663 | `github.repository_owner_id`, `github.actor_id` and their | |
| 1664 | `GITHUB_REPOSITORY_ID`, `GITHUB_REPOSITORY_OWNER_ID` and | |
| 1665 | `GITHUB_ACTOR_ID` variables are the same numbers, as text. | |
| 1666 | - **What the API takes by id keeps g1t's id.** `comment.id`, | |
| 1667 | `release.id`, `deployment.id`, `deployment_status.id`, | |
| 1668 | `workflow_run.id` and `workflow_run.workflow_id` are g1t's ids | |
| 1669 | (`cmt_…`, `rel_…`, `run_…`, `wfl_…`), so you can pass them straight | |
| 1670 | back, as in `PATCH /repos/{owner}/{repo}/issues/comments/{comment_id}` | |
| 1671 | or `run-id: ${{ github.event.workflow_run.id }}`. | |
| 1672 | - **`repository.owner.type`** is `User` for a repository in a person's | |
| 1673 | own workspace and `Organization` for any other workspace's. | |
| 1674 | - **On `push`,** `created` is true for a new branch or tag, and `forced` | |
| 1675 | is true when the commit before the push is not in the new commit's | |
| 1676 | history. g1t reads the 20 latest commits to tell, so a forced push onto | |
| 1677 | a longer history says `false`. `head_commit` is the commit pushed and | |
| Merge GitHub pull request #8 (claude/cool-newton-7nm8r9): Docker deployments on g1t.page behind a switch that stays off until Cloudflare's container APIs are checked live, workflows a workspace manages in its repositories, tarball and zipball downloads, refs/pull/* kept to g1t alone, framework detection for g1t.page builds, and a workflow's event payload matching GitHub's. | 1678 | `commits` lists at most 20, oldest first. `pusher.email` is the |
| 1679 | pusher's noreply address (`<id>+<username>@users.noreply.g1t.sh`), or | |
| 1680 | `g1t@users.noreply.g1t.sh` for g1t. | |
| 1681 | - **A commit's `added`, `removed` and `modified`** list the paths the | |
| 1682 | push changed when it pushed one commit and a workflow on `push` has a | |
| 1683 | `paths` or `paths-ignore` filter, which makes g1t compare the push. | |
| 1684 | Otherwise, and for a push of several commits, they are empty lists. | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' | 1685 | - **On pull request events,** `pull_request.base.sha` is the tip of the |
| 1686 | branch it merges into when the event happened, and | |
| 1687 | `pull_request.merge_commit_sha` is set only once it is merged, to the | |
| 1688 | commit it landed as. | |
| 1689 | - **On `workflow_run`,** `workflow_run` has the followed run's `name`, | |
| 1690 | `path`, `event`, `status`, `conclusion`, `head_branch`, `head_sha`, | |
| 1691 | `head_commit`, `run_number`, `run_attempt`, `actor`, `created_at`, | |
| Merge GitHub pull request #8 (claude/cool-newton-7nm8r9): Docker deployments on g1t.page behind a switch that stays off until Cloudflare's container APIs are checked live, workflows a workspace manages in its repositories, tarball and zipball downloads, refs/pull/* kept to g1t alone, framework detection for g1t.page builds, and a workflow's event payload matching GitHub's. | 1692 | `updated_at`, `html_url`, `repository` and `pull_requests`. Each pull |
| 1693 | request there has its `id`, `number`, `url`, and `head` and `base` | |
| 1694 | with their `ref`, `sha` and `repo` (`id`, `url`, `name`). As on | |
| 1695 | GitHub, a pull request from a fork is not listed. | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' | 1696 | |
| Merge GitHub pull request #8 (claude/cool-newton-7nm8r9): Docker deployments on g1t.page behind a switch that stays off until Cloudflare's container APIs are checked live, workflows a workspace manages in its repositories, tarball and zipball downloads, refs/pull/* kept to g1t alone, framework detection for g1t.page builds, and a workflow's event payload matching GitHub's. | 1697 | Labels on `issue`, `pull_request` and a `labeled` event's `label` have |
| 1698 | their `id`, `name`, `color` and `description` as the repository has | |
| 1699 | them, and `default`, which is true for the labels a repository starts | |
| 1700 | with. | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' | 1701 | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1702 | ## Checks |
| 1703 | ||
| 1704 | A pull request's checks are its workflows. Each workflow that runs on | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' | 1705 | `pull_request` runs for every pull request, whoever opened it, a |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1706 | person or an agent, and its runs report a check named after the workflow: |
| 1707 | a workflow with `name: CI` reports `CI`, with the status context | |
| Merge checks: statuses and check runs on every commit | 1708 | `CI / pull_request` (the workflow's name and the event). Each of its jobs |
| 1709 | is a [check run](/guides/checks/) on the commit, shown as | |
| 1710 | `CI / test (pull_request)` beside it wherever it appears. | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1711 | |
| Merge rulesets: branch and tag rules, agent-first, enforced on push and merge | 1712 | - **Which checks a merge needs** is up to the [rules](/guides/rules/) of the branch it merges into, |
| 1713 | their [required status checks](/guides/pull-requests/#required-status-checks), | |
| 1714 | under **Settings → Rules**. A required check that failed, | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1715 | is still running or has not reported holds the merge. Checks that are not |
| 1716 | required are shown on the pull request and never hold it. | |
| 1717 | - **In a repository that merges through the [merge queue](/guides/merge-queue/)**, | |
| 1718 | workflows with `on: merge_group` run on each combined state the queue | |
| 1719 | builds, on the branch `g1t-queue/<entry>`, and the state lands only if | |
| 1720 | they and every required check pass on it. A workflow behind a required | |
| 1721 | check needs `merge_group` in its `on:`. | |
| 1722 | ||
| 1723 | ```yaml | |
| 1724 | name: CI | |
| 1725 | ||
| 1726 | on: | |
| 1727 | pull_request: | |
| 1728 | push: | |
| 1729 | branches: [main] | |
| 1730 | merge_group: | |
| 1731 | ``` | |
| 1732 | ||
| 1733 | ### Add CI | |
| 1734 | ||
| 1735 | A repository with no workflows has nothing that proves a change works, for | |
| 1736 | people or for agents. Its pull requests, its **Branches and merging** | |
| 1737 | settings and its **Actions** page say **This repository has no checks**, | |
| 1738 | with an **Add CI** button. Anyone who can push to the repository can use it: | |
| 1739 | ||
| 1740 | 1. Choose **Add CI**. g1t looks at the files at the repository's root and | |
| 1741 | writes a starter workflow with a job for each stack it finds, up to | |
| 1742 | three: Node (npm, pnpm, Yarn or Bun), Rust, Go, Python (pip or uv), Ruby, | |
| 1743 | Java (Maven or Gradle), .NET, or Make. Each job installs, lints where | |
| 1744 | the project says how, builds and tests. When it finds none, the job is a | |
| 1745 | placeholder that fails until you replace its last step with your own | |
| 1746 | commands. | |
| 1747 | 2. The workflow is committed as `.g1t/workflows/ci.yml` on a new branch, | |
| 1748 | `add-ci`, and opened as a pull request, by you. It is named `CI` and runs | |
| 1749 | on `pull_request`, on `push` to the default branch, and on `merge_group`. | |
| 1750 | 3. Change it on the pull request if the steps are not how your project | |
| 1751 | builds, and merge it. | |
| 1752 | 4. Once it has run, `CI` is offered under **Require status checks to pass | |
| 1753 | before merging**. | |
| 1754 | Require it, so that nothing merges into the default branch unless it | |
| 1755 | passes. | |
| 1756 | ||
| 1757 | ## Secrets and variables | |
| 1758 | ||
| 1759 | Secrets are read as `${{ secrets.KEY }}` and config as `${{ vars.KEY }}`, | |
| 1760 | from the rows under **Settings → Secrets and variables** that are | |
| 1761 | available to Workflows. A job with `environment: production` reads each | |
| Merge branch 'main' into worktree-agent-a69aeabc4b0deeb97 | 1762 | key's Production row; other jobs read the rows for all environments. A |
| 1763 | job with an `environment:` also makes a deployment to it; see | |
| 1764 | [deployments from g1t Actions](/guides/deployments-api/#deployments-from-g1t-actions). See | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1765 | [Secrets and variables](/guides/secrets-and-variables/) for how rows, |
| 1766 | environments and the workspace's rows work. | |
| 1767 | ||
| Merge the OIDC docs: deploying to AWS, Google Cloud or Azure with a job's short-lived identity token now says which of the cloud's hosts to allow under Workflow-only domains, for the deploying workflow and environment, since a job on g1t's machines reaches only the hosts its project allows; and tests for the audience a job asks for and for the token variables reaching each step. | 1768 | To deploy to AWS, Google Cloud or Azure, or to a server of your own, |
| 1769 | you need no secret at all: give the job `permissions: id-token: write` | |
| 1770 | and trade its [OIDC token](#oidc-tokens) for short-lived credentials. | |
| 1771 | ||
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 1772 | Every job also gets `${{ secrets.G1T_TOKEN }}`, [its own token](#the-jobs-token), |
| 1773 | with `GITHUB_TOKEN` as its alias. A pull request's runs get secrets only | |
| 1774 | when its author has the Write [role](/guides/access-and-roles/) or higher | |
| The docs describe g1t as the place your coding agents work, not as an agent of its own. The guides to g1t's hosted agents are gone: agents, their abilities, access, budgets, memory, routines, sessions and skills, talking to agents, working with g1t, Customize, model providers, the AI Gateway, the context hub, spend, plans and the chat app's agent pages. Each old address redirects to the page that now covers what is left of it. | 1775 | on the repository, a member or an outside collaborator. Anyone else's, such as one |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1776 | from a fork or by someone with Read or Triage, runs without secrets and |
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 1777 | with a token that can only read. See |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1778 | [who gets secrets](/guides/secrets-and-variables/#who-gets-secrets). |
| 1779 | ||
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 1780 | ## The job's token |
| 1781 | ||
| 1782 | Each job gets a token of its own, `${{ secrets.G1T_TOKEN }}` | |
| 1783 | (`${{ secrets.GITHUB_TOKEN }}` and `${{ github.token }}` are the same). | |
| 1784 | `actions/checkout` uses it, and so can any step that calls the | |
| 1785 | [API](/reference/api/) or pushes with git: | |
| 1786 | ||
| 1787 | - It reaches **this repository only**. Every other repository, even one | |
| Merge packages: roles, Actions access, source label, soft delete, API | 1788 | in the same workspace, is refused. So are packages: it reaches this |
| 1789 | repository's own, and another package only once the package's admins | |
| 1790 | add this repository under its | |
| 1791 | [Manage Actions access](/guides/packages/#manage-actions-access). | |
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 1792 | - It can do **what its `permissions:` say**, and nothing more. |
| 1793 | - It **stops working when the job ends**, however it ends. | |
| 1794 | - Everything it changes is in the [audit log](/guides/audit-log/) as that | |
| 1795 | job's, under its run. | |
| 1796 | - What it changes **starts no workflows**: a push, a pull request, an issue | |
| 1797 | or a comment made with it runs nothing, so a workflow cannot set itself | |
| 1798 | off. `workflow_dispatch` and [`repository_dispatch`](#repository-dispatch) | |
| 1799 | are the exceptions, for a workflow that means to start another. | |
| 1800 | ||
| 1801 | `permissions:` goes at the top of the workflow, for every job, or on a job, | |
| 1802 | which then ignores the workflow's. Once either is written, every permission | |
| 1803 | it leaves out is `none`: | |
| 1804 | ||
| 1805 | ```yaml | |
| 1806 | permissions: | |
| 1807 | contents: read | |
| 1808 | ||
| 1809 | jobs: | |
| 1810 | release: | |
| 1811 | runs-on: ubuntu-latest | |
| 1812 | permissions: | |
| 1813 | contents: write | |
| 1814 | pull-requests: write | |
| 1815 | steps: | |
| 1816 | - uses: actions/checkout@v5 | |
| 1817 | - run: ./scripts/release.sh | |
| 1818 | ``` | |
| 1819 | ||
| 1820 | | Permission | `read` lets it | `write` also lets it | | |
| 1821 | | --- | --- | --- | | |
| 1822 | | `contents` | Clone and fetch with git, read the repository | Push, publish releases | | |
| 1823 | | `pull-requests` | Read pull requests | Open, review, close and merge them | | |
| 1824 | | `issues` | Read issues | Open, edit, comment on and close them | | |
| 1825 | | `actions` | Read workflows, runs and logs | Run, cancel and re-run them | | |
| 1826 | | `checks`, `statuses` | Read statuses and check runs | Report them | | |
| 1827 | | `deployments`, `pages` | Read deployments | Report them | | |
| 1828 | | `packages` | Pull packages | Push and publish them | | |
| 1829 | | `security-events` | Read security alerts | Upload code scanning results, change alerts | | |
| 1830 | | `metadata` | Always `read` | | | |
| 1831 | | `id-token` | Nothing | Ask for an [OIDC token](#oidc-tokens) | | |
| 1832 | | `discussions`, `attestations`, `models`, `repository-projects` | Nothing on g1t | Nothing on g1t | | |
| 1833 | ||
| 1834 | `read-all` and `write-all` set every permission; `permissions: {}` sets | |
| 1835 | none, so the token cannot even clone a private repository. A reusable | |
| 1836 | workflow's jobs get no more than the job that calls it. | |
| 1837 | ||
| Docs and plan: fine-grained tokens, workspace token rules, workflow files, workspace token Write | 1838 | There is no `workflows` permission for a job's token: it can never add, |
| 1839 | change or delete a file under `.g1t/workflows/` or `.github/workflows/`, | |
| 1840 | even with `contents: write`. A push that does is declined, naming the file, | |
| 1841 | so a workflow cannot rewrite the workflows that run with its repository's | |
| 1842 | secrets. To change workflows from a job, push with a | |
| One kind of access token; presence and status; usernames keep their case; the tour is a miniature of the real app; icons for password managers | 1843 | [personal access token](/guides/authentication/#workflow-files) that has |
| 1844 | Workflow files: write, kept as a secret. | |
| Docs and plan: fine-grained tokens, workspace token rules, workflow files, workspace token Write | 1845 | |
| 1846 | The job's token is the repository's workspace acting with the Write role | |
| 1847 | at most, never Admin: it cannot manage webhooks, secrets, deploy keys or who | |
| 1848 | has access, whatever it asks for. | |
| 1849 | ||
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 1850 | **Without `permissions:`** a job gets the repository's default, which |
| 1851 | someone with the Admin role sets under **Settings → Actions**: | |
| 1852 | ||
| 1853 | | Repository | Default until someone chooses | | |
| 1854 | | --- | --- | | |
| 1855 | | Made before restricted tokens came in, in October 2026 | **Read and write**: every permission at `write`, as before | | |
| 1856 | | Made since | The workspace's default for new repositories: **Read repository contents and packages** (`contents: read`, `packages: read`) unless an owner chose otherwise | | |
| 1857 | ||
| 1858 | The workspace's owners set that default, and a **maximum**, under the | |
| 1859 | workspace's **Settings → Actions**: with a maximum of **Read only**, no | |
| 1860 | repository's default goes past `contents: read` and `packages: read`, | |
| 1861 | whatever it chose. Workflows that write `permissions:` get what they | |
| 1862 | write either way, and whatever a workflow asks for, a pull request from | |
| 1863 | outside the repository's writers (a fork, or someone with Read or Triage) | |
| 1864 | gets a token that can only read. | |
| 1865 | ||
| 1866 | **Allow g1t Actions to create and approve pull requests** is off unless a | |
| 1867 | repository's admin turns it on under **Settings → Actions**, and they can | |
| 1868 | only where the workspace's owners allow it. Until then a job's token | |
| 1869 | cannot open a pull request or approve one, whatever its `pull-requests` | |
| 1870 | permission says; it can still read, comment on, review with changes | |
| 1871 | requested, and merge them. | |
| 1872 | ||
| 1873 | The token can never change secrets, variables, environments' rules or | |
| 1874 | the Actions settings, approve runs or deployments, or reach another | |
| 1875 | repository. | |
| 1876 | ||
| 1877 | ## Environments | |
| 1878 | ||
| 1879 | A job that names an environment with `environment:` reads that | |
| 1880 | environment's [secrets and variables](/guides/secrets-and-variables/#a-value-per-environment) | |
| 1881 | and records a [deployment](/guides/deployments-api/#deployments-from-g1t-actions) | |
| 1882 | to it. Give the environment protection rules, and such a job waits until | |
| 1883 | they let it through, and only then gets the environment's secrets: | |
| 1884 | ||
| 1885 | | Rule | What it does | | |
| 1886 | | --- | --- | | |
| 1887 | | **Required reviewers** | Up to 6 people or teams. The job waits until one of them approves it. | | |
| 1888 | | **Prevent self-review** | Whoever started the run cannot approve it, even as a reviewer. | | |
| 1889 | | **Wait timer** | Minutes the job waits once it reaches the environment, up to 43,200 (30 days). | | |
| 1890 | | **Deployment branches and tags** | **All branches**; **Protected branches only**, those the repository's [rules](/guides/rules/) protect, the default branch included; or **Selected branches and tags**, by pattern, such as `main`, `release/*` or `v*`. A job on any other ref fails, saying so. A pull request's run is on no branch, so it can deploy only where all branches may. | | |
| 1891 | | **Allow admins to bypass** | On unless you turn it off: someone with the Admin role may approve without being a reviewer, which also skips the wait timer. | | |
| 1892 | ||
| 1893 | To set them: | |
| 1894 | ||
| 1895 | 1. Open the repository's **Settings → Environments**. It lists every | |
| 1896 | environment your workflows, secrets and deployments name. | |
| 1897 | 2. Choose one, or name a new one, and set its rules. | |
| 1898 | 3. Save. Runs that reach the environment from then on wait by them. | |
| 1899 | ||
| 1900 | A run whose jobs wait shows **Waiting for review** at the top of its page, | |
| 1901 | with the environments, the jobs each holds, its reviewers and when its | |
| g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them. | 1902 | wait timer runs out. Reviewers are told in their [notifications](/guides/notifications/); |
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 1903 | on the run's page they choose **Approve and deploy** or **Reject**, with |
| 1904 | room for a comment. One review covers every job of the run that names the | |
| 1905 | environment. A rejected job fails, and so does anything that needs it. The | |
| 1906 | rest of the run goes on meanwhile: jobs that do not need the waiting ones | |
| 1907 | run. | |
| 1908 | ||
| 1909 | The environment's name may be an expression, such as | |
| 1910 | `environment: ${{ inputs.target }}`: it is read once the job's needs are | |
| 1911 | done, and its rules and secrets are that environment's. Names are matched | |
| 1912 | without regard to case. | |
| 1913 | ||
| 1914 | From the API, `PUT /repos/{owner}/{repo}/environments/{environment}` sets | |
| 1915 | the rules, with `reviewers`, `prevent_self_review`, `wait_timer`, | |
| 1916 | `deployment_branch_policy`, `branch_policies` and `can_admins_bypass`; | |
| 1917 | `GET` on the same route returns them as `protection_rules`; `DELETE` | |
| 1918 | removes them. `POST /repos/{owner}/{repo}/actions/runs/{id}/pending_deployments` | |
| 1919 | approves or rejects a run's waiting jobs: | |
| 1920 | ||
| 1921 | ```sh | |
| 1922 | curl -X PUT https://api.g1t.sh/repos/acme/web/environments/production \ | |
| 1923 | -H "Authorization: Bearer $G1T_TOKEN" -H "Content-Type: application/json" \ | |
| 1924 | -d '{"reviewers": [{"type": "Team", "name": "deployers"}], "wait_timer": 10, | |
| 1925 | "deployment_branch_policy": {"protected_branches": true, "custom_branch_policies": false}}' | |
| 1926 | ``` | |
| 1927 | ||
| 1928 | A job's own token cannot approve, reject or change any of it. | |
| 1929 | ||
| 1930 | ## Pull requests from outside | |
| 1931 | ||
| 1932 | A pull request from someone outside the workspace runs code anyone could | |
| 1933 | have written. By the repository's **approval policy**, its runs wait as | |
| 1934 | **Approval required** until someone with the Write | |
| 1935 | [role](/guides/access-and-roles/) chooses **Approve and run** on the run's | |
| 1936 | page. Nothing runs before then: no job starts, and no token or secret is | |
| 1937 | handed out. | |
| 1938 | ||
| 1939 | | Policy, under **Settings → Actions** | Whose pull requests' runs wait | | |
| 1940 | | --- | --- | | |
| 1941 | | **First-time contributors** | Someone outside the workspace who has not had a pull request merged here yet. | | |
| 1942 | | **Outside contributors** (the default) | Those, and everyone outside the workspace who cannot push here: pull requests from forks, and from people with Read or Triage. | | |
| 1943 | | **All external contributors** | Everyone outside the workspace, [outside collaborators](/guides/access-and-roles/#outside-collaborators) with Write included. | | |
| 1944 | ||
| The docs describe g1t as the place your coding agents work, not as an agent of its own. The guides to g1t's hosted agents are gone: agents, their abilities, access, budgets, memory, routines, sessions and skills, talking to agents, working with g1t, Customize, model providers, the AI Gateway, the context hub, spend, plans and the chat app's agent pages. Each old address redirects to the page that now covers what is left of it. | 1945 | Members' pull requests never wait. Each new push to the pull request waits again. |
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 1946 | `pull_request_target` runs, which run the default branch's workflow and |
| 1947 | code, never wait. | |
| 1948 | ||
| 1949 | From the API: `POST /repos/{owner}/{repo}/actions/runs/{id}/approve` | |
| 1950 | approves a run, and `GET` and `PUT | |
| 1951 | /repos/{owner}/{repo}/actions/permissions/fork-pr-contributor-approval` | |
| 1952 | read and set the policy, as `approval_policy`. | |
| 1953 | ||
| 1954 | ## Repository dispatch | |
| 1955 | ||
| 1956 | `POST /repos/{owner}/{repo}/dispatches` starts the default branch's | |
| 1957 | workflows that run `on: repository_dispatch` for its `event_type`, those | |
| 1958 | listing it under `types:` or listing none. `client_payload` is theirs to | |
| 1959 | read as `github.event.client_payload`: | |
| 1960 | ||
| 1961 | ```yaml | |
| 1962 | on: | |
| 1963 | repository_dispatch: | |
| 1964 | types: [docs-published] | |
| 1965 | ||
| 1966 | jobs: | |
| 1967 | announce: | |
| 1968 | runs-on: ubuntu-latest | |
| 1969 | steps: | |
| 1970 | - run: echo "Docs ${{ github.event.client_payload.version }} are out" | |
| 1971 | ``` | |
| 1972 | ||
| 1973 | ```sh | |
| 1974 | curl -X POST https://api.g1t.sh/repos/acme/web/dispatches \ | |
| 1975 | -H "Authorization: Bearer $G1T_TOKEN" -H "Content-Type: application/json" \ | |
| 1976 | -d '{"event_type": "docs-published", "client_payload": {"version": "2.4.0"}}' | |
| 1977 | ``` | |
| 1978 | ||
| 1979 | It needs the Write role, or a token with `code:write`; a job's own token | |
| 1980 | needs `contents: write`. `client_payload` is a JSON object of at most 10 | |
| 1981 | properties and 64 KB. | |
| 1982 | ||
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1983 | ## Who may run workflows |
| 1984 | ||
| 1985 | What you can do with a repository's workflows follows your | |
| 1986 | [role](/guides/access-and-roles/) on it: | |
| 1987 | ||
| 1988 | | | Needs | | |
| 1989 | | --- | --- | | |
| 1990 | | See workflows, runs and their logs | Read: on a public repository, anyone | | |
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 1991 | | Run a workflow by hand, cancel or re-run a run, approve a pull request's run from outside | Write | |
| 1992 | | Approve or reject a job waiting for an environment | One of the environment's reviewers | | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1993 | | Enable or disable a workflow | Maintain | |
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 1994 | | The repository's secrets and variables, seeing them included; environments' rules; **Settings → Actions** | Admin | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 1995 | |
| 1996 | Jobs run in g1t's sandboxes, so they need the | |
| 1997 | [g1t plan](/guides/usage-and-billing/#the-g1t-plan) or | |
| 1998 | [the trial](/guides/usage-and-billing/#the-trial); jobs on | |
| 1999 | [self-hosted runners](/guides/self-hosted-runners/#billing) need neither. | |
| 2000 | On a public repository, | |
| 2001 | [g1t's open-source pool](/guides/usage-and-billing/#the-open-source-pool) | |
| 2002 | runs them too, after a card check, until the month's pool is spent. | |
| 2003 | ||
| 2004 | Before each job starts, g1t reserves what it may cost (its time limit at | |
| 2005 | the sandbox price) with billing, and settles what it really cost when it | |
| 2006 | ends; each job's sandbox is charged as | |
| 2007 | [sandbox time](/guides/usage-and-billing/#sandbox-time), from the first | |
| 2008 | second. A job billing refuses does not start: it is recorded as failed | |
| 2009 | with "Not started:" and the reason, such as "Workflows run in g1t's | |
| 2010 | sandboxes, which cost real money, so they need the g1t plan ($20 a month) | |
| 2011 | or a card check", and what to do about it. The | |
| 2012 | Actions page tells people with Write on a repository whose workspace | |
| 2013 | cannot run jobs before the first run. | |
| 2014 | ||
| 2015 | ## From the API | |
| 2016 | ||
| 2017 | The routes follow the standard Actions REST shape, so existing scripts | |
| 2018 | usually work once they point at `https://api.g1t.sh`. | |
| 2019 | ||
| 2020 | | `workflow` action | Route | | |
| 2021 | | --- | --- | | |
| 2022 | | `list` | `GET /repos/{owner}/{repo}/actions/workflows` | | |
| Merge branch 'worktree-agent-a4db4b523bb973765' | 2023 | | `get` | `GET /repos/{owner}/{repo}/actions/workflows/{workflow}`, with `ref`: the workflow, with `source`, its file on that branch or tag | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 2024 | | `list_runs` | `GET /repos/{owner}/{repo}/actions/runs`, with `workflow`, `branch`, `event`, `pull`, `head_sha` | |
| 2025 | | `get_run` | `GET /repos/{owner}/{repo}/actions/runs/{id}` | | |
| Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009) | 2026 | | `job_logs` | `GET /repos/{owner}/{repo}/actions/jobs/{job}/logs?after=`, or `?format=text` for the whole log as plain text | |
| 2027 | | `get_run` with `attempt` | `GET /repos/{owner}/{repo}/actions/runs/{id}/attempts/{attempt}` | | |
| 2028 | | No tool: a download | `GET /repos/{owner}/{repo}/actions/runs/{id}/logs`, or `…/attempts/{attempt}/logs`: every job's log as a zip | | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 2029 | | `dispatch` | `POST /repos/{owner}/{repo}/actions/workflows/{workflow}/dispatches` with `ref` and `inputs` | |
| Merge Actions runs: summaries, attempts and re-runs, graceful cancel, log downloads, badges (actions 0009) | 2030 | | `cancel` | `POST /repos/{owner}/{repo}/actions/runs/{id}/cancel`; `…/force-cancel`, or `force`, to stop running jobs without their cleanup steps | |
| 2031 | | `rerun` | `POST …/runs/{id}/rerun`, or `…/rerun-failed-jobs`; one job and those that need it with `POST /repos/{owner}/{repo}/actions/jobs/{job}/rerun`. Each takes `enable_debug_logging` (or `debug`) | | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 2032 | | `update` | `PUT …/workflows/{workflow}/enable` and `…/disable` | |
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 2033 | | `approve_run` | `POST /repos/{owner}/{repo}/actions/runs/{id}/approve` | |
| 2034 | | `pending_deployments` | `GET /repos/{owner}/{repo}/actions/runs/{id}/pending_deployments` | | |
| 2035 | | `review_deployments` | `POST /repos/{owner}/{repo}/actions/runs/{id}/pending_deployments` with `environment_names`, `state` and `comment` | | |
| 2036 | | `get_environment` | `GET /repos/{owner}/{repo}/environments/{environment}` | | |
| 2037 | | `update_environment` | `PUT /repos/{owner}/{repo}/environments/{environment}` | | |
| 2038 | | `delete_environment` | `DELETE /repos/{owner}/{repo}/environments/{environment}` | | |
| 2039 | | `get_permissions`, `set_permissions` | `GET` and `PUT /repos/{owner}/{repo}/actions/permissions/workflow`, with `default_workflow_permissions` (`read`, `write` or `inherit`) and `can_approve_pull_request_reviews` | | |
| 2040 | | `get_workspace_permissions`, `set_workspace_permissions` | `GET` and `PUT /workspaces/{workspace}/actions/permissions/workflow`, with `default_workflow_permissions`, `max_workflow_permissions` and `can_approve_pull_request_reviews` | | |
| 2041 | | `get_approval_policy`, `set_approval_policy` | `GET` and `PUT /repos/{owner}/{repo}/actions/permissions/fork-pr-contributor-approval` | | |
| Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts | 2042 | | `get_access`, `set_access` | `GET` and `PUT /repos/{owner}/{repo}/actions/permissions/access`, with `access_level` (`none` or `organization`) | |
| Merge branch 'worktree-agent-a3abfcce648e87dca' | 2043 | | `repository_dispatch` | `POST /repos/{owner}/{repo}/dispatches` with `event_type` and `client_payload` | |
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 2044 | | `list_artifacts` | `GET /repos/{owner}/{repo}/actions/artifacts`, with `name`, `page`, `per_page` | |
| 2045 | | `run_artifacts` | `GET …/actions/runs/{id}/artifacts`, with `name` | | |
| 2046 | | `get_artifact` | `GET …/actions/artifacts/{artifact_id}` | | |
| 2047 | | `download_artifact` | `GET …/actions/artifacts/{artifact_id}/zip`: a `302` to a link good for 10 minutes | | |
| 2048 | | `delete_artifact` | `DELETE …/actions/artifacts/{artifact_id}` | | |
| Merge main into rm-agents: mirroring removal, open signups, free-tier limits, the g1t CLI and runner fixes, with the agent removal kept. The CLI's table of operations is regenerated from the API without the agent, customize and AI credit operations; no CLI command used them. | 2049 | | `artifact_retention`, `set_artifact_retention` | `GET` and `PUT …/actions/permissions/artifact-and-log-retention` with `days` (it sets artifacts' days only; logs are kept for 90 days) | |
| Merge branch 'worktree-agent-a3b9b1f730f55b5bf' | 2050 | | `list_caches`, `cache_usage`, `delete_caches`, `delete_cache` | `…/actions/caches` and `…/actions/cache/usage`; see [Seeing and deleting entries](#seeing-and-deleting-entries) | |
| A comped workspace's Usage shows what its runs used at cost, not $0.00 spent and a $0.000 average | 2051 | |
| 2052 | Secrets and variables have a tool of their own, `secret`: | |
| 2053 | ||
| 2054 | | `secret` action | Route | | |
| 2055 | | --- | --- | | |
| 2056 | | `list_secrets`, `set_secret`, `delete_secret` | `GET /repos/{owner}/{repo}/actions/secrets`, `PUT` and `DELETE …/secrets/{name}` | | |
| 2057 | | `list_variables`, `set_variable`, `delete_variable` | `GET` and `POST /repos/{owner}/{repo}/actions/variables`, `PATCH` and `DELETE …/variables/{name}` | | |
| 2058 | ||
| 2059 | Workspace secrets and variables are under | |
| 2060 | `/workspaces/{workspace}/actions/secrets` and `…/variables`. The fields | |
| 2061 | g1t adds (environments, who reads a row, linked repositories) are in | |
| 2062 | [Secrets and variables](/guides/secrets-and-variables/#from-the-api). | |
| 2063 | ||
| 2064 | ```sh | |
| 2065 | curl -X POST https://api.g1t.sh/repos/acme/web/actions/workflows/ci.yml/dispatches \ | |
| 2066 | -H "Authorization: Bearer $G1T_TOKEN" -H "Content-Type: application/json" \ | |
| 2067 | -d '{"ref": "main", "inputs": {"environment": "staging"}}' | |
| 2068 | ``` | |
| 2069 | ||
| Merge branch 'worktree-agent-a8b78c62188153aa3' into claude/cool-newton-7nm8r9 | 2070 | Give only the inputs the workflow declares under |
| 2071 | `on.workflow_dispatch.inputs`: a run with any other input is refused, and | |
| 2072 | the answer names the inputs it did not expect. A `boolean` input is `true` | |
| 2073 | or `false`, a `number` a number, a `choice` one of its `options`, and an | |
| 2074 | `environment` the name of one of the repository's | |
| 2075 | [environments](#environments). In the run, the `inputs` context keeps | |
| 2076 | booleans and numbers as they are, and `github.event.inputs` has every | |
| 2077 | input as text, `"true"` and `"3"`, as on GitHub. | |
| 2078 | ||
| Actions: OIDC tokens, the toolkit's cache and artifact services, and artifacts in R2 | 2079 | To save an artifact from a script, follow the redirect: |
| 2080 | ||
| 2081 | ```sh | |
| 2082 | curl -L -o web-dist.zip -H "Authorization: Bearer $G1T_TOKEN" \ | |
| 2083 | https://api.g1t.sh/repos/acme/web/actions/artifacts/4182/zip | |
| 2084 | ``` |
This file's history is long; its oldest lines are credited to the oldest commit read.