SkillAgentSearch skills...

Cilicon

🛠️ Self-Hosted ephemeral macOS CI on Apple Silicon

Install / Use

/learn @traderepublic/Cilicon

README

<p align="center"> <a href="https://github.com/traderepublic/Cilicon/"><img width="350" src="https://user-images.githubusercontent.com/1622982/204773431-050cc008-029c-4ab1-98a6-9d4fc30d272d.png" alt="Cilicon" /></a><br /><br /> Self-Hosted macOS CI on Apple Silicon<br /><br /> <a href="#-about-cilicon">About</a> • <a href="#-getting-started">Getting Started</a> • <a href="#-ideas-for-the-future">Ideas for the Future</a> • <a href="#-join-us">Join Us</a> </p>

[!WARNING] There seems to be an issue with swift-nio based SSH on macOS 15.0-15.3.X. Please use macOS 15.4+ for a more reliable experience.

<details><summary><h3>💥 What's new in 2.0?</h3></summary> We're excited to announce a new major update to Cilicon! Here's a summary of what's new: <ul> <li>While Cilicon 1.0 relied on a user-defined Login Item script in the VM, its new version now includes an SSH client and directly executes commands on the VM.</li> <li>Cilicon has partially adopted the <a href="https://github.com/cirruslabs/tart">tart</a> image format and can automatically convert 1.0 images to it.</li> <li>The integrated OCI client can download pre-built CI images that have been created with/for tart. We recommend their <a href="https://github.com/cirruslabs/macos-image-templates/pkgs/container/macos-sonoma-xcode">macos-sonoma-xcode</a> images.</li> </ul> <h4>Migrating from 1.0</h4> <ul> <li>The config file schema has changed slightly. In most cases renaming the <code>vmBundlePath</code> property to <code>source</code> should suffice.</li> <li>When Cilicon detects a 1.0 image it will offer you to automatically convert it to the new format for you.</li> <li>When converting an image from the 1.0 format, you must enable SSH and set the respective credentials in the config (or use the default <code>admin:admin</code>).</li> </ul> </details>

🔁 About Cilicon

Cilicon is a macOS App that leverages Apple's Virtualization Framework to create, provision and run ephemeral CI VMs with near-native performance. It currently supports Github Actions, Buildkite Agent, GitLab Runner and arbitrary scripts. Depending on your setup, should be able to get up and running with your self-hosted CI in minutes 🚀

Cilicon operates in a very simple cycle described below:

<table> <tr> <td><img width="500" alt="Cilicon Cycle" src="https://github.com/traderepublic/Cilicon/assets/1622982/0774ad39-4c86-4f23-ab27-5be4c89fa8f8"> </br><p align="center"><i>The Cilicon Cycle</i></p></td> <td><img width="600" alt="Cilicon Cycle" src="https://github.com/traderepublic/Cilicon/assets/1622982/31a0e031-4938-4d42-bc75-6ee29269abe4"> </br><p align="center"><i>Running a sample job via GitHub Actions (2x playback)</i></p></td> </tr> </table>

🚀 Getting Started

To get started, download the latest release here.

✨ Choosing a Source

Cilicon uses the tart container format and comes with an integrated OCI client to fetch images from the internet.

It's recommended to use publicly hosted images, however if you need to create or customize your own image, you may use tart.

⚠️ Important

  • When choosing an OCI hosted image, make sure to prepend the oci:// scheme to the url. Cilicon will otherwise assume a local filesystem path.
  • Don't use the latest tag when choosing an image version. Instead pick the specific version of Xcode you would like to have installed (e.g. 14.3).
  • Images downloaded via OCI will reside in the ~/.tart folder which should be cleared of unused images periodically.
  • Images with newer versions of macOS may be published with the same version of Xcode installed. In case you want to upgrade, you may need to manually delete the outdated image and start Cilicon again.

⚙️ Configuration

Cilicon expects a cilicon.yml file to be present in the Host OS's home directory. For more information on all available settings see Config.swift.

GitHub Actions

To use the GitHub Actions provisioner you will need to create and install a new GitHub App with Self-hosted runners Read & Write permissions on the organization level and download the private key file to be referenced in the configuration file.

source: oci://ghcr.io/cirruslabs/macos-runner:sequoia
provisioner:
  type: github
  config:
    appId: <APP_ID>
    organization: <ORGANIZATION_SLUG>
    privateKeyPath: ~/github.pem

GitLab Runner

To use the GitLab Runner provisioner you will need to create a runner with an authentication token.

Minimal example:

source: oci://ghcr.io/cirruslabs/macos-runner:sequoia
provisioner:
  type: gitlab
  config:
    gitlabURL: <GITLAB_INSTANCE_URL>
    runnerToken: <RUNNER_TOKEN>

Full configuration:

source: oci://ghcr.io/cirruslabs/macos-runner:sequoia
provisioner:
  type: gitlab
  config:
    gitlabURL: <GITLAB_INSTANCE_URL>
    runnerToken: <RUNNER_TOKEN>
    executor: <EXECUTOR> # defaults to 'shell'
    maxNumberOfBuilds: <MAX_BUILDS> # defaults to '1'
    downloadLatest: <DOWNLOAD_LATEST> # defaults to 'true'. If 'false' it expects the binary to be present at the user's home directory
    downloadURL: <DOWNLOAD_URL> # defaults to GitLab official S3 bucket
    tomlPath: <PATH_TO_TOML> # defaults to `nil`. If set, it ignores the other runner related variables and passes the specified path to the runner executable
consoleDevices:
  - tart-version-2
sshConnectMaxRetries: <SSH_CONNECT_MAX_RETRIES> # defaults to 10

Buildkite Agent

To use the Buildkite Agent provisioner, simply set your agent token in the provisioner config.

source: oci://ghcr.io/cirruslabs/macos-runner:sequoia
provisioner:
  type: buildkite
  config:
    agentToken: <AGENT_TOKEN>

Script

If you want to run a script (e.g. to start a runner that's not natively supported), you may use the script provisioner.

source: oci://ghcr.io/cirruslabs/macos-runner:sequoia
provisioner:
  type: script
  config:
     run: |
     	echo "Hello World"
        sleep 10

Console Devices

Cilicon supports injecting console devices into the VM configuration. This is particularly useful for compatibility with tools like tart-guest-agent which expect specific console devices to be present.

To add console devices, use the consoleDevices field in your configuration:

consoleDevices:
  - tart-version-2

SSH Connect Retries

After the VM starts, Cilicon connects to the guest over SSH to run any preRun/postRun commands and the provisioner. Some images may take a while before the SSH service is ready. Use sshConnectMaxRetries to control how many connection attempts Cilicon will make before giving up (default: 10).

Example:

sshConnectMaxRetries: 20

Liveness Probe

The liveness probe monitors the health of your VM during job execution. It periodically executes a shell command via SSH, and if the command fails (exits with non-zero status), Cilicon will automatically restart the VM. This helps ensure reliability by detecting and recovering from stuck or failed jobs.

Configuration options:

  • command: Shell command to execute for health check (required)
  • interval: Time in seconds between health checks (default: 30)
  • delay: Initial delay in seconds before starting probes (default: 60)

The probe will restart the VM if the command exits with a non-zero code. Temporary SSH connection errors are logged but won't trigger a restart.

Example for GitHub Actions (with default values):

provisioner:
  type: github
  config:
    appId: <APP_ID>
    organization: <ORGANIZATION_SLUG>
    privateKeyPath: ~/github.pem
    livenessProbe:
      command: "pgrep -fl /Users/admin/actions-runner/run.sh"
      interval: 30
      delay: 60

Note: The liveness probe is currently only supported for the GitHub Actions provisioner. By default, it checks if the GitHub Actions runner process is running. You can customize the probe command to check for other conditions specific to your setup.

🔨 Setting Up the Host OS

It is recommended to use Cilicon on a macOS device fully dedicated to the task, ideally one that is freshly restored.

If you don't want to host your machine locally, OakHost provides great value dedicated Macs and are kindly offering 10% off the first two months for new customers with the code CILICON10 (Disclaimer: We do not receive any form of compensation from sharing this code).

  • Transfer Cilicon.app, cilicon.yml as well as any other files referenced by your config (e.g. Local image, GitHub private key etc.) to your Host OS.
  • Add Cilicon.app as a launch item
  • Set up Automatic Login
  • Disable automatic software updates
  • Disable any concept of screen lock, battery saving etc.

🔮 Ideas for the Future

Support for more Provisioners

We use GitHub Actions for our iOS builds at Trade Republic but would love to see Cilicon being used for other CI services as well. Implementing support for more services should be easy by building on top of the Provisioner protocol.

Running 2 VMs in parallel

Xcode b

View on GitHub
GitHub Stars1.1k
CategoryDevelopment
Updated45m ago
Forks36

Languages

Swift

Security Score

100/100

Audited on Apr 3, 2026

No findings