New here? Read docs/start-here.md first: how to pick an issue, what you can fix without a Mac, and what happens to your pull request. This file is the mechanics: setup, checks, CI and the pull request checklist.
Be nice, assume the best: CODE_OF_CONDUCT.md. Write issues and pull requests the way the short writing guide says.
Only needed for the native app. Docs, translations, Python tooling, cmux-tui and
web/ work on Linux; see what you can fix without a Mac build.
-
macOS 14+
-
Xcode 26 (the pinned toolchain). Xcode 16.2 on Intel Macs with macOS 14.5+ also builds the app, best effort (Swift 6.0 limits).
-
The Xcode 26 Metal compiler, which is a separate download. Select the Xcode you build with first (
DEVELOPER_DIRoverridesxcode-select), then:xcodebuild -downloadComponent MetalToolchain
-
Zig:
brew install zig -
Rust. Every app build compiles the bundled
cmux-cuaengine withcargo, andscripts/setup.shlooks forrustupin~/.cargo/bin, where the official installer puts it:curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Homebrew's
rustupworks too, but it is keg-only: add$(brew --prefix rustup)/bintoPATHand runrustup default stableyourself.
git clone --recursive https://github.com/manaflow-ai/cmux.git
cd cmux
./scripts/setup.sh
CMUX_DEV_BACKEND_MODE=local ./scripts/reload.sh --tag my-featuresetup.shinitializes the submodules, installs the pinned Rust toolchain, and fetches a checksum-pinned prebuiltGhosttyKit.xcframework(it builds from source with Zig if that fails; force that withCMUX_GHOSTTYKIT_NO_PREBUILT=1).reload.sh --tag <tag>builds a tagged Debug app and prints its path. Add--launchto open it, or--build-onlyto only compile.CMUX_DEV_BACKEND_MODE=localpoints it at the local dev origin; without it a tagged build expects the maintainers' shared backend and stops. See tagged builds for cache reuse and Release variants.reload.shskips emitting the app's Swift module to make rebuilds a little faster, except on Xcode 26.2 and 26.3, where that build stops at the module merge witherror: type mismatch of function ... but used in a swift module as .... If you see that error on another Xcode, rerun withCMUX_RELOAD_APP_EMIT_MODULE=1.- After pulling changes to setup or the merge drivers, rerun
./scripts/install-git-hooks.sh. With a customcore.hooksPathit prints thepre-commitandpost-mergelines to add yourself; wire both.
Team members with a Stack account can also sign DEBUG builds in and attach an iOS build: see team dev setup.
python3 scripts/verify-local.pyIt picks the static checks your diff touches (localization, project and test
wiring, package grouping, generated policy, feature flags) and parses changed
Swift. It compares against your local upstream/HEAD, then origin/HEAD, and
fetches nothing. When a check fails it prints the rerun command, for example:
python3 scripts/verify-local.py --only project --only test-wiring--list previews, --all runs the full static recipe CI uses, and --receipt -
prints JSON (details). Parsing is not typechecking
or testing. The script runs repository code, so use a
trusted checkout. Git push does
not run it for you.
For web/ and other JS/TS sources, run bun run biome:check from the repository
root. The root biome.json deliberately scopes that to maintained web and JS/TS
sources, excluding generated bundles, build outputs, vendored trees and review-tool
metadata. Formatting and import sorting are off for now, so do not wire this into
required CI until the remaining source lint diagnostics are paid down.
Go up the verification ladder as far as your change needs: source checks, the owning package's tests, compiling the app and tests, then runtime and physical checks. In the pull request, say which of those you ran. A parse or a build is not a test run.
You do not need to run the app-host or UI tests on your own Mac. They launch the app and need a disposable GUI session. If you can't run them, open the pull request anyway and say so under Testing. Opening the pull request is the request for CI:
- Static checks run on every pull request. The Linux guards run when your diff touches what they cover.
- Swift, package, app-host and tooling tests are routed from your diff: an edited suite runs, and an app-source change runs the suites whose tests mention what you changed. No label needed.
- The broad macOS suite is label-gated. A maintainer adds
full-ciwhen a change needs it (PR CI coverage). It is not a merge requirement. - No pull request job runs
cmuxUITests/in full. If you touch that directory, thesuite-coveragecheck stays red until a maintainer runs the affected classes and records it withno-full-ci. - On your first pull request, checks wait for a maintainer to approve the workflow run. That's a GitHub default for new contributors, not a judgement on the patch.
Read which tests actually ran on your commit, not the color of the checks list: a skipped job is green and is not coverage.
ghostty points to manaflow-ai/ghostty,
our fork of Ghostty. To change it, rebuild GhosttyKit.xcframework or pull in
upstream, follow the cmux-ghostty skill: push the
submodule commit to the fork before committing the pointer here. Fork changes and
conflict notes are in docs/ghostty-fork.md.
- One change per pull request. A fix plus a reformat is two pull requests.
- Fill in the template: a summary of the problem and what someone can do after the change, and Testing with the commands you ran.
- For a bug fix, commit the failing regression test before the fix (regression commits).
- Under
## Changelog, write oneAdded/Changed/Fixed/Removedline for a user-visible change, ornone. Don't edit CHANGELOG.md; releases build it from these lines. - Localize user-facing strings (localization skill).
- No unrelated formatting, generated files, vendored trees or version bumps.
- Sign the CLA once by commenting
I have read the CLA Document v2.2 and I hereby sign the CLAon your pull request. The check matches commit author emails to your GitHub account, so commit with an email linked to it.
Merges are squash merges, so the title and description become the commit that ships. How review works and what makes a patch wait is in start here.
Agents working in this repository also follow CLAUDE.md (also AGENTS.md).
By contributing to this repository, you agree that:
- Your contributions are licensed under the license of the directory you contribute to: the Business Source License 1.1 (
BUSL-1.1) for the server directories listed in LICENSE (web/,workers/ci-artifacts/,workers/iroh-v2/,workers/presence/,services/iroh-relay-minter/,cmux-tui/relays/cloudflare-do/), and the project's GNU General Public License v3.0 or later (GPL-3.0-or-later) everywhere else unless a file states otherwise. - You grant Manaflow, Inc. a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license to use, reproduce, modify, sublicense, and distribute your contributions under any license, including a commercial license offered to third parties.