No Docker, no full VM — just a lightweight per-process virtual machine that translates Linux syscalls to macOS equivalents. Millisecond startup, native speed, ~160 syscalls.
A single 300KB native macOS binary. No daemon, no disk image, no multi-GB download.
VM creation takes ~1–3ms. Docker container start is seconds; full VM boot is minutes. hl is imperceptible in pipelines.
Guest aarch64 code runs on real ARM64 hardware — zero instruction emulation. x86_64 runs via Apple's Rosetta with hardware-accelerated JIT/AOT.
aarch64-linux natively, x86_64-linux via Rosetta. Both from the same tool, auto-detected from the ELF header.
Statically linked ELFs work out of the box. Dynamically linked work with --sysroot (musl or glibc).
The guest reads and writes the macOS filesystem directly. No overlay, no volume mount, no copy. Changes are instant.
Up to 64 concurrent guest threads, each mapped 1:1 to a host pthread with its own HVF vCPU. Full futex support.
I/O, filesystem, networking, signals, threading, process management, time, epoll, inotify, /proc, /dev — all translated.
A single native macOS binary. No daemon, no runtime, no disk image. Runs from anywhere — even a USB stick.
A 5-step pipeline that translates Linux syscalls to macOS equivalents inside a lightweight HVF virtual machine.
hl parses the ELF binary and maps PT_LOAD segments into a demand-paged guest address space (up to 1TB — only touched pages use RAM).
A minimal EL1 kernel shim (~500 lines of AArch64 assembly) provides exception vectors. The MMU is enabled inside the guest on the first instruction.
The guest binary executes at full native hardware speed on an Apple Hypervisor.framework vCPU.
When the guest makes a Linux syscall (SVC #0), the shim forwards it via HVC. hl translates it to the equivalent macOS call — errno codes, flag values, struct layouts, all converted.
Results flow back to the guest. The vCPU resumes. This loop repeats for every syscall — typically microseconds per round-trip.
For x86_64 binaries:
Apple's Rosetta Linux translator is loaded as a co-resident aarch64 binary.
Rosetta JIT/AOT-translates x86_64 instructions to ARM64 at runtime.
All resulting syscalls appear as ARM64 SVC #0 — hl's existing
syscall handlers work transparently.
hl is not a replacement for Docker or a full VM.
It runs single Linux binaries with minimal overhead.
| hyper-linux | Docker Desktop | Lima | UTM / QEMU | |
|---|---|---|---|---|
| What runs | Single Linux binary | Full Linux VM + containers | Full Linux VM + containerd | Full Linux/other VM |
| Linux kernel | None (syscall translation) | Yes (in VM) | Yes (in VM) | Yes (in VM) |
| Startup time | ~1–3 ms | ~2–10 s | ~5–30 s | ~10–60 s |
| Memory overhead | Used pages only (~MB) | Fixed VM RAM (2–8 GB) | Fixed VM RAM (2–4 GB) | Fixed VM RAM |
| Disk overhead | ~300 KB binary | Multi-GB image | Multi-GB image | Multi-GB image |
| Filesystem | Direct macOS FS access | Volume mount / virtiofs | virtiofs / sshfs | Shared folders |
| x86_64 support | Via Rosetta (fast) | Via QEMU (slow) | Via QEMU (slow) | Via QEMU (slow) |
| Threading | 1:1 HVF vCPUs (up to 64) | Full kernel scheduler | Full kernel scheduler | Full kernel scheduler |
| Networking | In-process translation | Virtual network | Virtual network | Virtual network |
| Install | Single binary or nix run | Desktop app | brew install | Desktop app |
Verified with real-world programs — from coreutils to Haskell binaries. Both aarch64 and x86_64 via Rosetta.
104 tools tested: ls, cat, sort, grep, wc, cp, mv, rm, chmod, date, head, tail, tr, cut, uniq, seq, stat, du, df, and many more.
static + dynamic60+ applets including awk, sed, grep, tar, gzip, bzip2, find, bc, diff, hexdump, wget, nc, ash shell.
staticbash (arrays, associative arrays, regex, arithmetic, subshells/fork), dash (loops, conditionals, recursion, case/glob).
static + dynamicjq (JSON processing), GNU grep, GNU sed, GNU find, tree, diffutils.
staticCREATE, INSERT, SELECT, ORDER BY, recursive CTEs, string functions. Full database engine running in the guest.
staticLua interpreter (Sieve of Eratosthenes, Fibonacci), GNU awk (Mandelbrot renderer).
staticMarkdown→HTML, HTML→Markdown, JSON AST. Exercises GHC RTS + Lua FFI.
haskell · dynamicShell script linter. Exercises GHC threaded RTS + regex engines.
haskell · dynamicAll of the above also work as x86_64-linux binaries, auto-detected from the ELF header.
rosetta · JIT + AOT
hl takes a Linux ELF binary and runs it. That's it.
$ hl ./hello-static
Hello, world!
$ hl /path/to/jq '.name' data.json
"hyper-linux"
# Run bash interactively with a musl sysroot
$ hl --sysroot ./musl-sysroot /path/to/bash
bash-5.2$
# x86_64 binaries are auto-detected via ELF header
$ hl ./my-x86_64-binary
# Verbose output for debugging
$ hl --verbose ./my-program arg1 arg2
Pure computation runs at native ARM64 hardware speed. The only overhead is per-syscall VM exit round-trips.
mmap + hv_vm_create + page table setup. Imperceptible in pipelines.
Each VM exit round-trip for syscall translation. Microseconds, not milliseconds.
Guest aarch64 code runs on real ARM64 hardware. No instruction emulation, no interpretation.
Address space up to 1TB, but only touched pages consume physical RAM. macOS handles the rest.
In practice: Single-command tools (echo, true, basename) are dominated by 1–3ms startup. Long-running programs (bash sessions, pandoc) amortize startup to zero — steady-state performance is native + microseconds per syscall.
Apple Silicon Mac (M1+), macOS 13+. macOS 15+ recommended for 1TB address space.
One command. Downloads, codesigns, and installs to /usr/local/bin.
curl -fsSL https://hyper-linux.app/install.sh | sh
Via the zw3rk tap. Handles codesigning automatically.
brew install zw3rk/hyper-linux/hl
Run directly without installing, or add to your flake inputs.
nix run github:zw3rk/hyper-linux
Key innovations that make kernel-less Linux binary execution possible.
Every Linux syscall is intercepted via HVC and translated to the equivalent macOS call in-process. Full translation of errno codes, flag values, struct layouts, and socket address formats.
Apple HVF enforces write-xor-execute even with SCTLR.WXN=0. The page table system handles this via 4KB L3 splitting when mixed permissions are needed within a 2MB block.
HVF allows only one VM per process. Fork spawns a new hl process and serializes entire VM state — registers, memory, FDs via SCM_RIGHTS, signals — over a Unix socket.
Guest threads map 1:1 to host pthreads, each with its own HVF vCPU sharing the same physical memory. 7-operation futex enables musl pthread support.
x86_64 binaries run by co-loading Apple's Rosetta at 128TB using 48-bit IPA. AOT translation via rosettad supported for complex binaries with indirect calls.
/proc/self/exe, /proc/cpuinfo, /proc/meminfo, /proc/self/maps, /dev/null, /dev/urandom, and more — synthesized responses that match Linux format.
0x010000 Page table pool (960KB)
0x100000 Shim code (2MB, RX)
0x200000 Shim data/stack (2MB, RW)
0x400000 ELF LOAD segments
0x1000000 brk heap (grows up)
0x7E00000 Stack guard page
0x7E01000 Stack (2MB, grows down)
0x10000000 mmap RX region (256MB initial, extends on demand)
0x200000000 mmap RW region (8GB, 256MB initial, extends on demand)
interp_base Dynamic linker (60GB / 1020GB)
USAGE:
hl [OPTIONS] [--] <elf-path> [args...]
OPTIONS:
-h, --help Display the manual page
-V, --version Print version and exit
-v, --verbose Enable verbose diagnostic output on stderr
-t, --timeout SECONDS Per-iteration vCPU timeout (default: 10s)
--sysroot PATH Musl/glibc sysroot for dynamically-linked binaries
-- Stop processing hl options
EXIT STATUS:
The exit status of hl is the exit status of the guest binary.
ENVIRONMENT:
Guest inherits the host environment verbatim. No special variables.
hl translates syscalls, not the kernel.
Some things are outside scope by design.
Requires M1/M2/M3/M4 or later. Intel Macs are not supported.
No namespaces, cgroups, or kernel modules. This is syscall translation, not a full kernel.
GDB/LLDB cannot attach to the guest process.
Up to 64 concurrent guest threads per VM instance.
Shared memory semantics are not preserved across processes (guest is process-scoped).
Complex x86_64 binaries with indirect calls may need rosettad AOT translation.