{"id":13815747,"url":"https://github.com/shapehq/tartelet","last_synced_at":"2026-01-16T05:03:10.003Z","repository":{"id":149344206,"uuid":"590053118","full_name":"shapehq/tartelet","owner":"shapehq","description":"⚙️💻 A macOS app that makes it a breeze to manage multiple GitHub Actions runners in ephemeral virtual machines on a single host machine. The benefits are that runners can run in parallel, and each job runs in an isolated environment.","archived":false,"fork":false,"pushed_at":"2025-06-23T10:19:13.000Z","size":25564,"stargazers_count":608,"open_issues_count":19,"forks_count":31,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-06-23T11:32:18.570Z","etag":null,"topics":["github-actions","macos","runner","self-hosted-runner","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shapehq.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-01-17T14:58:02.000Z","updated_at":"2025-06-23T10:19:17.000Z","dependencies_parsed_at":"2023-09-23T02:49:13.757Z","dependency_job_id":"8db97ded-3837-442f-a205-7d58d39c58f0","html_url":"https://github.com/shapehq/tartelet","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/shapehq/tartelet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shapehq%2Ftartelet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shapehq%2Ftartelet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shapehq%2Ftartelet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shapehq%2Ftartelet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shapehq","download_url":"https://codeload.github.com/shapehq/tartelet/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shapehq%2Ftartelet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28477210,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T03:13:13.607Z","status":"ssl_error","status_checked_at":"2026-01-16T03:11:47.863Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["github-actions","macos","runner","self-hosted-runner","swift"],"created_at":"2024-08-04T04:03:58.968Z","updated_at":"2026-01-16T05:03:09.986Z","avatar_url":"https://github.com/shapehq.png","language":"Swift","readme":"![Hero artwork](artwork.jpg)\n\n## 👋 Welcome to Tartelet - a macOS app that launches self-hosted GitHub Actions runners in virtual machines using [Tart](https://github.com/cirruslabs/tart).\n\nTartelet makes it a breeze to manage up to two GitHub Actions runners in ephemeral virtual machines on a single host machine. The benefits are that runners can run in parallel and each job runs in an isolated environment that is recreated after each GitHub Actions job has finished.\n\n- [🚀 Getting Started](https://github.com/shapehq/tartelet#-getting-started)\n- [👨‍🔧 How does it work?](https://github.com/shapehq/tartelet#-how-does-it-work)\n- [🏎 How is the performance?](https://github.com/shapehq/tartelet#-how-is-the-performance)\n- [👩‍💻 How can I contribute?](https://github.com/shapehq/tartelet#-how-can-i-contribute)\n- [🤨 Why is it named Tartelet?](https://github.com/shapehq/tartelet#-why-is-it-named-tartelet)\n- [🙏 Acknowledgements](https://github.com/shapehq/tartelet#-acknowledgements)\n\n## 🚀 Getting Started\n\nPlease refer to the following articles in [the wiki](https://github.com/shapehq/tartelet/wiki) to get started with Tartelet.\n\n- [Installing Tartelet](https://github.com/shapehq/tartelet/wiki/Installing-Tartelet)\n- [Configuring Tartelet](https://github.com/shapehq/tartelet/wiki/Configuring-Tartelet)\n- [Starting the Virtual Machines](https://github.com/shapehq/tartelet/wiki/Starting-the-Virtual-Machines)\n\n## 👨‍🔧 How does it work?\n\n![Screenshot of Tartelet running two virtual machines](screenshot.jpg)\n\nTartelet uses Tart for managing the virtual machines and Tart which in turn uses Apple's [Apple's Virtualization framework](https://developer.apple.com/documentation/virtualization). The lifecycle of a GitHub Actions runner managed by Tartelet is as follows:\n\n1. Tartelet uses Tart to clone a virtual machine.\n2. The virtual machine is booted.\n3. After the machine is booted, a setup script is being run. The script downloads the newest version of [GitHub's runner application](https://docs.github.com/en/actions/hosting-your-own-runners/adding-self-hosted-runners) and registers the runner on the GitHub organization.\n4. The runner listens for a job and executes it.\n5. After executing the job, the runner automatically removes itself from the GitHub organization.\n6. The virtual machine is shutdown.\n7. Tartelet uses Tart to delete the virtual machine.\n\nAfter the last step the process starts over.\n\n## 🏎 How is the performance?\n\nThe performance depends on the hardware that the app is running on. When testing on a Mac mini M1 from 2020 with 16 GB memory, we found that our jobs run 3 - 4 times faster than on GitHub's runners.\n\nWe found that our jobs run about 12% slower when running two virtual machines in parallel compared to running a single virtual machine. We find this performance cost negligible as running two virtual machines significantly increases our throughput at a low monetary cost.\n\nThis means that Tartelet can run two virtual machines at once. This the maximum number of virtual machines that Apple’s Virtualization framework allows us to run at once.\n\nAfter a job has finished, the virtual machine that ran the job is shut down and destroyed, and a new virtual machine is created and booted. This process takes about 25 - 30 seconds. However, that overhead is insignificant in most cases as Tartelet creates a new virtual machine after each job has finished. This means that a new virtual machine and its GitHub Actions runner are ready to process the next job. Unless there are more jobs queued on GitHub than the number of available virtual machines, the overhead of creating and booting a virtual machine becomes negligible.\n\nThese numbers were last updated in January/February 2023.\n\n## 👩‍💻 How can I contribute?\n\nPull requests with bugfixes and new features are much appreciated. We are happy to review PRs and merge them once they are ready, as long as they contain changes that fit within the vision of Tartelet.\n\nClone the repository to get started working on the project.\n\n```bash\ngit clone git@github.com:shapehq/tartelet.git\n```\n\n### Generating a Project File with XcodeGen\n\nAfter cloning the repository you will notice that the project does not contain a .xcodeproj file. This should be generated using [XcodeGen](https://github.com/yonaskolb/XcodeGen). Install XcodeGen using [Homebrew](https://brew.sh) by running the following command in your terminal.\n\n```bash\nbrew install xcodegen\n```\n\nAfter installing XcodeGen the project file can be generated by running the following command.\n\n```bash\nxcodegen generate\n```\n\n### Generating Resource Constants with SwiftGen\n\nWe use [SwiftGen](https://github.com/SwiftGen/SwiftGen) to generate constants for images, colors, and localizations. Install SwiftGen using [Homebrew](https://brew.sh) by running the following command in your terminal.\n\n```bash\nbrew install swiftgen\n```\n\nConstants for images, colors, and localizations are then generated by running the following command in your terminal.\n\n```bash\nswiftgen\n```\n\nThe `swiftgen.yml` file at the root of the repository describes how constants are generated.\n\n### Configuring the project to run on your machine\n\nTo run the project locally, it is necessary to edit the `Tartelet.entitlements` file to specify a keychain access group that you control. Then you will need to edit the `Composers.swift` file to ensure the keychain is initialized with the keychain access group specified in the entitlements file. If you do not do this, the app will not be able to persist settings to the keychain.\n\nIn other words, you will need to search for `$(AppIdentifierPrefix)dk.shape.Tartelet` and `566MC7D8D4.dk.shape.Tartelet` in the project and replace the occurrences with references to your keychain access group.\n\n### Linting the Codebase with SwiftLint\n\nWe use [SwiftLint](https://github.com/realm/SwiftLint) to ensure uniformity in the code. Install SwiftLint using [Homebrew](https://brew.sh) by running the following command in your terminal.\n\n```bash\nbrew install swiftlint\n```\n\n## 🤨 Why is it named Tartelet?\n\nThe app is named Tartelet because it builds upon [Tart](https://tart.run), a source-available CLI for managing macOS virtual machines. Tartelet makes it easy to run multiple virtual machines using Tart. The Danish word for \"easy\" is \"let\". \"Tart\" + \"e\" + \"let\" = \"Tartelet\" and [a \"tartelet\" is a traditional Danish food.](https://www.valdemarsro.dk/tarteletter-hoens-asparges/)\n\n\u003cimg src=\"Tartelet/Assets.xcassets/AppIcon.appiconset/Artboard_512x512.png?raw=true\" width=\"192\" /\u003e\n\n## 🙏 Acknowledgements\n\n- [Tart](https://github.com/cirruslabs/tart) does all the heavy-lifting of creating, cloning, and running virtual machines.\n- Tartelet is heavily inspired by [Cilicon](https://github.com/traderepublic/Cilicon).\n\n---\n\nTartelet is built with ❤️ by [Shape](https://shape.dk) in Denmark. Oh, and [we are hiring](https://careers.shape.dk) 🤗\n","funding_links":[],"categories":["Swift"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshapehq%2Ftartelet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshapehq%2Ftartelet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshapehq%2Ftartelet/lists"}