> ## Documentation Index
> Fetch the complete documentation index at: https://paper.brimble.io/llms.txt
> Use this file to discover all available pages before exploring further.

# CI runners

> Run your GitHub Actions jobs on Brimble sandboxes by changing one line in a workflow.

A **CI runner** connects a GitHub organization to Brimble so its GitHub Actions jobs run on Brimble sandboxes. You set it up once in the dashboard, then point a workflow at it:

```yaml theme={null}
jobs:
  test:
    runs-on: brimble
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm test
```

Every step in the job runs inside a sandbox, with the same isolation as any other [sandbox](https://paper.brimble.io/sandboxes/overview.md).

> [!NOTE]
>
> CI runners are being rolled out. If **CI runners** isn't in your dashboard sidebar, it isn't enabled for your account yet.

## Before you start

* **A GitHub organization.** CI runners work for repositories owned by an organization. Repositories under a personal GitHub account can't use them.
* **The Brimble GitHub App installed on that organization** and connected to your Brimble account. This is the same app you use to deploy from GitHub. See [Git integrations](https://paper.brimble.io/projects/git-integrations.md).
* **The app's runner permission accepted.** The app asks the organization for permission to manage its self-hosted runners. An organization owner accepts it in GitHub under **Settings**, **GitHub Apps**, **Review request** next to the Brimble app. Until it's accepted, jobs stay queued in GitHub.

Each organization has one runner. All of its repositories that the app can access share it.

## Choose how jobs run

A runner works in one of two ways. You pick when you create it and can switch later while no sandboxes are attached.

| | Long-lived sandboxes (recommended) | Fresh sandbox per job |
| - | - | - |
| What runs the job | A sandbox you attach to the runner. It stays running between jobs. | A new sandbox, started for the job and destroyed when the job ends. |
| Start time | Jobs start right away. | Each job waits for its sandbox to start. |
| Jobs at once | One per attached sandbox. Attach more sandboxes to run more. | Up to the runner's **Max concurrent jobs**. |
| State between jobs | The job's workspace is emptied after each job. Other files in the sandbox, such as installed tools and caches, stay. | None. Every job starts clean. |
| Billing | For as long as the sandbox is attached and running. | Only while each job's sandbox runs. |

## Create a runner

1. In the dashboard, open **CI runners** and click **New runner**.
2. Pick the **GitHub organization** and give the runner a name.
3. Under **How jobs run**, choose **Long-lived sandboxes** or **Fresh sandbox per job**.
4. Fill in the section that matches your choice (below), then create the runner.

![New CI runner form showing the GitHub organization picker, the runner name, the two ways jobs run, and the Runner sandbox section with Create one for me selected](https://mintcdn.com/brimble-86/-jtkA22dP_XB1S9f/images/sandboxes/new-ci-runner-form.jpg?fit=max\&auto=format\&n=-jtkA22dP_XB1S9f\&q=85\&s=d7e30bd26f2069ffe9ef53aa582bc8da)

The New CI runner form with an organization picked, long-lived sandboxes selected, and a runner sandbox set to be created.

### Long-lived sandboxes

Under **Runner sandbox**, choose where the jobs run:

* **Create one for me.** Pick a **Sandbox size** and **Sandbox region**. Brimble creates a sandbox for the runner and attaches it.
* **Use a sandbox I already have.** Pick a ready sandbox that you created from the `github-actions-runner` template. Its size and region are used as they are.

Attaching registers the sandbox with GitHub and starts the runner in it. This can take up to two minutes. When it finishes, the runner shows as online in your organization's runner list in GitHub.

While a sandbox is attached, it doesn't expire, and it's billed for as long as it runs. A long-lived runner is enabled only while it has a sandbox attached. With none attached it is disabled, and you can't enable it until you attach one.

### Fresh sandbox per job

Pick the **Sandbox size** and **Sandbox region** that each job's sandbox uses, and set **Max concurrent jobs**. When more jobs are queued than that, the extra jobs wait in GitHub's queue until a slot frees up.

## Use the runner in a workflow

Set `runs-on` in any workflow in the organization:

```yaml theme={null}
runs-on: brimble
```

To ask for a specific sandbox size, use the size's name as the label:

```yaml theme={null}
runs-on: sbx.small
```

Size labels are the same names you see when you create a sandbox. How a label is matched depends on how the runner runs jobs:

* **Long-lived sandboxes:** `brimble` uses any attached sandbox. A size label only matches an attached sandbox of that size, so `runs-on: sbx.small` waits until a small sandbox is attached and free.
* **Fresh sandbox per job:** `brimble` uses the runner's size. A size label starts a sandbox of that size for the job.

Jobs that ask for anything else, such as `ubuntu-latest`, are left for GitHub's own runners.

## What a job can use

The runner sandbox comes with common toolchains already installed:

| | |
| - | - |
| Languages | Node.js 22 with npm, yarn and pnpm. Python 3. Go. Java 21 with Maven. .NET 8. Ruby. PHP with Composer. Rust. |
| Build tools | gcc, g++, make, cmake, ninja, and the development headers most native packages need. |
| Browser | Google Chrome, for end-to-end tests. |
| Command-line tools | git, git-lfs, the GitHub CLI, the AWS CLI, kubectl, helm, terraform. |
| Database clients | psql, mysql, redis-cli, sqlite3. |

Actions that download a tool into the job's workspace, such as `actions/setup-node`, work as usual. Installing packages for your own user works too: `npm install -g`, `pip install`, `gem install` and `cargo install` all write to locations the job can use.

Jobs can't install system packages with `apt-get`, and they can't run Docker. If a job needs a tool that isn't listed, download it in a step or use an action that sets it up.

Pick a size that fits the work. The smallest size is fine for linting and light scripts. Builds and test suites run noticeably faster on a larger one.

## Manage sandboxes on a long-lived runner

Open the runner. **Attached sandboxes** on its overview shows what's attached and whether each one is online in GitHub.

* **Attach sandbox** adds another sandbox, so more jobs can run at the same time.
* **Detach** stops the runner in that sandbox and removes it from GitHub. The sandbox itself is not deleted, and it goes back to its normal expiry.

If a runner goes offline while its sandbox is still running, Brimble restarts it. If the sandbox is destroyed, it is detached from the runner.

## See your jobs

The **Jobs** tab on a runner lists the GitHub Actions jobs that asked for it, newest first, with the repository, the job name, its status, and the sandbox it ran on. Open a job in GitHub to read its logs.

![A CI runner's Jobs tab showing succeeded, failed and cancelled GitHub Actions jobs with their repository, status, runner name, queue time and duration](https://mintcdn.com/brimble-86/-jtkA22dP_XB1S9f/images/sandboxes/ci-runner-jobs.jpg?fit=max\&auto=format\&n=-jtkA22dP_XB1S9f\&q=85\&s=00ee9f6910c786cd34c32bd93b0f25e6)

The Jobs tab of a runner, listing each job with its repository, label, status, the runner sandbox it ran on, and how long it took.

## Disable or delete a runner

Both are in the runner's **Settings**. **Disable runner** detaches every attached sandbox and stops Brimble running jobs for the organization. **Delete runner** does the same and removes the runner. Neither deletes your sandboxes.

Jobs that still say `runs-on: brimble` after that stay queued in GitHub, so change those workflows back first.

## Troubleshooting

**A job stays queued in GitHub and never shows up under Jobs.**
The organization hasn't accepted the Brimble app's runner permission. An organization owner can accept it in GitHub under **Settings**, **GitHub Apps**.

**A job stays queued on a long-lived runner.**
Check **Attached sandboxes** on the runner. The job needs an attached sandbox that is online and not already running another job. If the workflow uses a size label, an attached sandbox must have that size.

**Jobs from a public repository stay queued.**
GitHub doesn't send jobs from public repositories to an organization's runners unless the organization allows it. An owner can change this in GitHub under **Settings**, **Actions**, **Runner groups**, by allowing public repositories on the default group.

**Attaching a sandbox fails.**
The sandbox must be ready and created from the `github-actions-runner` template. A sandbox that was created some time ago may predate runner support. Choose **Create one for me** to get a new one.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.