CI runners

Run GitHub Actions jobs in a fresh Space each on your own computers (an experiment: `cua experiments enable ci-runners`).

CommandDescription
cua ci connectConnect 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 addAdd capacity: a computer over SSH.
cua ci removeRemove 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 statusWhat 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 overviewEverything 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 whyWhy 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 configWhich repositories Cua CI serves, how fork pull requests are treated, concurrency caps and the monthly budget.
cua ci disconnectStop serving jobs on this computer and remove it from Cua CI.
cua ci serveRun 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 lsAn own-app pool's runners now: Space, runner, state and age.
cua ci logsRecent jobs; or one job's timeline and Cua CI log (the job's own step logs stay at GitHub).
cua ci stopStop an own-app pool's service (idle runners stay until it starts again).
cua ci startStart an own-app pool's service again.
cua ci cacheEmpty 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 clearDelete 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 disconnect

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. Prints the runs-on line for your workflows.

cua ci connect [OPTIONS]
FlagShortTypeDefaultDescription
--teamstringA Cua organization to connect (id, alias or name); default: your own account.
--allowstringServe jobs of this repository (owner/name, repeatable). Default: the ones you pick, or ask.
--workflowsstringWith --open-pr: change only these workflow files. Repeatable.
--macos-slotsintegermacOS jobs at once on this computer (default 2 on Apple silicon; at most 2 per Mac).
--linux-slotsintegerLinux jobs at once on this computer (default: one per 4 cores).
--macos-imagestringThe image macOS jobs start from.
--linux-imagestringThe image Linux jobs start from.
--namestringThe name shown in cua ci status (default: this computer's name).
--cloudstringAlso add a cloud right away (aws, gcp, azure, hetzner, modal, macstadium): the same as cua ci add after connecting. Not in this build yet.
--orgstringThe GitHub organization: the one to install the Cua CI app on, or with --own-app the organization to register runners for (--org trycua).
--repostringWith --own-app: register runners for one repository (--repo owner/name).
--poolstringThe pool's name (default: the organization, or owner-name).
--groupstringThe organization runner group runners join (default: the organization's default group). Restrict it to selected repositories at GitHub.
--labelsstringLabels besides self-hosted, the OS, the architecture and cua (comma-separated). Repeatable.
--imagestringghcr.io/trycua/macos:26The image each runner's Space starts from: a registry image, or checkpoint:<name> (a golden image saved with cua sb checkpoint, with --os).
--osmacos | linuxThe image's OS, macos or linux (default: from the image's name; needed for a checkpoint).
--onstringlocalWhere job Spaces run: local (this computer), auto (any of your computers) or host:<computer>.
--maxinteger2At most this many runners at once (macOS on one computer: at most 2).
--warmintegerIdle runners to keep ready (default: --max).
--cpusintegervCPUs per runner (default for macOS here: half this Mac's cores per runner).
--memory-mbintegerMemory per runner in MiB (default for macOS here: this Mac's memory less 8 GiB split between the runners, at most 8 GiB).
--disk-gbintegerDisk per runner in GiB (default: the image's).
--job-timeoutstring6hStop a job that runs longer (its Space is deleted).
--idle-timeoutstring60mReplace an idle runner after this long.
--egressdeny-private | offdeny-privatedeny-private (default): runner Spaces cannot reach private, tailnet, link-local or unique-local addresses; off.
--app-idintegerThe GitHub App's id.
--installation-idintegerThe App's installation id (default: looked up).
--private-key-filepathThe App's private key (.pem). Delete the file afterwards: the key is kept in the keychain.
--key-filepathKeep 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-storekeychain | filekeychainWhere 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-urlstringhttps://api.github.comThe GitHub REST API (GitHub Enterprise Server: https://HOST/api/v3).
--own-appbooleanfalseUse 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-prbooleanfalseOpen 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-ybooleanfalseDo not ask.
--no-browserbooleanfalsePrint the sign-in and GitHub links instead of opening a browser.
--require-egressbooleanfalseRefuse to start runners where egress cannot be enforced (macOS VMs today) instead of starting them without it.
--private-key-stdinbooleanfalseRead the App's private key from stdin.
--token-stdinbooleanfalseRead a GitHub token from stdin instead of using an App.
--no-servicebooleanfalseWrite the configuration without installing the service (run cua ci serve yourself).
--no-verifybooleanfalseDo 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.pem

cua 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]
ArgumentTypeDefaultDescription
<TARGET>stringrequiredaws, gcp, azure, hetzner, modal, macstadium or host.
<ADDRESS>stringoptionalFor host: its SSH address (USER@ADDRESS).
FlagShortTypeDefaultDescription
--budgetnumberMonthly budget in dollars (default: asked once, 50).
--max-per-hournumberHard cap in dollars an hour (default: a twentieth of the budget).
--warmintegerFix 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.
--goalcheapest | balanced | fastestWhat Cua optimizes when it chooses: cheapest (lowest bill), balanced (default) or fastest (shortest starts). The budget stays a hard limit for all three.
--regionstringRegion or location (default: the nearest one).
--account-idstringAWS: the 12-digit account id (found automatically when aws is signed in on this computer).
--project-numberstringGoogle Cloud: the project number the trust step prints.
--subscriptionstringAzure: the subscription id.
--tenantstringAzure: the Microsoft Entra tenant id.
--client-idstringAzure: the managed identity's client id.
--keystringhost: 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-keystringhost: the computer's public host key as <type> <base64> (default: fetched with ssh-keyscan and confirmed by its fingerprint).
--monthlynumberhost: what the computer costs a month in dollars when rented (default: yours, free).
--macosbooleanfalseAWS: Mac hosts for macOS jobs (billed at least 24 hours a host).
--yes-ybooleanfalseDo not ask.
--no-browserbooleanfalsePrint links instead of opening a browser.
--token-stdinbooleanfalseHetzner, Modal, MacStadium: read the token from stdin.
--key-stdinbooleanfalsehost: read the private key from stdin.

Examples

cua ci add host root@build.example.com

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 remove [OPTIONS] <TARGET> [ADDRESS]
ArgumentTypeDefaultDescription
<TARGET>stringrequiredaws, gcp, azure, hetzner, modal, macstadium or host.
<ADDRESS>stringoptionalFor host: its SSH address.
FlagShortTypeDefaultDescription
--yes-ybooleanfalseDo not ask.

Examples

cua ci remove host root@build.example.com

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. Pools of your own GitHub App show with --pool.

cua ci status [OPTIONS]
FlagTypeDefaultDescription
--poolstringA pool made with connect --own-app (default: Cua CI, else every pool).

Examples

cua ci status
cua ci status --json
cua ci status --pool trycua

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. Read from this computer's own records, no network (--live adds the repositories the service lists).

cua ci overview [OPTIONS]
FlagTypeDefaultDescription
--livebooleanfalseAlso 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 --live

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 why [OPTIONS] [TARGET]
ArgumentTypeDefaultDescription
<TARGET>stringoptionalA target (aws, hetzner, ...); default: every target.

Examples

cua ci why
cua ci why aws

cua 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]
FlagShortTypeDefaultDescription
--allowstringServe jobs of this repository (owner/name, repeatable).
--removestringStop serving this repository (repeatable).
--fork-prsrestricted | deny | allowFork pull requests: restricted (default: no secrets, read-only caches, no private network), deny (never served) or allow.
--repostringApply --fork-prs and --max-jobs to this repository only.
--max-jobsstringJobs at once (a number, or none).
--max-macos-jobsstringmacOS jobs at once (a number, or none).
--max-job-minutesstringThe longest a job may run, in minutes (a number, or none).
--queue-timeoutstringThe longest a job waits for capacity (15m, or none).
--budgetstringMonthly budget in dollars for cloud computers (50, or none). With none set, cloud computers are not used.
--on-budget-limitstop | warnAt the budget limit: stop (default) sends no more jobs to cloud computers; warn only warns.
--budget-scopebyoc | allWhat the budget counts: byoc (cloud computers, default) or all.
--egressdeny-private | offNetwork for jobs: deny-private (default) keeps them off your private network and tailnet; off.
--allow-org-widebooleanfalseAccept owner/* in --allow (every repository of an owner).
--yes-ybooleanfalseConfirm 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 2

cua 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]
FlagShortTypeDefaultDescription
--repostringStop serving this repository only (repeatable).
--poolstringA pool made with connect --own-app.
--all-machinesbooleanfalseRemove every computer of the account, not just this one.
--unlinkbooleanfalseAlso unlink the GitHub installation (removes Cua's runner group and runners).
--uninstallbooleanfalseAlso uninstall the Cua CI app from GitHub.
--yes-ybooleanfalseDo not ask.

Examples

cua ci disconnect
cua ci disconnect --repo acme/old
cua ci disconnect --all-machines --unlink
cua ci disconnect --pool trycua --yes

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 serve [OPTIONS]
FlagTypeDefaultDescription
--poolstringA pool made with connect --own-app (default: Cua CI).
--oncebooleanfalseOne 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 --once

cua ci ls#

An own-app pool's runners now: Space, runner, state and age.

cua ci ls [OPTIONS]

Alias: cua ci list.

FlagTypeDefaultDescription
--poolstringThe pool (default: every pool).

Examples

cua ci ls
cua ci ls --pool trycua --json

cua 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]
ArgumentTypeDefaultDescription
<JOB>stringoptionalA job: its run/job key or id (default: list recent jobs).
FlagShortTypeDefaultDescription
--repostringOnly this repository's jobs.
--limitinteger30How many jobs to list.
--poolstringA pool made with connect --own-app.
--slotstringA runner slot of that pool (cua ci ls, or the event log).
--eventsinteger40How many recent events of that pool to show.
--follow-fbooleanfalseKeep 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 3f9a12c0

cua ci stop#

Stop an own-app pool's service (idle runners stay until it starts again).

cua ci stop [OPTIONS]
FlagTypeDefaultDescription
--poolstringThe pool (default: the only one).

Examples

cua ci stop --pool trycua

cua ci start#

Start an own-app pool's service again.

cua ci start [OPTIONS]
FlagTypeDefaultDescription
--poolstringThe pool (default: the only one).

Examples

cua ci start --pool trycua

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 [OPTIONS] <COMMAND>

Examples

cua ci cache clear
cua ci cache clear --pool trycua

cua ci cache clear#

Delete the caches, mirrors and golden saved starts.

cua ci cache clear [OPTIONS]
FlagTypeDefaultDescription
--poolstringOnly this pool (default: every pool of this computer).

Examples

cua ci cache clear
cua ci cache clear --pool trycua

Exit codes#

CodeMeaning
0Success.
1Failure, or cua do reported an error.
2Invalid argument, or an ambiguous sandbox name (qualify it: local:NAME).
3Not found: sandbox, window, skill or image (or an image not published yet).
4Not supported, or not configured (for example no provider credentials).
5No cua-spacesd answered, or a transport failure.
6Unauthenticated or permission denied (by Cua or your cloud account).
7Not enough free disk space (see cua cache).
8No room on the machine: its VMs are at their memory or CPU limit, or it is low on memory.
130Cancelled (Ctrl-C during a create): what it made was removed.