CI runners
Run GitHub Actions jobs in a fresh Space each on your own computers (an experiment: `cua experiments enable ci-runners`).
| Command | Description |
|---|---|
cua ci connect | Connect this computer to Cua CI: sign in, install the hosted GitHub app on your organization (you pick the repositories), and serve jobs here. |
cua ci add | Add capacity: a computer over SSH. |
cua ci remove | Remove capacity added with cua ci add: ends the computers Cua started there (only the ones it recorded and tagged), then forgets the target. |
cua ci status | What Cua CI is doing: computers and free slots, waiting and running jobs, the last 7 days, and this month's spend against the budget. |
cua ci overview | Everything the CI Runners page shows, as JSON: setup steps, the repositories that ran jobs, usage over the last 7 days, the jobs table (wait, run, cost, computer, cloud), the autopilot's reasons and the budget. |
cua ci why | Why capacity looks the way it does: what Cua chose from your job history (computers kept ready, idle time, spot or on-demand) and the reason for each, in plain words. |
cua ci config | Which repositories Cua CI serves, how fork pull requests are treated, concurrency caps and the monthly budget. |
cua ci disconnect | Stop serving jobs on this computer and remove it from Cua CI. |
cua ci serve | Run what this computer serves in the foreground (what the service runs): Cua CI jobs, or a pool of your own GitHub App with --pool. |
cua ci ls | An own-app pool's runners now: Space, runner, state and age. |
cua ci logs | Recent jobs; or one job's timeline and Cua CI log (the job's own step logs stay at GitHub). |
cua ci stop | Stop an own-app pool's service (idle runners stay until it starts again). |
cua ci start | Start an own-app pool's service again. |
cua ci cache | Empty the dependency caches and repository mirrors of this computer's pools, for a cold run (jobs restore nothing and the first checkout fetches in full). |
cua ci cache clear | Delete the caches, mirrors and golden saved starts. |
Every command also accepts the global options.
Cua CI, GitHub Actions jobs on Cua Spaces: each job runs in a fresh Space (a macOS VM or a Linux container or VM) registered with a just-in-time runner, then deleted. Connect this computer, then use runs-on: cua. An experiment: cua experiments enable ci-runners.
cua ci [OPTIONS] <COMMAND>Examples
cua ci connect
cua ci status
cua ci logs
cua ci config --budget 50
cua ci disconnectcua ci connect#
Connect this computer to Cua CI: sign in, install the hosted GitHub app on your organization (you pick the repositories), and serve jobs here. Prints the runs-on line for your workflows.
cua ci connect [OPTIONS]| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--team | string | A Cua organization to connect (id, alias or name); default: your own account. | ||
--allow | string | Serve jobs of this repository (owner/name, repeatable). Default: the ones you pick, or ask. | ||
--workflows | string | With --open-pr: change only these workflow files. Repeatable. | ||
--macos-slots | integer | macOS jobs at once on this computer (default 2 on Apple silicon; at most 2 per Mac). | ||
--linux-slots | integer | Linux jobs at once on this computer (default: one per 4 cores). | ||
--macos-image | string | The image macOS jobs start from. | ||
--linux-image | string | The image Linux jobs start from. | ||
--name | string | The name shown in cua ci status (default: this computer's name). | ||
--cloud | string | Also add a cloud right away (aws, gcp, azure, hetzner, modal, macstadium): the same as cua ci add after connecting. Not in this build yet. | ||
--org | string | The GitHub organization: the one to install the Cua CI app on, or with --own-app the organization to register runners for (--org trycua). | ||
--repo | string | With --own-app: register runners for one repository (--repo owner/name). | ||
--pool | string | The pool's name (default: the organization, or owner-name). | ||
--group | string | The organization runner group runners join (default: the organization's default group). Restrict it to selected repositories at GitHub. | ||
--labels | string | Labels besides self-hosted, the OS, the architecture and cua (comma-separated). Repeatable. | ||
--image | string | ghcr.io/trycua/macos:26 | The image each runner's Space starts from: a registry image, or checkpoint:<name> (a golden image saved with cua sb checkpoint, with --os). | |
--os | macos | linux | The image's OS, macos or linux (default: from the image's name; needed for a checkpoint). | ||
--on | string | local | Where job Spaces run: local (this computer), auto (any of your computers) or host:<computer>. | |
--max | integer | 2 | At most this many runners at once (macOS on one computer: at most 2). | |
--warm | integer | Idle runners to keep ready (default: --max). | ||
--cpus | integer | vCPUs per runner (default for macOS here: half this Mac's cores per runner). | ||
--memory-mb | integer | Memory per runner in MiB (default for macOS here: this Mac's memory less 8 GiB split between the runners, at most 8 GiB). | ||
--disk-gb | integer | Disk per runner in GiB (default: the image's). | ||
--job-timeout | string | 6h | Stop a job that runs longer (its Space is deleted). | |
--idle-timeout | string | 60m | Replace an idle runner after this long. | |
--egress | deny-private | off | deny-private | deny-private (default): runner Spaces cannot reach private, tailnet, link-local or unique-local addresses; off. | |
--app-id | integer | The GitHub App's id. | ||
--installation-id | integer | The App's installation id (default: looked up). | ||
--private-key-file | path | The App's private key (.pem). Delete the file afterwards: the key is kept in the keychain. | ||
--key-file | path | Keep the App's private key in this file instead of the keychain (it must be yours, mode 0600). For a headless host or one set up over SSH, whose login keychain cannot be used. The pool reads it on every start; nothing is copied. | ||
--secret-store | keychain | file | keychain | Where the credential is kept: keychain (the login keychain on macOS) or file (a file only you can read under ~/.cua/ci/secrets/; for a Mac set up over SSH, whose keychain is locked). | |
--api-url | string | https://api.github.com | The GitHub REST API (GitHub Enterprise Server: https://HOST/api/v3). | |
--own-app | boolean | false | Use your own GitHub App (its key kept in the keychain or a file only you can read) and no Cua service, for self-hosting. --org or --repo and the App options below go with it. | |
--open-pr | boolean | false | Open a pull request in each served repository that points its workflows at Cua CI (it uses your own GitHub sign-in: gh auth login, or GH_TOKEN). Nothing is pushed to the default branch. | |
--yes | -y | boolean | false | Do not ask. |
--no-browser | boolean | false | Print the sign-in and GitHub links instead of opening a browser. | |
--require-egress | boolean | false | Refuse to start runners where egress cannot be enforced (macOS VMs today) instead of starting them without it. | |
--private-key-stdin | boolean | false | Read the App's private key from stdin. | |
--token-stdin | boolean | false | Read a GitHub token from stdin instead of using an App. | |
--no-service | boolean | false | Write the configuration without installing the service (run cua ci serve yourself). | |
--no-verify | boolean | false | Do not check the credential with GitHub. |
Examples
# The usual way: sign in, install the app on GitHub in your browser, serve jobs
cua ci connect
# Serve only these repositories, and open a pull request that changes their workflows
cua ci connect --allow acme/app --allow acme/api --open-pr
# A headless Mac over SSH: print the links instead of opening a browser
cua ci connect --no-browser
# Your own GitHub App with its key in a 0600 file (self-hosting, no Cua service)
cua ci connect --own-app --org trycua --app-id 123456 --key-file ~/.cua/ci/github-app.pemcua ci add#
Add capacity: a computer over SSH. host USER@ADDRESS installs and joins any rented or owned computer, which then serves jobs as one more computer. Cloud accounts are not in this build yet.
cua ci add [OPTIONS] <TARGET> [ADDRESS]| Argument | Type | Default | Description |
|---|---|---|---|
<TARGET> | string | required | aws, gcp, azure, hetzner, modal, macstadium or host. |
<ADDRESS> | string | optional | For host: its SSH address (USER@ADDRESS). |
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--budget | number | Monthly budget in dollars (default: asked once, 50). | ||
--max-per-hour | number | Hard cap in dollars an hour (default: a twentieth of the budget). | ||
--warm | integer | Fix how many free slots are kept ready so a job does not wait for a computer to boot (0: never). Without it Cua chooses from your own job history, inside the budget. Never on Mac hosts. | ||
--goal | cheapest | balanced | fastest | What Cua optimizes when it chooses: cheapest (lowest bill), balanced (default) or fastest (shortest starts). The budget stays a hard limit for all three. | ||
--region | string | Region or location (default: the nearest one). | ||
--account-id | string | AWS: the 12-digit account id (found automatically when aws is signed in on this computer). | ||
--project-number | string | Google Cloud: the project number the trust step prints. | ||
--subscription | string | Azure: the subscription id. | ||
--tenant | string | Azure: the Microsoft Entra tenant id. | ||
--client-id | string | Azure: the managed identity's client id. | ||
--key | string | host: a private key file for the SSH login. With it Cua manages the computer itself (installs and removes its own units over SSH, keeps the key in this computer's keychain, runs jobs in isolated Spaces on it). Without it the computer signs in to Cua on its own. | ||
--host-key | string | host: the computer's public host key as <type> <base64> (default: fetched with ssh-keyscan and confirmed by its fingerprint). | ||
--monthly | number | host: what the computer costs a month in dollars when rented (default: yours, free). | ||
--macos | boolean | false | AWS: Mac hosts for macOS jobs (billed at least 24 hours a host). | |
--yes | -y | boolean | false | Do not ask. |
--no-browser | boolean | false | Print links instead of opening a browser. | |
--token-stdin | boolean | false | Hetzner, Modal, MacStadium: read the token from stdin. | |
--key-stdin | boolean | false | host: read the private key from stdin. |
Examples
cua ci add host root@build.example.comcua ci remove#
Remove capacity added with cua ci add: ends the computers Cua started there (only the ones it recorded and tagged), then forgets the target.
cua ci remove [OPTIONS] <TARGET> [ADDRESS]| Argument | Type | Default | Description |
|---|---|---|---|
<TARGET> | string | required | aws, gcp, azure, hetzner, modal, macstadium or host. |
<ADDRESS> | string | optional | For host: its SSH address. |
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--yes | -y | boolean | false | Do not ask. |
Examples
cua ci remove host root@build.example.comcua ci status#
What Cua CI is doing: computers and free slots, waiting and running jobs, the last 7 days, and this month's spend against the budget. Pools of your own GitHub App show with --pool.
cua ci status [OPTIONS]| Flag | Type | Default | Description |
|---|---|---|---|
--pool | string | A pool made with connect --own-app (default: Cua CI, else every pool). |
Examples
cua ci status
cua ci status --json
cua ci status --pool trycuacua ci overview#
Everything the CI Runners page shows, as JSON: setup steps, the repositories that ran jobs, usage over the last 7 days, the jobs table (wait, run, cost, computer, cloud), the autopilot's reasons and the budget. Read from this computer's own records, no network (--live adds the repositories the service lists).
cua ci overview [OPTIONS]| Flag | Type | Default | Description |
|---|---|---|---|
--live | boolean | false | Also ask the service which repositories the GitHub app can see and which of them may run jobs (needs the network). |
Examples
cua ci overview
cua ci overview --livecua ci why#
Why capacity looks the way it does: what Cua chose from your job history (computers kept ready, idle time, spot or on-demand) and the reason for each, in plain words.
cua ci why [OPTIONS] [TARGET]| Argument | Type | Default | Description |
|---|---|---|---|
<TARGET> | string | optional | A target (aws, hetzner, ...); default: every target. |
Examples
cua ci why
cua ci why awscua ci config#
Which repositories Cua CI serves, how fork pull requests are treated, concurrency caps and the monthly budget. With no options it shows the current settings.
cua ci config [OPTIONS]| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--allow | string | Serve jobs of this repository (owner/name, repeatable). | ||
--remove | string | Stop serving this repository (repeatable). | ||
--fork-prs | restricted | deny | allow | Fork pull requests: restricted (default: no secrets, read-only caches, no private network), deny (never served) or allow. | ||
--repo | string | Apply --fork-prs and --max-jobs to this repository only. | ||
--max-jobs | string | Jobs at once (a number, or none). | ||
--max-macos-jobs | string | macOS jobs at once (a number, or none). | ||
--max-job-minutes | string | The longest a job may run, in minutes (a number, or none). | ||
--queue-timeout | string | The longest a job waits for capacity (15m, or none). | ||
--budget | string | Monthly budget in dollars for cloud computers (50, or none). With none set, cloud computers are not used. | ||
--on-budget-limit | stop | warn | At the budget limit: stop (default) sends no more jobs to cloud computers; warn only warns. | ||
--budget-scope | byoc | all | What the budget counts: byoc (cloud computers, default) or all. | ||
--egress | deny-private | off | Network for jobs: deny-private (default) keeps them off your private network and tailnet; off. | ||
--allow-org-wide | boolean | false | Accept owner/* in --allow (every repository of an owner). | |
--yes | -y | boolean | false | Confirm the changes that widen what jobs may do. |
Examples
cua ci config
cua ci config --allow acme/api
cua ci config --fork-prs deny
cua ci config --max-jobs 4 --max-macos-jobs 2 --max-job-minutes 90
cua ci config --budget 50 --on-budget-limit stop
cua ci config --repo acme/app --fork-prs restricted --max-jobs 2cua ci disconnect#
Stop serving jobs on this computer and remove it from Cua CI. The GitHub app stays installed unless you ask. For a pool of your own GitHub App, --pool removes it (its Spaces, runners and key).
cua ci disconnect [OPTIONS]| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--repo | string | Stop serving this repository only (repeatable). | ||
--pool | string | A pool made with connect --own-app. | ||
--all-machines | boolean | false | Remove every computer of the account, not just this one. | |
--unlink | boolean | false | Also unlink the GitHub installation (removes Cua's runner group and runners). | |
--uninstall | boolean | false | Also uninstall the Cua CI app from GitHub. | |
--yes | -y | boolean | false | Do not ask. |
Examples
cua ci disconnect
cua ci disconnect --repo acme/old
cua ci disconnect --all-machines --unlink
cua ci disconnect --pool trycua --yescua ci serve#
Run what this computer serves in the foreground (what the service runs): Cua CI jobs, or a pool of your own GitHub App with --pool.
cua ci serve [OPTIONS]| Flag | Type | Default | Description |
|---|---|---|---|
--pool | string | A pool made with connect --own-app (default: Cua CI). | |
--once | boolean | false | One reconcile pass of an own-app pool (create, check and clean up), then exit. |
Examples
cua ci serve
cua ci serve --pool trycua
# One pass of an own-app pool, then exit
cua ci serve --pool trycua --oncecua ci ls#
An own-app pool's runners now: Space, runner, state and age.
cua ci ls [OPTIONS]Alias: cua ci list.
| Flag | Type | Default | Description |
|---|---|---|---|
--pool | string | The pool (default: every pool). |
Examples
cua ci ls
cua ci ls --pool trycua --jsoncua ci logs#
Recent jobs; or one job's timeline and Cua CI log (the job's own step logs stay at GitHub). An own-app pool's events with --pool.
cua ci logs [OPTIONS] [JOB]| Argument | Type | Default | Description |
|---|---|---|---|
<JOB> | string | optional | A job: its run/job key or id (default: list recent jobs). |
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--repo | string | Only this repository's jobs. | ||
--limit | integer | 30 | How many jobs to list. | |
--pool | string | A pool made with connect --own-app. | ||
--slot | string | A runner slot of that pool (cua ci ls, or the event log). | ||
--events | integer | 40 | How many recent events of that pool to show. | |
--follow | -f | boolean | false | Keep showing new lines until the job ends. |
Examples
cua ci logs
cua ci logs --repo acme/app
cua ci logs 9912345678/27300000111
cua ci logs job_01HZX --follow
cua ci logs --pool trycua --slot 3f9a12c0cua ci stop#
Stop an own-app pool's service (idle runners stay until it starts again).
cua ci stop [OPTIONS]| Flag | Type | Default | Description |
|---|---|---|---|
--pool | string | The pool (default: the only one). |
Examples
cua ci stop --pool trycuacua ci start#
Start an own-app pool's service again.
cua ci start [OPTIONS]| Flag | Type | Default | Description |
|---|---|---|---|
--pool | string | The pool (default: the only one). |
Examples
cua ci start --pool trycuacua ci cache#
Empty the dependency caches and repository mirrors of this computer's pools, for a cold run (jobs restore nothing and the first checkout fetches in full).
cua ci cache [OPTIONS] <COMMAND>Examples
cua ci cache clear
cua ci cache clear --pool trycuacua ci cache clear#
Delete the caches, mirrors and golden saved starts.
cua ci cache clear [OPTIONS]| Flag | Type | Default | Description |
|---|---|---|---|
--pool | string | Only this pool (default: every pool of this computer). |
Examples
cua ci cache clear
cua ci cache clear --pool trycuaExit codes#
| Code | Meaning |
|---|---|
0 | Success. |
1 | Failure, or cua do reported an error. |
2 | Invalid argument, or an ambiguous sandbox name (qualify it: local:NAME). |
3 | Not found: sandbox, window, skill or image (or an image not published yet). |
4 | Not supported, or not configured (for example no provider credentials). |
5 | No cua-spacesd answered, or a transport failure. |
6 | Unauthenticated or permission denied (by Cua or your cloud account). |
7 | Not enough free disk space (see cua cache). |
8 | No room on the machine: its VMs are at their memory or CPU limit, or it is low on memory. |
130 | Cancelled (Ctrl-C during a create): what it made was removed. |