Simple Mac menu bar app and CLI for managing GitHub Actions self-hosted runners.
- π Run multiple GitHub Actions runners on a single Mac
- π₯οΈ Dual CLI + GUI β manage runners from terminal or menu bar
- π
ghCLI integration β no manual PAT tokens, uses your existinggh auth - π Hybrid isolation β choose user isolation (macOS runners) or container isolation (Linux workflows)
- π Headless by default β runners run without GUI access (enable when needed for visual testing)
- βΈοΈ Pause/Resume all runners with one click
- π― Perfect for when you need your Mac's resources for intensive work
- π Monitor runner status from menu bar
- β‘ Native Mac app, lightweight and fast
- π€ Fully automated setup β downloads and configures runners automatically
GitHub Actions self-hosted runners are great, but:
- Official runner only supports one instance per machine
- No easy way to pause runners when you need CPU/memory
- Managing multiple repos means multiple runner processes
- No visual indication of runner status
Mac Runner solves this.
brew tap omniaura/tap https://github.com/omniaura/mac-runner
brew install --cask mac-runnerDownload the latest DMG from Releases
Mac Runner is not code-signed yet. macOS Gatekeeper will block the first launch. To allow it:
xattr -cr /Applications/MacRunner.appOr: right-click the app β Open β click "Open" in the dialog.
- macOS 13+ (macOS 15+ for user isolation, macOS 26+ for container isolation)
ghCLI installed and authenticated (gh auth login)- Apple Silicon Mac (for container isolation)
- Launch Mac Runner β appears in menu bar
- Click "Add Runner"
- Browse your repos (fetched via
gh), pick one - Runner downloads, configures, registers, and starts automatically
# Check GitHub auth
mac-runner auth
# Add a runner (downloads, configures, starts in background)
mac-runner add owner/repo --name my-runner --labels macos,mac-runner
# Add a runner with GUI access (for visual tests, Xcode UI tests, etc.)
mac-runner add owner/repo --enable-gui
# List runners
mac-runner list
# Start/stop
mac-runner start my-runner
mac-runner stop my-runner
# Remove (also deletes from GitHub)
mac-runner remove my-runner
# Status summary
mac-runner statusRunners started via CLI persist in the background β they survive the terminal session. Stop and start them from any terminal or from the GUI.
Mac Runner uses a pattern that automatically routes CI jobs to your self-hosted Mac when it's online, and falls back to GitHub-hosted cloud runners when it's not. This means pushes to main always build, regardless of whether your Mac is on.
The release workflow uses mikehardy/runner-fallback-action to query the GitHub API for available self-hosted runners before the build job starts:
jobs:
preflight:
runs-on: ubuntu-latest
outputs:
runner: ${{ steps.runner.outputs.use-runner }}
steps:
- name: Select runner
id: runner
uses: mikehardy/runner-fallback-action@v1
with:
primary-runner: mac-runner
fallback-runner: macos-latest
fallback-on-error: true
github-token: ${{ secrets.RUNNER_TOKEN }}
build:
needs: preflight
runs-on: ${{ fromJson(needs.preflight.outputs.runner) }}
steps:
- run: echo "Running on the best available runner"| Mac online | Runner used | Cost |
|---|---|---|
| Yes | mac-runner (self-hosted) |
Free |
| No | macos-latest (cloud) |
GitHub Actions minutes |
This pattern is useful for any project that wants fast, free self-hosted builds when available, with reliable cloud fallback. See the community discussion for background on why this isn't built into GitHub Actions natively.
The runner-fallback-action queries the GitHub REST API to check runner availability. This requires a token with admin read access β the default GITHUB_TOKEN does not have this permission.
- Create a fine-grained Personal Access Token:
- Repository access: select "Only select repositories" and pick your repo
- Permissions β Repository β Administration: Read-only
- Add it as a repository secret named
RUNNER_TOKEN:gh secret set RUNNER_TOKEN
Note: If the token is missing or invalid,
fallback-on-error: trueensures the workflow still runs β it just falls back to cloud runners.
mikehardy/runner-fallback-actionβ runner availability checkerjimmygchen/runner-fallback-actionβ original (archived)- GitHub Community: Auto-switch to GitHub runner if self-hosted unavailable
Mac Runner supports three isolation modes to protect your development environment:
- Runners execute directly as your current user
- Simple setup, works on any macOS version
β οΈ Not recommended for untrusted workflows β CI jobs have full access to your files
- Each runner runs as a dedicated system user (e.g.,
_macrunner) - Prevents CI jobs from accessing your files, credentials, and desktop
- Best for macOS-based workflows
- How to enable:
# CLI mac-runner add owner/repo --isolation user # GUI Settings β Isolation Mode β Dedicated User
- Runs Linux workflows in isolated, lightweight virtual machines
- Uses Apple's Containerization framework
- Sub-second startup times with Rosetta 2 for linux/amd64 emulation
- Best for Linux-based workflows, Docker builds, cross-platform testing
- Requirements: macOS 26+, Apple Silicon, Linux kernel 6.14.9+
- How to enable:
# CLI mac-runner add owner/repo --isolation container # GUI Settings β Isolation Mode β Container
You can set a global default isolation mode and override it per-runner:
# Set global default to user isolation
mac-runner settings --isolation user
# Add a Linux runner with container isolation
mac-runner add owner/linux-project --isolation container
# Add a macOS runner with no isolation (for trusted workflows)
mac-runner add owner/trusted-project --isolation noneIn the GUI, each runner displays its isolation mode with an icon:
- π No isolation
- π€ User isolation
- π¦ Container isolation
By default, runners operate in headless mode β they run without access to the GUI (display, windows, etc.). This is optimal for most CI jobs and prevents interference with your desktop.
When to enable GUI access:
- Visual testing (screenshot comparisons, E2E tests with browsers)
- Xcode UI tests
- iOS Simulator tests
- macOS app GUI automation
How to enable:
# CLI
mac-runner add owner/repo --enable-gui
# GUI
Add Runner β Enable GUI Access (toggle)Note: GUI sessions are currently shared across runners. For full isolation (separate GUI session per runner), see Issue #27.
- Auto-provision CI tools (node, npm, gh) in runner environments
- Automatic pause when battery low
- Pause during specific hours
- Resource usage monitoring
- Notifications for job starts
- Custom container images for containerized runners
- Swift 6 / SwiftUI β Native Mac app
- Menu Bar Interface β Always accessible, minimal UI
ghCLI β All GitHub API calls go throughgh(auth, repos, runner tokens, CRUD)- PID-based process management β Runners persist across CLI sessions
- Dual entry point β
main.swiftdispatches to CLI handler or SwiftUI app
# Build
swift build
# Run CLI
.build/debug/mac-runner --help
# Run GUI (no args)
.build/debug/mac-runner
# Test
swift testWe use Conventional Commits for automatic versioning:
feat:β New feature (minor bump)fix:β Bug fix (patch bump)chore:β No release
See CONTRIBUTING.md for full guidelines.
MIT