Run the upstream Omarchy desktop as a native, hardware-accelerated app on an Apple Silicon Mac.
Try Omarchy packages a stock aarch64 Omarchy install, a QEMU runtime using Apple Hypervisor Framework with UEFI firmware, and a small Swift/AppKit launcher into one macOS app. The factory disk is installed from Omarchy's own package repositories with Omarchy's own install steps. Everything Try Omarchy adds inside Linux is one pacman package, try-omarchy. Omarchy then updates itself inside the VM with omarchy update, kernel included. On ARM, Omarchy publishes to its edge channel for now.
The Omarchy mark in the app icon is sourced from the official Omarchy brand kit and remains subject to Omarchy's trademark rights.
- Open Releases and download the latest signed and notarized
.dmg. - Open the DMG and drag Try Omarchy to Applications.
- Launch Try Omarchy from Applications.
The first launch downloads the Omarchy image (about 3 GB) from the same GitHub release before it creates the VM; the launch button shows its progress. An interrupted download, from a lost connection, sleep or quitting the app, continues where it stopped on the next launch, and every part is checked against its SHA-256 digest before it is used. The volume needs room for the image and the prepared disk (about 15 GB); the download stops with 1 GB still free rather than filling the disk.
By default, every launch begins at the launcher. Enable Skip launcher to start Omarchy using your saved settings on subsequent launches. A confirmation explains how to return to the launcher; choose OK to enable Skip launcher or Cancel to leave it off. Hold Option while opening the app to show the launcher again and change settings or turn Skip launcher off. You can also open Setup → Try Omarchy Settings inside Omarchy. Skip launcher is saved with the VM workspace; deleting that workspace clears the choice. A missing VM disk always shows the launcher, even if its settings file remains. Reset requests still show the confirmation flow. Startup checks still show any error dialogs.
While that menu is open, Try Omarchy behaves like a regular Mac app. Try Omarchy → Settings… (Command-comma) brings the launcher or its open editor forward without discarding drafts. The menus also provide standard text editing, Services, Hide Others, Show All, and window commands, including Bring All to Front. Help opens the user guide, maintenance and recovery notes, or the issue tracker in your browser. After the VM starts, that native app chrome steps aside for Omarchy. Immersive is on by default, so Omarchy opens Full Screen with the Mac menu bar and Dock hidden. Turn it off to open a resizable window; if you later enter Full Screen, the Mac menu bar and Dock remain available at the screen edges. Whenever the Omarchy window is focused, Command belongs to the guest as Super in either mode; Accessibility permission lets system shortcuts such as Command-Space reach it before macOS. Microphone and camera access are optional. The first launch takes longer while the app prepares Linux and starts Omarchy's account provisioning.
Inside Omarchy, choose Setup → Try Omarchy Settings, search for Try Omarchy Settings, or run omarchy-native-settings to reopen the Mac settings window. You can change Skip launcher, permissions, CPU, memory, sharing, port forwarding, and immersive mode here. CPU, memory, sharing, ports, and immersive mode are saved for the next launch; Restart Omarchy shuts down Linux and starts a new VM process to apply them. Save your work first. A disposable VM keeps its disk across this restart until you close the app.
For VM location and reset, choose Shut Down. The settings window stays open even with Skip launcher enabled; reset still asks for confirmation. Done or closing the running settings window returns to Omarchy without stopping it.
Restarting from inside Omarchy reboots the guest in the same Try Omarchy app. Shutting down Omarchy closes the app and leaves it closed.
- Hardware-accelerated ARM64 virtualization and VirGL graphics
- Opt-in nested KVM virtualization on M3 and newer Apple Silicon running macOS 26+
- Resizable native window with automatic guest resolution and HiDPI scale updates
- Mac audio input/output selection inside Omarchy, with live routing and system-default fallback
- FaceTime HD and other Mac cameras exposed to Omarchy as an on-demand 720p webcam
- The Mac's battery charge and charging state mirrored into the Omarchy bar
- Two-way clipboard sharing for text and PNG images between macOS and Omarchy
- One optional shared Mac folder, available inside Omarchy under the same name (
~/Workstays~/Work) - Loopback-only TCP and UDP port forwarding from the Mac into Omarchy
Current limitation: Video decoding is CPU-only, so playback can be slow, especially at high resolutions. An improved video path is in development.
This fork moves the runtime to QEMU 11.1.1 to pick up Apple's in-hypervisor GIC, and fixes two audio problems found along the way.
| Component | Upstream | This fork | Reason |
|---|---|---|---|
| QEMU | cf3e71d8 — 10.2.50, 2026-01-13 |
c3d48b7d — 11.1.1, 2026-08-26 |
First release carrying hw/intc/arm_gicv3_hvf.c |
| ARM GIC | GICv2, emulated in QEMU userspace | GICv3 via Hypervisor.framework | Removes the interrupt path from the big QEMU lock |
| Render patch | startergo mega-patch, 29 files | Vendored and trimmed to 18, forward-ported | Upstream is unmaintained since 2026-01-14 and QEMU's display API moved |
| Python build deps | Host interpreter | Pinned setuptools, wheel, pip wheels |
QEMU 11.1 builds qemu.qmp, and Python 3.12+ dropped setuptools |
| Render patch source | Downloaded from the startergo tarball | Vendored in macos/patches/ |
That tree is unmaintained since 2026-01-14; the archive is no longer fetched at all |
| Cocoa keyboard capture | Capture follows the mouse grab | Capture follows the key window | An absolute-pointing guest drops the grab as soon as virtio-tablet binds, leaking host Command chords mid-session |
Idle CPU. QEMU emulated GICv2 in userspace under the big QEMU lock, so every guest interrupt cost about four lock acquisitions and every IPI about five across two vCPU threads. The cost scaled with vCPU count and was independent of what the guest was doing.
| Measured at idle | Before | After |
|---|---|---|
| QEMU | ~65% of a core | ~15% |
coreaudiod attributable to the VM |
6.4% | 0.3% |
| Total | ~71% | ~15% |
The QEMU figure moved twice: the GIC work took it to ~22%, and clearing the Cocoa GL dirty flag (below) took it to ~15%. The second measurement was taken on a freshly booted desktop rather than the same session, so treat the split between the two as approximate.
Under HVF, QEMU 11.1.1 also rejects GICv2 outright, so this is now the only supported configuration rather than an optimisation.
A host audio device held open forever. sdl_enable_out only paused the
device, and QEMU links sdl2-compat over SDL3 where pausing a logical device
leaves the physical one running. The device being held was not even from
playback — sdl_init_out opens one at startup purely to negotiate a format,
and nothing released it. The host resampled silence for the life of the VM.
Microphone capture is stricter: its initial device open is deferred until an
Omarchy application actually records, and the device is closed again when the
guest capture stream stops. The first recording may therefore take one device
open longer to begin, but merely launching Try Omarchy does not activate the
Mac microphone.
An unconditional re-render every refresh tick. The vendored
GPU-resolution patch cleared gl_dirty inside an if (cocoa_gl_trace_enabled())
block, so in a normal build the flag was never cleared: it latched true on the
first damage and cocoa_gl_refresh then blitted the scanout on every tick for
the life of the VM, whether or not anything had changed. The clear now sits at
function scope, where its own comment says it belongs.
Audio dropouts. PipeWire reported continuous xruns on a ring 682 ms deep,
with the guest driver using 17 us against a 42 ms deadline. QEMU advances the
emulated Intel HDA DMA position from a 100 Hz timer, so the counter moves in
coarse jumps and ALSA concludes it has missed. Raising the guest's quantum
gives the emulated counter fewer and larger checks to satisfy. A deeper SDL
buffer made this worse, and raising the QEMU main loop to
QOS_CLASS_USER_INTERACTIVE changed nothing, which rules out both buffer
depth and priority inversion.
The display uses QEMU's native macOS OpenGL backend (gl=on). VirGL replays
Linux graphics commands in an Apple OpenGL 4.1 core context, backed by the
Apple Silicon GPU.
Browser / Hyprland / Omarchy
| OpenGL or OpenGL ES
v
Mesa virgl driver guest
| command stream
v
virtio-gpu-gl-pci ─────────────────────────── VM boundary
|
v
virglrenderer host, replays as desktop OpenGL
|
v
Apple OpenGL driver / Cocoa Apple Silicon GPU
The guest sees a virtio GPU and needs no Apple-specific driver. The shared renderer preserves real multisample support and uses mutable multisample textures when macOS lacks immutable multisample storage. This allows browsers to create the ES 3 contexts they need for default acceleration, without browser-specific flags. Native Apple drivers also select integer vertex attributes automatically, with alpha and BGRA textures converted once. Hardware video decoding and Vulkan remain unavailable.
The runtime also bundles pinned ANGLE libraries for its upstream compatibility code. ANGLE's Metal backend is not the default display path. KosmicKrisp, Mesa's Vulkan-to-Metal driver, is not part of this path.
Window resize across a HiDPI boundary, Mac output-device switching mid-session,
the shared folder, and clipboard sharing have not been exercised since the
port. The dtc mirror should be reverted once kernel.org returns.
Choose Resources → Configure… on the start menu to adjust processor cores and memory, and set a maximum disk size for the next launch. Processor cores range from 4 to all the cores on this Mac; the default remains up to 8 cores. Memory defaults to 8 GiB on Macs with at least 16 GiB of RAM, and 4 GiB on smaller Macs. Custom allocations can leave as little as 4 GiB for macOS; higher choices carry a performance note.
Maximum disk size (GiB) defaults to 64 GiB for new launcher settings, and supports capacities up to 8192 GiB. Mac storage is allocated as the guest writes data, rather than reserving the whole maximum in advance. For example, choosing 256 GiB does not immediately use 256 GiB on the Mac. The volume still needs free space as the VM fills it; the maximum is guest capacity, not a quota on backups or total app storage.
Keep the displayed value to retain the current capacity. Larger values sparsely
extend the stopped disk at the next launch; the guest grows its root partition
and btrfs filesystem on boot. Existing disks cannot shrink. Use Defaults
selects 64 GiB, or the existing capacity if larger. Previously saved settings
without a disk maximum retain their current capacity. For direct launcher
script usage, set OMARCHY_QEMU_GPU_DISK_GIB=256.
Save remembers these choices. Cancel leaves them unchanged, and Use Defaults restores the draft until you save. Existing memory preferences are carried forward. A choice that no longer fits a smaller Mac falls back to its default without erasing the saved choice.
Both are ordinary Omarchy packages on ARM: install them from the Omarchy menu (Install → Terminal → Ghostty, Install → Service → 1Password). Try Omarchy no longer ships its own installers for them. Ghostty runs on the software renderer because the VM's graphics path lacks the OpenGL version it needs; see Ghostty.
Choose Allow… next to Camera access on the start menu to make the Mac's
FaceTime HD camera available in Omarchy as Mac Camera. The bridge publishes a
standard Linux V4L2 camera at /dev/video42, so browser calls and Linux camera
apps can use it without special configuration. Capture is on demand: the Mac
camera and its indicator turn on only while an Omarchy app is actively using
the virtual camera. Denying camera permission does not prevent Omarchy from
launching.
Copy and paste work in both directions as soon as you sign in to Omarchy: text and PNG images copied on the Mac appear in the Omarchy clipboard, and content copied in Omarchy lands on the Mac pasteboard. Nothing is transferred until something is copied.
Folder sharing is off until you pick a folder. Use Choose… next to
Shared folder on the start menu to select one Mac folder; Omarchy links it
into its home under the same name (~/Work on the Mac becomes ~/Work in
Omarchy) with full read and write access, so choose a folder you intend Linux
software to modify. The whole home folder, ~/Library, and system directories
cannot be shared. Turn Off keeps the choice but stops exporting it on the
next launch; Omarchy then removes the link and gives back any standard folder
such as ~/Documents that the link had taken over. The share belongs to the
first Omarchy account created during
provisioning. Additional guest accounts can reach the same share, with each
entry's normal Unix permission bits deciding whether they can modify it.
The share uses cache=readahead to avoid the 9p writeback corruption risk in
some guest kernels. Writable shared memory mappings are unavailable; keep
databases and mmap-based IPC files on the guest's local disk. See
shared-folder safety for the mount policy and
how to verify it.
Passthrough is off until you pick a device. Use Choose… next to USB device on the start menu to select one device currently attached to the Mac; the choice applies on the next launch, and Turn On / Turn Off keeps it without reselecting. Omarchy gets a USB 3 controller with that one device attached, matched on its vendor and product identifiers and its physical bus and port. The picker lists the bus and port for each device. The match stays fixed even when only one device is connected, so unplugging it cannot hand an identical device on another port to the guest. Moving a device to another port requires choosing it again. If the saved device is absent at launch, Omarchy starts without USB passthrough. Old selections without a saved location must also be chosen again.
Upstream QEMU treats hostbus=0 as "any bus", and libusb numbers the first
USB controller 0 — on a Mac with a dock, usually the controller behind every
dock and hub port. The bundled QEMU carries
macos/patches/qemu-usb-host-exact-bus.patch so that hostbus=0 selects bus 0
exactly, and the launcher refuses a runtime without it. The selection
identifies a model at a physical port, not a serial number; replacing it with
the same model at the same port still matches.
Only one device at a time, and never a USB hub — passing a hub through would take every device behind it, frequently this Mac's own dock, keyboard, or display controls.
What gets through depends entirely on privilege. libusb's Darwin backend
accepts exactly two kinds of caller for taking a device away from macOS -- a
process holding com.apple.vm.device-access, or one running as root -- and
turns every other caller away before it asks the kernel anything:
/* libusb/os/darwin_usb.c, darwin_detach_kernel_driver() */
if (0 != geteuid()) {
usbi_warn (ctx, "USB device capture requires either an entitlement "
"(com.apple.vm.device-access) or root privilege");
return LIBUSB_ERROR_ACCESS;
}Unprivileged, which is how this app ships: only a device no macOS driver
has claimed, which is rarer than it sounds. Surveying every USB device attached
to one Apple Silicon Mac found a driver bound to all of them: hubs, docks
(through AppleUSBHostBillboardDevice), HID receivers, audio interfaces, USB
Ethernet and mass storage. What is left is hardware macOS has no driver for at
all, such as SDR receivers, JTAG probes and custom vendor-specific boards.
Everything else enumerates in the guest but never gets a configuration: lsusb
lists it while /sys/bus/usb/devices/*/bConfigurationValue stays empty, and no
sda, input device or camera appears. Both libusb_detach_kernel_driver and
libusb_claim_interface return LIBUSB_ERROR_ACCESS immediately, without the
kernel ever being asked.
As root, this same build takes a driver-claimed device completely. Measured
on one Apple Silicon Mac with a SanDisk 3.2Gen1 stick, a device class macOS
drives through IOUSBMassStorageDriver:
# inside the guest
$ lsblk
sda 57.3G disk
|-sda1 200M part vfat EFI
`-sda2 57G part vfat VCAUSB /run/media/vcanuel/VCAUSB
$ cat /sys/bus/usb/devices/2-1/speed
5000
$ readlink /sys/bus/usb/devices/2-1:1.0/driver
../../../../../../../../bus/usb/drivers/usb-storage
$ dd if=/dev/urandom of=/run/media/vcanuel/VCAUSB/u.bin bs=1M count=256 conv=fsync
268435456 bytes (268 MB, 256 MiB) copied, 3.69127 s, 72.7 MB/s
The volume mounts on the Omarchy desktop like any other drive, and writes land on the stick at SuperSpeed. Nothing in the passthrough path itself needs changing for this; only the privilege of the process that calls libusb.
The xHCI controller is started with streams=off, so the guest uses
usb-storage rather than uas. With streams on, uas binds the same stick
but the first command after each connection gets no answer: after a replug,
REPORT LUNS and then INQUIRY each timed out after 30 s and forced a device
reset, so the stick mounted only about 60 s later. usb-storage on the same
stick reads its capacity about 1.2 s after connection, with no timeout. Linux
only picks uas on a controller that advertises streams, so with them off it
falls back to usb-storage by itself, with no guest configuration.
Unmount a drive on the Mac with diskutil unmountDisk rather than Finder's
Eject before handing it over. Eject sends the stick a SCSI stop, and it then
reports no medium ([sda] Media removed) until it is physically replugged.
Neither door is free. com.apple.vm.device-access is restricted: Apple grants
it per developer team, delivers it in a provisioning profile, and DTS describes
it as meant for virtualization apps shipping on the Mac App Store. Commercial
virtualization apps carry it, which is why they take a USB drive without
running as root. Root is not something a desktop app should assume either --
libusb reads the effective uid of the calling process, so it would be QEMU
itself running as root, not a small privileged helper alongside it. Which door
to open is a decision for whoever ships the app. See libusb/libusb#1014.
Replugging can freeze the window, and a bad exit wedges the device. Every
capture attempt goes through libusb's darwin_reenumerate_device(), which polls
an atomic for up to DARWIN_REENUMERATE_TIMEOUT_US — 10 seconds — on whichever
thread called it, and QEMU calls it from the main loop. Unplugging and
reconnecting the device while the VM runs costs one such timeout per attempt:
measured on this build, a QEMU-side detach blocked the main loop for 10.08 s,
and one physical replug stalled the guest's USB enumeration for 29.8 s (guest
kernel timestamps 34.98 → 64.77). The guest keeps computing, but the window
stops redrawing and stops accepting input until the timeout expires.
A later retest as root with streams=off did not reproduce the freeze: the
same stick, unmounted in the guest, then unplugged and replugged on the same
port, came back and remounted within about 5 s, with the window responsive
throughout. When the timeout is actually hit is not yet pinned down.
A device left behind by an unclean exit stays unusable until it is physically
reconnected. After QEMU was killed mid-reset, every bulk transfer to the stick
timed out — from QEMU and from a plain libusb program alike, both running as
root, with libusb_claim_interface still reporting success. One unplug and
replug restored it, and the same program then completed a SCSI INQUIRY in 20 ms.
Leave the device plugged in for the life of the VM, and replug it if a run ends
badly.
The guest needs its own tools for anything beyond enumeration: usbutils for
lsusb, libimobiledevice for an iPhone.
For scripted launches, OMARCHY_QEMU_GPU_USB_HOST overrides the saved choice
with a raw usb-host property list — vendorid=0x05ac, or
hostbus=1,hostaddr=6 to pin one physical port. The start menu shows when the
environment owns the choice and leaves its buttons disabled.
Use Configure… next to Networking on the start menu. NAT shares the Mac's connection and is the default. Bridged gives the VM its own LAN address through a selected eligible Mac interface. Changes take effect on the next launch. Bridging uses a networking helper approved once through macOS System Settings. Use Set Up / Repair Networking… to register it; subsequent bridged launches do not request your password. QEMU continues to run as your user. Remove Networking Helper unregisters the service when it is no longer needed. Shut down any bridged VM before repairing or removing the helper.
Persistent VMs keep a stable, randomly generated bridged MAC address across app updates, disk replacement, resizing, resets, and moves of the complete VM data folder. Existing saved addresses are retained when upgrading from older builds. The Networking sheet displays the address after the first bridged launch; Copy MAC makes it available for a DHCP reservation. Generate new MAC… shows a proposed address and requires confirmation while the VM is stopped. This action saves immediately; DHCP reservations may need updating. Cancelling the confirmation leaves the existing identity unchanged.
A copy of the complete VM data folder includes its network identity. To run a
copy as a separate VM, generate a new MAC before running both copies. Move or
restore the complete data folder to retain the identity; importing only a disk
into a new workspace does not transfer its network identity. Ephemeral bridged
VMs receive a fresh address on each launch. Damaged identity records produce an
error instead of silently changing the MAC. Regeneration retains
the preceding record as network-identities/current.previous.json in the VM
data folder; restore a known-good record only with the VM stopped.
For repeated local development builds, use a consistent Apple Development
signing identity (the DEVELOPMENT_SIGN_IDENTITY option above). Ad-hoc-signed
helper registrations are not reliable across rebuilds on the tested macOS
version. Approval is checked separately from a working helper connection;
repair and launch verify that the helper belongs to the current app copy.
On Wi-Fi hosts that expose the compatibility control, selecting bridging automatically enables temporary host-wide DHCP handling. The networking sheet explains this before you save the choice. It can affect other virtualization apps while the bridged VM runs. The previous setting is restored when the VM stops, the app exits, or the bridge helper fails. If the privileged supervisor itself is forcibly killed, restoration is retried on the next bridged launch. There is no separate compatibility checkbox. NAT does not change this host setting.
Saved port-forwarding rules remain stored but are inactive in bridged mode. Services listening on the guest network interface can be reached directly from the LAN. Allow SSH connections from the LAN is a separate opt-in; switching from a NAT SSH mapping does not enable it automatically. Guest account setup and SSH authentication are still required. Only one bridged Try Omarchy session can run at a time on a Mac.
If the selected adapter is unplugged, Omarchy starts offline and connects when it returns. Unplugging and reconnecting the adapter while running also recovers without restarting the VM. The selected adapter is preserved; the app does not automatically switch to NAT or another interface.
In NAT mode, use Configure… next to Port forwarding on the start menu to map a Mac
localhost port to a service port in Omarchy. Each mapping can use TCP or UDP;
the same Mac port may be used once for each protocol. Forwarded ports bind only
to 127.0.0.1, so other devices on the network cannot connect to them. The
service inside Omarchy must listen on 0.0.0.0 or the guest network interface,
not only on the guest's own localhost.
The reverse direction does not need a mapping. From Omarchy, connect to
10.0.2.2:<Mac port> to reach a service running on the Mac.
After completing Omarchy's first-boot account setup, open Port forwarding,
choose Add SSH, and save the prefilled TCP mapping from Mac port 2222 to
Omarchy port 22. Try Omarchy then starts sshd for boots that contain a TCP
mapping to guest port 22, and allows port 22 through Omarchy's firewall from
the Mac's NAT gateway for those boots. It does not change guest accounts,
sshd_config, password policy, or authorized keys.
Connect with the username and password created inside Omarchy (the Mac username is not assumed):
ssh -p 2222 <guest-user>@127.0.0.1Once the initial password login works, install a key if desired:
ssh-copy-id -p 2222 <guest-user>@127.0.0.1For a shorter command, add this to ~/.ssh/config on the Mac:
Host omarchy
HostName 127.0.0.1
Port 2222
User <guest-user>You can then use ssh omarchy, and the same alias works with scp, rsync,
Git, and VS Code Remote SSH. If you edit the preset's Mac port, substitute that
port in every command.
Factory Reset creates a new guest host key, and every ephemeral VM has its own disposable host key. If OpenSSH reports that the key for the reused endpoint changed, remove only that endpoint's old entry and reconnect to verify the new fingerprint:
ssh-keygen -R '[127.0.0.1]:2222'Loopback binding prevents devices on Wi-Fi, Ethernet, or the wider LAN from connecting. It does not isolate the listener from other users or processes on the same Mac; guest SSH authentication is still required.
An optional process-scoped integration can use the Mac's Touch ID to unlock 1Password inside the guest. Existing synced passwords and passkeys stay managed by 1Password. See setup and authorization boundaries.
Guest clock recovery handles time lost during Mac sleep so fresh signed approvals remain usable after wake.
The native authentication bridge can enroll this Mac and use
Touch ID as a sufficient authentication method for guest sudo. Open
the Touch ID for sudo row in the Omarchy menu, or run:
try-omarchy-touch-idThe integration ships disabled. Enabling first requires the normal guest sudo password, then Touch ID creates and proves possession of a Secure Enclave signing key. Only after that succeeds is the narrowly scoped sudo PAM rule installed. The menu then offers Test, Re-pair, and Disable actions.
The Mac stores only the Secure Enclave's device-bound encrypted key representation. Every later approval is signed over a root-private guest ID, fresh challenge, the sudo user and requesting user, the interactive TTY, and a 15-second validity window. Each enrolled guest has a distinct host signing key. The QEMU window must be frontmost. Cancellation, invalid responses, missing enrollment, and unavailable Touch ID all fall back to the normal guest password; no login or screen-unlock PAM policy is changed.
If Touch ID falls back, sudo displays the reason before asking for the guest
password. Signed approvals require synchronized Mac and guest clocks. If the
guest clock drifted, run sudo systemctl enable --now systemd-timesyncd.service,
then check timedatectl for System clock synchronized: yes before retrying.
Touch ID has not been verified in the current guest yet.
The Touch ID test refuses guest-password fallback and returns failure if sudo cannot authenticate. A passwordless sudo policy can also satisfy this check; the result only demonstrates Touch ID when its prompt appeared. Unanswered Mac prompts are canceled after 55 seconds, before the guest's 65-second timeout. Late responses are discarded without extending the current request's deadline.
Enrollment persists across guest and Mac restarts for the same persistent VM, Mac, and macOS account. Factory Reset, moving the VM to another Mac or account, or changing the enrolled Touch ID fingerprint set requires re-pairing. Disabling removes the guest enrollment and, while the host bridge is available, its wrapped Secure Enclave key representation.
Use Resources → Configure… on the start menu to pick how much of the Mac's RAM the guest boots with. Macs with at least 16 GiB default to 8 GiB; smaller Macs default to 4 GiB. The menu offers 4, 6, 8, 12 GiB and then continues in 4 GiB steps, leaving at least 4 GiB for macOS. For example, a 16 GiB Mac can allocate up to 12 GiB, and a 48 GiB Mac up to 44 GiB. Higher choices that leave less than 8 GiB for macOS are marked “may slow macOS.” An 8 GiB Mac offers 4 GiB only. Existing saved choices, including 4 GiB, are preserved. The choice is not tied to installation: change it before any launch, and it applies the next time Omarchy starts. Memory is a boot-time QEMU setting, never part of the guest image or VM data, so switching allocations never needs a reset and never touches your files. A stored choice that no longer fits the Mac it runs on falls back to the default.
Unused guest memory is automatically returned to macOS through virtio free-page reporting. Omarchy still sees the full selected RAM and can use it again when needed. Reclamation runs asynchronously and covers genuinely free pages, not Linux's file cache or memory still held by applications. For example, selecting 16 GiB and seeing 12 GiB used does not guarantee exactly 4 GiB returned: cache, fragmentation, and VM overhead also affect the Mac's memory usage. Keep enough headroom for macOS even with reclamation enabled.
Scripted launches can set OMARCHY_QEMU_GPU_MEMORY_MIB (a whole number of
MiB) instead. Scripted launches use the same host-aware default and leave
at least 4 GiB for macOS for allocations above the 4 GiB baseline. They also
accept values between menu steps, down to the guest's 2048 MiB minimum. The
4 GiB baseline remains available on smaller hosts such as CI runners.
New VMs inherit the Mac's primary language on first boot: English, Traditional
Chinese (zh_TW.UTF-8), Simplified Chinese (zh_CN.UTF-8), Korean
(ko_KR.UTF-8), or Japanese (ja_JP.UTF-8). Other Mac languages currently fall
back to English. There is no launcher language setting; change the locale inside Omarchy afterward. Later
boots and Mac language changes do not overwrite that guest choice.
Applications use translations where available. Omarchy's own setup wizard and menus stay in English: upstream has no translation mechanism for those shell scripts.
Omarchy sets up input methods itself. Its first-boot form asks for the keyboard
and input method (choosing Japanese selects Mozc); change it later with
Super+I or Setup > Input. The try-omarchy package keeps the Mozc,
Chewing and Hangul engines and CJK fonts installed, and on a Mac JIS keyboard
maps かな and 英数 to turning the input method on and off. macOS and
Omarchy select their input methods independently. See
Japanese input for details and verification.
- Apple Silicon Mac (
arm64) - macOS 15 or newer
- About 12 GB free for the first launch (the decompressed factory disk is about 9 GB), plus room for the VM to grow
Nested virtualization is off by default: with ARM EL2 exposed, the UEFI boot
currently hangs before Linux starts on M3 and newer Apple Silicon. Scripted
launches can set OMARCHY_QEMU_GPU_NESTED_VIRT=1 to try it on macOS 26 or
newer; when the host supports EL2, the guest then provides /dev/kvm for
nested VMs and compatible VMMs. Hardware-accelerated graphics are available on
both macOS 15 and macOS 26.
The start menu shows the installed Mac app release and Check for Updates…; the native application menu offers the same command. The update window checks the project's latest stable GitHub release and links to its release notes and download. Review the release's macOS requirements before installing.
Automatically check for updates is on by default; an existing choice to disable it is preserved. Opening the app checks at most once every 24 hours. A newer release changes the start menu link to Update Available… and shows a Download / Skip dialog when the launcher or settings are ready. It waits while you use the guest or another dialog. Download opens the GitHub release page; Skip hides reminders for that version. Each release is announced only once, and the update link and manual checks remain available at any time. Checks contact GitHub without a GitHub account, and failures do not block VM startup. This feature does not download or install app updates automatically.
Older app bundles used the same version metadata for different releases. If the build does not include a matching release tag in its metadata, the window reports an unknown installed release or a development build instead of claiming that it is up to date. The latest release and manual download remain available.
To upgrade, shut down Omarchy, quit the app, download the new DMG, and replace Try Omarchy in Applications. Reopen it to use your existing VM. You do not need to reset or delete the VM to update the Mac app.
Normal launches keep one persistent VM under
~/Library/Application Support/Try Omarchy/VM/v1: its disk and UEFI variables
in shell/, and the decompressed factory disk, shared by every new VM, in
shell-factory/. Removing or updating the app does not remove or replace this
data. The VM boots its own kernel and updates itself. A newer app's factory
image is downloaded only to create a new VM, after a confirmed Reset
Omarchy, or for an ephemeral launch, and removed once the VM has started.
VMs created by earlier versions of the app, which booted a kernel from the Mac,
are not launched by this version. Their files (disks/, boot/) stay in the
same folder untouched, and the app attaches the old disk to the new VM
read-only. Omarchy says so once after login; to bring your files over, choose
Setup > Import Previous VM in the Omarchy menu, or run:
try-omarchy-import-previous --dry-run # list what would be copied
try-omarchy-import-previous # copy it
try-omarchy-import-previous --packages # install the packages you had added
try-omarchy-import-previous --open # browse the old disk, --close when doneThe import copies every visible file and folder in your old home folder, plus
SSH and GnuPG keys, Git and GitHub CLI settings, fonts, pass, AWS and
Kubernetes credentials, and never replaces a file that already exists. It
leaves the old ~/.config alone, since it was written for an older Omarchy;
browse it with --open and copy what you want by hand. --packages installs
the packages you installed yourself in the old VM; those not in Omarchy's
repositories (from the AUR, say) are listed for yay. When you have
everything, delete disks/ and boot/ from the storage folder to detach the
old disk and free its space. Reset Omarchy leaves them alone.
Before Reset is enabled, the confirmation sheet requires typing Try Omarchy
exactly; cancelling the sheet returns to the start menu without changing the VM.
Each persistent launch writes the guest's virtio console to
~/Library/Application Support/Try Omarchy/VM/v1/shell/console.log, and moves
the previous launch's log aside to console.log.1 first. The guest adds
console=hvc0 to its own kernel command line for this. This is the record to
read when Omarchy fails to boot, loses its network, or hangs, because a fault
that forces a reboot is otherwise gone by the time you can look. An ephemeral
launch keeps its log with the rest of its temporary state and discards it on
exit. The log holds whatever the guest prints to its console, so treat it as
guest data and review it before attaching it to a bug report.
If QEMU crashes in hv_vm_map or hv_vm_unmap, a trace of the VM's memory
mappings shows which range failed. Quit Try Omarchy, then launch from Terminal
with an absolute log path:
OMARCHY_QEMU_GPU_HVF_TRACE_LOG="$HOME/Desktop/hvf-trace.log" \
"/Applications/Try Omarchy.app/Contents/Resources/scripts/run-qemu-gpu.sh"The log holds memory addresses and sizes, no guest data. Attach its last few hundred lines with the crash report.
Omarchy updates itself inside the VM: run omarchy update or use
Update → Omarchy in the Omarchy menu. It updates Omarchy, Hyprland and the
kernel, and takes a Snapper snapshot first; the snapshot appears in the boot
menu so you can roll back. omarchy-channel-set switches channels when
Omarchy publishes another one for ARM. Updating the Mac app does not change
these.
A confirmed reset is the deliberate, destructive way to start again from the newest bundled factory. Reset deletes the saved VM; the next launch prepares its replacement.
The Mac integrations inside Omarchy are the try-omarchy package. Each app
release bundles its version and offers it to the VM at every boot; the VM
installs it before login when it is newer than the installed one. There is
nothing to approve or run. The start menu's Omarchy row shows the guest's
Omarchy version and channel, and the integration version, after the VM has
started once. See integration updates.
Open Manage… on the launcher's Selected VM row after shutting down Omarchy. The dialog shows the selected VM folder and explains what the next launch will do:
- Switch to another VM → Choose Existing VM… selects a saved VM in another
folder. Choose the complete folder containing
shell. Files stay where they are; this changes which VM the app will launch. - Move the selected VM → Choose Destination… copies that VM into a completely empty APFS folder, verifies every file, and selects the copy only after success. The decompressed factory copy is not moved; the next launch rebuilds it. The dialog shows copy and verification progress, then the new selected folder and the original recovery-copy path. The original is kept.
- Create a separate VM → Choose Empty Folder… selects an empty folder for a fresh VM, created on the next launch. The previously selected VM is kept.
- Delete the selected VM → Delete VM… shows the exact folder and asks you to
type
Try Omarchyto confirm, then moves the whole VM to macOS Trash. Other VM copies are kept. Recover it from Trash before emptying Trash, or choose another VM or an empty folder to continue. A running VM cannot be deleted. - Use Default Folder selects
~/Library/Application Support/Try Omarchy/VM/v1again. If that VM has been deleted, the next launch creates a fresh VM there.
Choices are saved immediately. Done returns to the launcher; press Launch there to start the selected VM. During copying, verification, or deletion, Done and the other choices are disabled. Errors stay in the dialog. Failed operations keep the selected VM intact.
Moving always acts on the VM selected in the dialog. To move a different saved VM, switch to it first. Copies evolve independently after booting; switch between them with Choose Existing VM….
For example, create ~/Try Omarchy in the folder picker to relocate the VM
into your home directory. Omarchy uses exactly the selected folder. A drive's
top level and unrelated populated folders are refused.
Both locations must be on local APFS drives. Relocation holds the same
lock as the launcher, refuses an open VM and unsafe links, and never
replaces files at the destination. Same-volume copies use APFS clones;
cross-volume copies preserve sparse capacity. Leave enough free space for the
VM's allocated data plus 1 GiB of headroom. If copying or verification fails,
the original and the selected boot location stay unchanged. Do not delete the
original until you have booted and checked the relocated VM. Once you have
checked your files and settings, you can delete that old workspace, or retain
it as a recovery copy. For the default location, delete only VM/v1, keeping
the surrounding Try Omarchy Application Support folder: it also stores the
host Touch ID keys used by the relocated VM.
- Do not disconnect the drive while Omarchy is running. macOS refuses a normal eject while the VM holds the disk, but pulling the cable can damage it. If the volume does disappear, Omarchy shuts the VM down instead of writing on.
- If the drive is not connected, Omarchy will not quietly use the default VM instead. Launching offers to switch back to the default folder; resetting refuses outright, so a reset can never erase a workspace other than the one you confirmed. Opening the folder from the start menu will not recreate it on your startup disk either.
- Xcode command-line tools with Swift 6
- Python 3
pkg-config(Homebrew is the simplest way to install it)- A running Docker-compatible engine that supports privileged
linux/arm64containers - Roughly 40 GB free for the guest build (a 20 GiB sparse disk image, its compressed copy and the package cache), the runtime, and assembled output
Install the one Homebrew build tool with:
brew install pkg-configmake doctor performs the basic preflight. make runtime downloads a
checksum-pinned dependency set, builds QEMU, patched libslirp, and patched VirGL
for macOS 15.0, and rejects any runtime image that raises that minimum or strongly imports an
API unavailable on the declared platform. Installed Homebrew library versions
are never copied into the app.
For a first full build and launch:
make build runThe first build downloads Omarchy's packages to install the factory disk and
compiles QEMU from pinned sources, so it can take a while. make build includes the basic toolchain
check. Later builds hash the effective inputs and validate the existing outputs,
then rebuild only the guest package, factory disk, runtime, or app that changed:
a guest package change rebuilds the package in seconds, not the factory, and
pinned runtime downloads are kept in .build/downloads. To bypass that cache
deliberately, run make build FORCE=1 (or add FORCE=1 to an individual
component command).
The factory installs whatever Omarchy's edge repositories serve when it is
built. After each build, make build prints whether Omarchy has moved since
then, with the factory's age and the newer packages; make refresh rebuilds
the factory from the latest Omarchy. make release reuses the factory only
when everything it was built from still matches upstream, and rebuilds it
otherwise; make release FORCE=1 always rebuilds it.
Artifacts created before their .build/state/ record exists are rebuilt once;
the cache never adopts an output whose successful inputs it did not observe.
The generated app lives under dist/app.noindex/. macOS can run and package
the bundle normally, but Spotlight will not present it beside an installed
copy as a second, indistinguishable Command-Space result. The first app rebuild
after this layout change removes the old generated bundle from dist/.
Local builds use a separate Try Omarchy Dev privacy identity and automatically
select an installed Apple Development signing certificate, falling back to
Developer ID Application. Grant Accessibility, Camera, and Microphone once for
development; those decisions can then survive rebuilds with the same signing
identity. make package and make release keep the production identity and its
separate permission flow, and write the app to dist/release.noindex/.
If several certificates are available, set DEVELOPMENT_SIGN_IDENTITY to the
one you want. Without a certificate, local builds stop with setup instructions.
Use DEVELOPMENT_SIGN_IDENTITY=- for intentional ad-hoc builds, which still
require renewed grants after rebuilds.
Launching also ensures that the guest, runtime, and native app are current, so the normal follow-up command is:
make runRun the complete contract and native test suite with:
make testRun make help for component builds, persistent-storage reset, ephemeral mode, and cleanup commands.
To reclaim development build space, run:
make cleanThis removes all repository build output, the native and guest build caches, and Try Omarchy's project-scoped Docker builder image and work volumes. It does not touch a developer's persistent VM.
For a complete local reset, first quit Try Omarchy and then run:
make clean-allThe deep cleanup also permanently deletes the current user's Try Omarchy VM
disks and app state, plus stale Try Omarchy build and test directories in the
macOS temporary directories. It only selects Docker resources and temporary
paths owned by this project; it does not run a global Docker or system prune.
To prevent accidental data loss, the command requires an interactive terminal
and only proceeds after the developer types clean-all at the confirmation
prompt.
All generated output has one predictable home:
dist/
├── app.noindex/
│ └── Try Omarchy.app # development identity
├── release.noindex/
│ └── Try Omarchy.app # production identity
├── TryOmarchy.dmg # after make package or make release
├── factory/ # the image's release assets, after make package or make release
└── guest/ # factory disk, factory.json, packages/
Both DMG targets create distributable artifacts:
make packagerebuilds the app, Developer ID-signs the app and DMG, notarizes the DMG with Apple, and staples the notarization tickets. It usesPACKAGE_SIGN_IDENTITYandPACKAGE_NOTARY_PROFILE, which default to the configured release credentials, and fails instead of producing an unnotarized fallback.make releaseoffers patch, minor, or major selection and direct version entry, builds guest, runtime and firmware artifacts when needed, creates an annotated local release tag, and performs the same signing and notarization workflow with the release-specific credential variables. Usemake release VERSION=vX.Y.Zto choose the version without prompting.make publishpushes that tag and attaches the DMG and the factory image parts to its GitHub draft release, creating the draft if needed. Publishing the draft remains manual.
Maintainers should follow docs/releasing.md for the full build, test, signing, license, corresponding-source, and verification checklist.
.
├── Makefile public build interface
├── macos/ Swift launcher and QEMU/HVF runtime builder
├── guest/ try-omarchy guest package and factory-disk builder
├── docs/ architecture and release documentation
├── dist/ generated output (ignored)
├── CONTRIBUTING.md
├── SECURITY.md
├── THIRD_PARTY_NOTICES.md
└── LICENSE
The architecture and trust boundaries are documented in docs/architecture.md. Contributors should start with CONTRIBUTING.md.
Try Omarchy is pre-1.0 and under active development. Omarchy and bundled dependencies retain their own licenses; see THIRD_PARTY_NOTICES.md.
Report ordinary bugs through GitHub Issues. Report suspected vulnerabilities using the private process in SECURITY.md, not a public issue.
MIT - Created by Eduardo Martinez