On the Mac

The same Mac is your iOS CI.

Besides being the machine your phone controls, MacOn turns it into a full iOS pipeline: watch a repo, build, test across simulators, and ship to TestFlight, with no metered minutes and no queue.

macOS 14+ · Apple silicon & Intel. Signed and notarized by Apple, so it opens like any other app.

On the Mac

A CI server, without the server.

Everything a hosted CI does for iOS, running on hardware you already own.

Your Mac, your runner

No metered build minutes, no queue, no cloud VM spin-up. Warm caches make it the fastest CI a single dev can have.

Bitbucket & GitHub

Watch a branch or open PRs. Poll on a timer, or take webhooks (with HMAC secrets) for instant push-based builds, and post the status back as a commit check.

macon.yml pipelines

Bitrise-style workflows: before_run/after_run chains, triggers, env, run_if conditions and always-run steps, defined in your repo.

Test matrix

Fan a step out across device × OS combinations. UI-test on every simulator that matters, iOS, watchOS, tvOS, visionOS, in one push.

Ship to TestFlight

fastlane with automatic signing and App Store Connect API keys. Merge to main, upload a build, done.

Two CI modesalso runners

Run your own macon.yml pipelines, or host a pool of Bitbucket self-hosted runners and route steps to your Mac with runs-on. Same app, both worlds.

macon doctor & init Simulator manager launchd service Prometheus /metrics Secrets in Keychain Build history Export ↔ import config Build timeouts Cache cleanup Menu-bar control Push notifications Shell completions

macon.yml

Pipelines that live in your repo.

Composable workflows, a test matrix, and trigger routing, the same file runs in the app or the CLI.

name: PlanPal iOS CI workflows: _setup: steps: - { name: Gems, script: bundle install } - { name: SwiftLint, script: swiftlint lint --strict } test: before_run: [_setup] steps: - name: Unit Tests script: bundle exec fastlane test - name: Danger run_if: '[ -n "$MACON_PR_ID" ]' # only on PRs script: bundle exec danger beta: before_run: [test] after_run: [_notify] steps: - { name: TestFlight, script: bundle exec fastlane beta } _notify: steps: - { name: Slack, always_run: true, script: ./scripts/notify.sh }
test: steps: - name: UI Tests # fan out across devices × OS, 4 runs, one push matrix: device: ["iPhone 17 Pro", "iPad Air 11-inch (M4)"] os: ["26.4", "26.5"] script: bundle exec fastlane test \ device:"$MACON_MATRIX_DEVICE" os:"$MACON_MATRIX_OS" # every step also gets MACON_COMMIT, MACON_BRANCH, MACON_REPO, # MACON_WORKFLOW, MACON_BUILD_NUMBER, MACON_PR_* on PR builds, # plus provider-native BITBUCKET_* / GITHUB_* so tools like Danger work.
triggers: - { pull_request: "*", workflow: test } # any PR - { branch: main, workflow: beta } - { branch: "dev-*", workflow: test } # globs supported # no workflow flag? MacOn matches the branch/PR here, # the same routing in the app, the CLI, and the phone.

Homebrew

Install the CLI.

One tap, one install. Then bootstrap the toolchain and start watching.

1 · Tap & install

# add the tap, then install brew tap alimusawa313/macon https://github.com/alimusawa313/homebrew-macon brew install macon

2 · Check the machine

macon init # installs missing tools macon sims list # iOS / watchOS / tvOS / visionOS

3 · Watch & build

# poll a branch and build every commit macon watch --workspace acme --repo app --branch main # or GitHub, instant, via webhook macon watch --provider github --workspace org \ --repo app --webhook --port 8787

4 · Run it unattended & drive it remotely

# export from the app, run headless as a service macon install-service --config macon-export.json --companion # then, from any terminal macon trigger "My App" --follow # build now, exit 0/1 by result