Tech
It Has Been Verified on Docker/colima and UTM Running Linux Aarch64
Kakehashi is an experimental userspace translation layer that lets developers run macOS ARM64 binaries on Linux aarch64 systems. The CLI-first project, which does not use a JIT, loads Darwin Mach-O executables on Linux, maps a freestanding libSystem, and translates BSD syscalls to run real guest applications such as clang probes, 7-Zip's 7zz, curl, and threaded programs. It has been verified on Docker/Colima and UTM running Linux aarch64. Installation is a one-time process: relative -o and archive paths resolve against the host's current working directory of the kh process, with auto-mkdir support for O_CREAT.
Through the bottle, /Volumes/linux/… bridges to the host root (host / maps to host /). Docker helpers place artifacts under host.tmp/kh-out/. The project supports the full curl feature set, including POST bodies, proxies, HTTP/3 end-to-end, and every scheme, plus the real Apple Security.framework, git/CLT, GUI, and codesign.
The next product slice is git via kh install xcode-tools. The guest dylib is vendored at crates/kh-runtime/resources/libSystem. B.dylib and compiled into the runtime with include_bytes!.
Publishing kh-runtime ships the dylib, so end users do not need a separate download. The default root is ~/.local/share/kakehashi/bottle/, overridable with KAKEHASHI_DATA_DIR or KAKEHASHI_ROOT. Kakehashi runs guest code natively on the CPU.
The performance tax is the syscall boundary—TLS switch, alt stack, NEON save/restore, Rust dispatch—multiplied by how chatty the guest is, not an instruction emulator. On Ubuntu aarch64 bare-metal (UTM), a multi-file 7zz archive (-t7z -m0=lzma2 -mx=5 -mmt=4, ~8k files / ~240 MiB tree) shows a gap dominated by path walk and per-syscall boundary, not wrong LZMA. On compression-heavy, few-file samples, the gap is often much smaller (~×1.1–1.2).
Hypercall is on by default for all guest threads. Opt out with KAKEHASHI_HYPERCALL=0 only for debug (residual svc brk / SIGTRAP). The product goal for CI is not to match native macOS speed but to run Darwin CLI/tools on cheap Linux aarch64 runners instead of scarce, expensive macOS capacity.
GitHub Actions hosted runners (private-repo overage rates, USD per minute) show macOS standard is roughly ×10–×12 the Linux arm64 minute rate before any wall-time difference. Even if a job runs ×5 slower under kh on Linux arm64 than on a macOS runner, billable cost can still be lower because the macOS minute is an order of magnitude more expensive (illustrative: 5 × $0.005 ≈ $0.025 vs 1 × $0.062). Public-repo free minutes and self-hosted Linux amplify that further; macOS hosted capacity also tends to queue longer and, on GitLab SaaS, is Premium/Ultimate or beta-gated.
When macOS runners still win: GUI, codesign/notarization, Xcode UI tests, or any workload that is not a pure CLI Darwin binary under freestanding libSystem. Gates, not benches: CI correctness is cargo test / smoke / 7zz -mmt=4, not matching native wall clock. "as fast as native macOS,"
Source: Hacker News




