Repository navigation
Conversation
@maralcbr feel free to, thanks! |
eebfbc0 to
8c7c65b
Compare
|
Two updates, force-pushed with the same trees plus one new commit:
For omarchy-pkgs#380: |
Nine keymaps the keyboard picker offers have no row in systemd's kbd-model-map: colemak, azerty, bg-cp1251, cz, de_CH-latin1, kyrgyz, no-latin1, pl and ua. systemd-firstboot and localectl persist those as KEYMAP alone, and default/hypr/input.lua falls back to us without XKBLAYOUT, so a Polish, Czech, Ukrainian, Bulgarian, Norwegian, Swiss German, Kyrgyz or Colemak user got the chosen console keymap and a US desktop. For cz, de_CH, azerty and colemak the ASCII keys move between the two, so a password set on the console types differently at the desktop. Those rows now carry the XKB layout[:variant] as a third field, and omarchy_keyboard_xkb_settings turns it into the lines systemd-firstboot writes for a mapped keymap, with its pc105 model and terminate:ctrl_alt_bksp option. First-boot owner setup inserts them after KEYMAP once the keymap is persisted and only when systemd wrote no XKBLAYOUT, so every keymap systemd maps comes out exactly as before. The ISO's configure_keyboard reads the same helper from the list it vendors. Each layout is the one for the same language whose letters sit where the console keymap puts them, checked key by key against xkeyboard-config: kbd's cz is its QWERTY Czech map (cz:qwerty) and bg-cp1251 its phonetic Bulgarian one (bg:phonetic). ua, bg and kg are non-Latin, so input.lua puts us in front of them with the Alt toggle, as it does for the mapped ones. The pinned layout is for the desktop only. Plymouth reads a vconsole.conf with KEYMAP and no XKBLAYOUT through the console keymap the keymap hook loads, the one the LUKS passphrase was typed on in the installer and in first-boot setup, but switches to XKB as soon as XKBLAYOUT is set. Some pinned layouts put other characters on the same keys (Shift+4 is $ on the no-latin1 console and ¤ in XKB's no; azerty's = key is ! in XKB's fr), so the passphrase typed at install would stop unlocking, and the Latin-layout check would start leaving ua, bg and kg out of the initramfs. When the XKB lines in vconsole.conf are exactly the ones omarchy_keyboard_xkb_settings gives for its KEYMAP, omarchy_hooks.conf now bundles the file through a new omarchy-vconsole hook that leaves them out, so the initramfs gets the file it got before the pin and the LUKS prompt reads keys as before. The hook hands mkinitcpio a regular file rather than a pipe, because add_file reads its source twice when an earlier hook such as sd-vconsole has already added vconsole.conf. Every other vconsole.conf goes through the Latin-layout check and FILES exactly as before: one for a keymap systemd maps, one for a picker keymap written before the pin (so a later drop-in that sets HOOKS outright still keeps it), one with XKB lines set by hand, such as a QWERTZ cz layout on the cz console keymap, and any file on a system whose setup-form.sh is missing or predates the helper. The check reads the packaged setup-form.sh under /usr/share/omarchy rather than $OMARCHY_PATH, so rebuilding from a shell pointed at a checkout can't change what the LUKS prompt reads, and the list test pins all nine layouts, since changing one sends existing installs' desktop layout to the LUKS prompt. The Azerbaijani row is relabelled French (AZERTY). kbd's azerty is the French AZERTY map and kbd ships no Azerbaijani one; pairing it with XKB az would have the console and the desktop type different letters (az puts ü on W), so the row now says what it gives and gets fr. The mkinitcpio-hooks-test in omacom#13362 composes the drop-ins against the host's own /etc/vconsole.conf and sets its FILES entry aside. On a machine whose vconsole.conf carries a pinned layout it would also need to set omarchy-vconsole aside from HOOKS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019juCxGWnRefP2JnpA5tmdt
|
Pushed six more commits (section 7 in the description): generic helpers omarchy-mac grew for aarch64 that any machine can use, one commit each with its callers and tests.
None of them adds an Apple branch. In an x86_64 container each of the six fails exactly the same |
|
Rerun done: all 15 Apple-relevant test files from the six helper commits pass natively on the M2 Max at the pushed head (087bd8d). |
|
Pushed five more commits (section 8 in the description): what prebuilt images and a platform's own setup need, one commit each with its tests. None of it runs on an ISO install.
Testing, on the pushed revisions: in an x86_64 Arch container each of the five fails exactly the same |
|
Pushed eight more commits (sections 9 and 10 in the description). They cover the Apple Silicon lines omarchy-mac still carried in files Omarchy already has, one commit per area with its tests. Mac-only desktop defaults don't come into Omarchy. Omarchy gets generic places a platform package fills, and omarchy-mac ships the Mac's own files there.
Without a platform package, the new directories and files are empty or absent and the dispatch operations resolve to nothing, so x86 and Snapdragon run as before. The exceptions are the generic detection fixes, listed under Risk. Testing:
@scottjones, @ryanrhughes, @skkumarsparsh, @dl-alexandre and @kx0101 are co-authors where their code is carried. |
omacom/omarchy#13362 sets HOOKS per platform inside 00-omarchy-hooks.conf, with no column-0 HOOKS= line, so the aarch64 build failed on it; settings-dev tracks quattro automatically and would break as soon as it lands. Wrap only a single-line HOOKS=(...), refuse any other column-0 HOOKS=, then source the shipped files onto a Mac line and a stock line: the Mac line must come through unchanged and the stock one must not. Back up 00-omarchy-hooks.conf when it ships, and refuse it without the omarchy-hw-platform copy it asks. The test now uses the real v4.0.4 hooks file, #13362's two files and omarchy-mac-boot's 90-94 fragments, and covers upgrades over a hand-restored file.
|
Pushed seven more commits (sections 11 to 13 in the description):
x86_64 runs as before: the refresh copies the same templates, the keyring step is unchanged, and the Thunderbolt module is still listed. Snapdragon differences from Testing:
@birkskyum and @jdvmi00 are co-authors of the pacman commit, and @scottjones of the Apple package list. |
ad15142 to
fe9611e
Compare
|
Thanks @scottjones, this was a great pass. I've taken nearly all of it, rewriting the commits rather than adding removals on top, so each change lands in the commit it belongs to. The branch is now 45 commits: the head you read, plus the step 6 commits and sections 11 to 13 pushed since, with this round folded in. Point by point: Dropped
Synced with
Keep, but easier to see
Your open questions
Credits
|
|
Thanks @maralcbr, and sorry for the slow reply. Yes please, I'd be glad to be added on the detector and the guard. I went through the detector, the guard and the channel refresh from the Snapdragon side. Detector. A
Guard. It reads well from our side. Starting with no Qualcomm tags and adopting them package by package suits us. Refresh. Both differences are fine by me. A stable Thanks for carrying |
fe9611e to
39a9909
Compare
…-boot setup A deferred install (an Apple Silicon image, an OEM ISO install) runs its hardware steps before the owner picks a timezone, on the UTC placeholder, which names no country, so install/hardware/set-wireless-regdom.sh leaves the regulatory domain unset and the radios stay on the world domain. Owner setup now runs that step again once the owner's timezone is set, and applies it to the radios through wireless-regdb's helper, since no reboot follows setup. An up-front install, which picks the timezone before its hardware steps, is unchanged.
First-boot setup kept going when the chosen layout did not take: loadkeys errors were ignored, a keymap localectl did not list kept the default, and a failed or partial write of /etc/vconsole.conf was only logged. The owner then typed the disk password in one layout while the boot files asked for it in another, and could only unlock the disk by typing US-style. The keyboard step now fails closed. On a console loadkeys must succeed, the keymap must be in localectl's list exactly (a list localectl cannot produce counts as a failure too, logged apart), and after systemd-firstboot or the localectl fallback, /etc/vconsole.conf is read back in a clean shell and must name the chosen keymap with an XKB layout. Any failure is logged, the owner is told the layout could not be set, and the layout is asked for again, so the password form is never reached with a layout that did not take.
omarchy-update-keyring reinstalls archlinux-keyring (and Arch Linux ARM's on aarch64) before the system upgrade, so a rotated key never fails that upgrade's signature checks. A platform's own repository has a keyring of its own that nothing refreshed: on Apple Silicon, asahi-alarm-keyring for [asahi-alarm]. A platform package now lists those keyrings in /usr/share/omarchy-platform/keyrings, one package name per line, and omarchy-update-keyring reinstalls each one that is installed in the same transaction. It adds no repository the machine didn't already trust. A line that isn't one keyring package name is skipped with a warning, so a mistake in the list can't stop every update. Without the file, as on x86 today, the step runs as before.
Quickshell types only exact media classes, so a virtual source (an Audio/Source/Virtual: EasyEffects' source, or the microphone mapping a platform package adds) has no PwNode.audio. With one as the default input the audio panel showed the input at 0% and its slider changed nothing, the peak meter stayed flat, the microphone widget read it as muted, and the panel could not list it unless it was already the default. Such an input now goes through wpctl for its volume and mute (UntypedInput in shell/Commons, one reader and one pactl subscribe for the whole shell), the panel meters it with the new omarchy-audio-source-level, and the input list takes an untyped node PulseAudio lists as a source. A platform whose audio runs through its own processing can also name nodes that are neither devices nor apps in /usr/share/omarchy-platform/audio.json, which Omarchy ships none of: the panel and the microphone widget leave them out, and a "replaced" node only while its replacement exists. Without the file nothing is hidden. On every machine: the input list leaves out a source whose ports are all unavailable (an empty headset jack) unless it is the default, as the output list does for sinks; choosing an input no longer moves a filter's own capture (a source output with node.link-group), which would feed the filter from the new input or from itself; the shell's own level meters no longer light the microphone widget; and omarchy-audio-sink-availability reads pactl in the C locale for sinks too, since "not available" is translated.
systemd-firstboot writes an XKB layout only for keymaps listed in kbd-model-map. Nine the setup form offers are not (Colemak, Azerbaijani, Bulgarian, Czech, Swiss German, Kyrgyz, Norwegian, Polish, Ukrainian), so it wrote KEYMAP= alone, the readback refused it, and owner setup could never get past the keyboard step for them. Setup now adds the XKB settings itself when firstboot left none, matching the console map so the shared password types the same on the desktop: kbd's cz is QWERTY, bg-cp1251 phonetic and azerty French AZERTY, and non-Latin layouts keep a US layout to switch to, as kbd-model-map's own rows do. A test checks every layout the form offers ends with an XKB layout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Codex XHigh <noreply@openai.com>
The ambient keyboard backlight treated any 0 the keyboard-brightness keys had not recorded as an accident and relit it within five seconds. Firmware Fn keys (Fn+Space on ThinkPads and Framework laptops, Fn+F10 on Dells) write the LED directly, so on those laptops turning the keys off never stuck. The lock screen's off now records a blank, and only that blank or a 1% leftover is taken back; any other off is a choice that pauses auto like the keys do. A wake clears the blank only once the restore succeeded, the command runs one at a time so a blank racing a wake can't leave the LED and record disagreeing, and the loop drops a blank once it has taken the keys back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Codex XHigh <noreply@openai.com>
Each menu open checked every Install row against the sync databases, which costs most of a second of pacman work on every machine to hide rows only an ARM machine is missing. The fix for those is publishing the ARM packages, not hiding the rows, so this removes omarchy-pkg-available, the Install rows' availability and architecture guards, and reinstall's skipping of defaults no repository offers. The Windows VM row keeps its x86_64 guard, since no package fixes a guest that needs an x86_64 host, and reinstall keeps its aarch64 channel handling. This reverts commit aea001c. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Codex XHigh <noreply@openai.com>
Factory reset moved the running root aside, marked the reset committed, then renamed the staged factory root to @. If that second rename failed, cleanup saw a committed reset: it skipped the boot package's rollback and kept the throwaway LUKS slot, and since the swap had not happened it deleted the staged root as well, leaving nothing at @. The reset now commits only once the factory root is at @. A failed activation renames the old root back first, then cleanup rolls the platform's boot state back and revokes the throwaway slot. If that rename fails too, both roots are kept, cleanup still rolls back and revokes, and the error names the rename that recovers the machine. The generic Limine path has already rebuilt its boot files from the factory root by then, as it had before this change.
A saved pid that no longer named a recorder made status and stop select every gpu-screen-recorder and wf-recorder the user ran, so stopping could interrupt, and after five seconds kill, a recording started somewhere else. A stale pid now means no recording of ours is running: the toggle starts a new one, and --stop-recording finds nothing to stop. Stop acts on the recorder the status check selected rather than selecting again. Without a saved pid, as for a recording started before the pid was saved, every recorder the user runs still counts.
With desktop and microphone audio both requested, wf-recorder records a null sink fed by two loopbacks, and a loopback that failed to load was ignored: the recording went ahead without that source, or silent when both failed. A missing null sink or default device dropped audio just as quietly. A source that cannot be captured is now left out with a notification naming it, the loopbacks that did load are unloaded, and the recording carries the source that remains, or no audio track at all.
These vendors currently publish Linux builds for x86_64 alone (the AUR's
microsoft-edge-stable-bin and spotify are arch=('x86_64'), and Dropbox lists
no Linux ARM client), so no native aarch64 build is available and choosing
one on an ARM machine only fails. Like the Windows VM row they keep a uname
check, which the menu answers once per open without asking pacman. The other
Install rows are unchanged.
The generic Limine path added its throwaway LUKS slot without recording it, so a reset that failed before activation never revoked it. Once the factory root's UKI was on the ESP, a failed activation that put the old root back left a machine that booted the factory kernel and unlocked unattended with a key readable on the ESP, while the screen said the current root was back. The generic slot is now recorded like the platform's and revoked by cleanup whenever the reset fails before the factory root is active. A failed activation on that path says the boot files were already rebuilt from the factory system and to run limine-update before rebooting.
The recorder's pid is saved only once its file exists. Until then a pid left by a recording that ended without a stop still counted as stale, so pressing the toggle again while the new recorder started found nothing of ours and could start a second recording. Starting a recording now clears that pid, and during startup the toggle falls back to the user's recorders as before.
The notice said the dropped source "could not be captured", which was wrong when the null sink itself failed to load: the microphone was never tried, and desktop audio recorded alone as it always has. It now says the source could not be added to the recording, true for a missing device, a failed loopback and a failed null sink alike.
Heroic publishes Linux builds for x86_64 alone (its arm64 builds are for macOS and Windows), and Mojang's Linux launcher is a single x86_64 tarball. They join Edge, Spotify and Dropbox under the same uname check, so every row whose vendor ships no native Linux aarch64 build is treated alike.
The bar indicator and the menu's Stop Screenrecording row asked the process helper whether any recorder the user runs was alive, while the toggle's stop acts only on the recording it saved. With a stale saved pid alongside an unrelated recorder, both offered a stop that did nothing. omarchy-capture-screenrecording --status answers with the selection the stop uses, and both now ask it. Status needs no recordings directory and never notifies, so the recordings-directory check moved below argument parsing and skips it.
On aarch64 a channel change edited the machine's pacman.conf in place: an awk pass found the [omarchy] server and rewrote its channel, appended a section where there was none, checked the channel's omarchy.db first, and gated it all on a per-platform table of qualified channels. Install finalization appended Omarchy to a template, or on a Mac copied one bundled inside omarchy-mac. What a machine ended up with was never in the repository. Each platform now has a pacman.conf and mirrorlist per channel, copied whole: x86_64's stay in default/pacman, Snapdragon and other aarch64 machines use default/pacman/aarch64, and Apple Silicon default/pacman/apple-silicon, with Omarchy and Asahi ALARM ahead of Arch Linux ARM. Omarchy publishes aarch64 packages on edge alone so far, so every ARM channel points at edge for now and channel changes work there; moving a channel is a template edit. A channel without both files is refused before anything changes, including a dev checkout's own templates. Reinstall goes back to resetting to stable, and the update confirmation loses the missing-repository notice it no longer needs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Codex XHigh <noreply@openai.com>
…does" This reverts commit 9a07e13.
On aarch64 a channel change edited the machine's pacman.conf in place: an awk pass found the [omarchy] server and rewrote its channel, appended a section where there was none, checked the channel's omarchy.db first, and gated it all on a per-platform table of qualified channels. Install finalization appended Omarchy to a template, or on a Mac copied one bundled inside omarchy-mac. What a machine ended up with was never in the repository. Each platform now has a pacman.conf and mirrorlist per channel, copied whole: x86_64's stay in default/pacman, Snapdragon and other aarch64 machines use default/pacman/aarch64, and Apple Silicon default/pacman/apple-silicon, with Omarchy and Asahi ALARM ahead of Arch Linux ARM. Omarchy publishes aarch64 packages on edge alone so far, so every ARM channel points at edge for now and channel changes work there; moving a channel is a template edit. A channel without both files is refused before anything changes, including a dev checkout's own templates. Reinstall goes back to resetting to stable, and the update confirmation loses the missing-repository notice it no longer needs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Codex XHigh <noreply@openai.com>
Fresh installs mark every migration done, and every Apple Silicon machine is a fresh install, so the Mac handoff to omarchy-mac-boot (and the migrate operation it called), zram for aarch64 installs that predate the package list, the Brave Widevine link and the Broadcom migration's Apple Silicon guard never run anywhere. The exit-75 deferral in omarchy-migrate existed only for two of them. Keyboard backlight auto stays on new installs through first run rather than switching on for existing ones, and migration 1786605598 goes back to quattro: the mkinitcpio drop-ins arrive by package. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pacman platform guard (and the detector copy omarchy-settings shipped for it, which the HOOKS baseline fell back to), the lint against uname gates, first run staying pending after a failed finalization, run_logged echoing failures to stderr, half-up battery rounding, hiding empty-jack inputs and leaving a filter's capture alone when choosing an input all rode along with the Mac work without serving it. Each goes back to quattro's behaviour and can come back on its own merits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A platform package could load its own Hyprland binds, settings and gestures: binds that replaced Omarchy's chords and decorated every later bind, settings ahead of the theme, and gestures after the user's files, which needed every hl.gesture call wrapped so a default could step aside. On a Mac those carried macOS habits (a three-finger workspace swipe, tap-to-click off, menus opening on the built-in screen, other screenshot and keyboard-backlight chords), not anything the hardware needs, and Omarchy should behave the same on every machine. The one bind a Mac does need, its lid switch under the SMC's name, joins Omarchy's own lid binds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ts them Every aarch64 channel's template pointed at the edge repository, but a switch to stable or rc installs the release-named omarchy and omarchy-settings. On edge/aarch64 those are the 4.0.4 release line, which has no omarchy-hw-platform, lifecycle dispatch or omarchy-pkg-defaults, so `omarchy-channel-set stable` on a Mac replaced the quattro runtime it runs with one that cannot run it, and succeeded. aarch64 platforms now have edge templates alone, so a switch to stable or rc is refused before anything changes; adding those templates once a release supports aarch64 opens them. Refresh with no channel named, as reinstall runs it, and install finalization for a channel the platform has no templates for take the platform's default channel: stable on x86_64, edge on aarch64.
d0b94d9 returned omarchy-audio-input-set-default to moving every source output, as not serving Mac support. It does: asahi-audio's microphone DSP on Apple Silicon records the raw array through a filter-chain capture stream (audio_effect.jNNN-mic, node.link-group "filter-chain-..."). On an M1 Pro, choosing the Mac's microphone in the audio panel moved that stream onto the DSP's own output, and the microphone recorded digital silence (-91 dB, from -55 dB of room noise) until PipeWire restarted. With the skip it keeps recording (-54 dB). This restores the skip of source outputs carrying node.link-group, and its test, as they were before that commit.
The aarch64 edge templates, the template helper and the update-process docs still said every platform has a template per channel and every ARM channel installs from edge, which the previous commit made untrue.
omarchy-mac and omarchy-mac-boot now live in omacom/omarchy-mac-pkgs, with each package at the top level. The dispatcher, its documentation and the Apple Silicon package list name that repository, and the drop-in test's fixtures, byte for byte the same as omarchy-mac-boot/files/etc/mkinitcpio.conf.d at 4399105, cite it there.
The migrate operation went with the Mac migrations, and no caller hands a machine to a platform migration any more, so the header lists only the flows that still dispatch. The optional-operations comment is rewrapped.
A fresh install marks every migration done only for the user it creates, so an account added later runs them all on its first update. On an Apple Silicon Mac this one matches: an M1 Pro reports sys_vendor "Apple Inc." and a BCM4387 (14e4:4433), so it would append feature_disable=0x82000, which stops that chip scanning once brcmfmac reloads. Restore the guard and its test case.
Steam's installer now adds the 32-bit drivers before Steam itself, so the hook runs after both and before the first launch.
606e33d to
2827c5e
Compare
This is the generic part of the Apple Silicon work in omacom/omarchy-mac, plus fixes Snapdragon and x86 need too, as one PR in place of the eight smaller ones we had lined up. It has 48 commits grouped by topic. Each one adds no test failure over the baseline given under Testing, so it can be reviewed and bisected commit by commit. On x86 every new path is a no-op or behaves exactly as today, except for the changes listed under What changes on x86.
Why
aarch64 now covers Snapdragon laptops (
dragon), Apple Silicon Macs (omacom/omarchy-mac), Raspberry Pis and VMs, souname -mcan no longer pick platform setup. Macs also boot through a chain (m1n1 → U-Boot → Limine, with the install key on a separate boot partition) that first boot, factory reset andomarchy updatecan't drive through the Limine UKI path. Until now omarchy-mac carried Mac branches inside those flows. This PR gives Omarchy one detector and a small, fixed set of lifecycle hooks that a platform's boot package implements. Omarchy keeps no Mac code; the Mac side ships as packages.Along the way we found and fixed generic bugs in the encrypted first-boot path: the LUKS parent lookup broke on
lsblktree glyphs, an interrupted re-key could lock setup out or leave the disk unlocking unattended, andomarchy-drive-passwordleft the login and root passwords behind.What changes on x86
Everything else in this PR is a no-op on x86 or read-only there. These change behaviour on purpose:
lsblktree glyphs), the journaled first-boot re-key, the factory-reset passphrase check ignoring tokens, andomarchy-drive-password: on the system disk it now changes the login and root passwords with the disk's, as setup gave all three one password, and says so before it asks for anything. LUKS1 drives can change their password again, and the drive list comes fromlsblk, so it no longer says there are no encrypted drives until root has runblkid.thunderboltis early-loaded only where the kernel builds it as a module, as on every x86 kernel today.loadkeysfailing on a console, a keymaplocalectldoesn't list, or an/etc/vconsole.confthat doesn't read back with it) is asked for again instead of being ignored, so the disk password is never set in one layout and asked for in another. After three failures in a row, setup's own retry-or-console screen takes over. The first-boot re-key rebuilds the boot files again if the layout changes after it.widevinepackage; a failed setup step also prints its error on stderr.omarchy-reinstall-pkgsfinishes after skipping a default no repository offers (it prints each).BAT*name: a machine whose battery is named otherwise (Framework'sCMB0, for one) now gets the battery panel and the laptop-only services, and battery status reads its thresholds and cycles. Battery presence ignores a peripheral's battery. Battery status picks the battery UPower marks as the power supply, shows the magnitude of a negativepower_now(kernels that sign it by direction), and rounds the percentage half-up for display instead of truncating it. A machine without an ACPI lid but with an input device reporting a lid switch counts as a laptop, and its lid state comes from logind (ACPI lids read as before).omarchy-hw-touchpadstill takes a device named touchpad or trackpad first; only when there is none does it take a mouse udev marks as a touchpad, so a touchscreen's multi-touch mouse interface is never picked.pactlis read in the C locale for sinks too.omarchy-refresh-pacman,omarchy-channel-setand install finalization askomarchy-hw-platformfirst and stop before changing anything if it can't place the machine; x86_64 then writes the same templates as before.How this relates to omarchy-mac
omarchy-mac's integration branch,
quattro-upstream, carries this generic slice plus the Apple-only content, which stays in omarchy-mac. Once this merges,quattro-upstreamtakes the slice from upstreamquattroand keeps only the Apple packages on top. The branch lives on omacom/omarchy-mac (a fork of this repo) so it can be rebased there alongside that work.What's in it
1. Platform detector and package lists (4 commits)
bin/omarchy-hw-platformprintsapple-silicon,qualcomm,generic-aarch64orgeneric. It reads the vendor prefix of each token in the device tree's rootcompatible(apple,/qcom,, from/proc/device-tree, then/sys/firmware/devicetree/base) and the CPU, and fails instead of guessing when the evidence contradicts itself.bin/omarchy-hw-apple-siliconis a predicate on top of it, for the Mac packages to call./var/lib/omarchy/image/target(format=1,platform=). While a root is being built rather than booted (no/run/systemd/system, PID 1 rooted elsewhere, or PID 1 not systemd) the detector answers from it. A booted system always answers from its hardware. As root the detector restarts underenv -iwithPATH=/usr/binandbash -p.test/shell.d/architecture-gates-test.shfails on a newuname -mplatform gate in shipped code that isn't on its reviewed list (ABI, binary availability, a repository's$arch).bin/omarchy-pkg-defaults [platform]composes the default set:omarchy-base.packages, theninstall/omarchy-aarch64.packages(zram-generator) on aarch64, theninstall/omarchy-<platform>.packageswhen there is one (omarchy-qualcomm.packages:linux-firmware-qcom; Apple Silicon's is in section 11).omarchy-reinstall-pkgsinstalls that set. x86_64 gets exactly the base list, as before, and reinstall stops before touching packages if the platform can't be told.thunderbolt_module.confaddsthunderboltonly wheremodinfofinds it as a module for the kernel being built:linux-aarch64has no such module, and mkinitcpio fails the whole image over a missing one. The optionalthunderbolt?form isn't enough, since a systemd initramfs copies it verbatim into modules-load.d. x86_64 kernels build it as a module, so their images are the same. Co-authored with @scottjones.hw-platform-test.sh(real M1 Pro, M2 Max, M1 mini, Yoga Slim 7x, XPS 13 9345 and T14s trees, QEMU virt, a Pi, ACPI-only aarch64, x86, every contradiction, and agreement withdragon'somarchy-hw-qualcomm-socon every aarch64 fixture),image-target-platform-test.sh(chroots, PID namespaces, bound/run, stale and hostile manifests, root ignoringBASH_ENV, exported functions,PATHand fixture roots),platform-packages-test.sh. Also run natively on aarch64, as a normal user and as root.2. Composable boot and generic encryption (8 commits)
HOOKS=(...)line moves, unchanged, fromomarchy_hooks.confinto a newetc/mkinitcpio.conf.d/00-omarchy-hooks.conf, which sorts first, so a numbered drop-in (90-*.conf) from a platform or hardware package can add hooks without being overwritten.omarchy_hooks.confkeeps the NVIDIA and vconsole handling. Migration 1786605598 now sources the baseline before reading HOOKS. Old against new drop-ins gave identical HOOKS, MODULES and FILES across 588 combinations. Two hand-edited setups behave differently: a user drop-in that sets HOOKS and sorts between00-andomarchy_hooks.confnow takes effect, and a user who deleted the HOOKS line from their ownomarchy_hooks.confnow gets the baseline.omarchy-hw-platform. Apple Silicon starts from the systemd lineomarchy-mac-boot's drop-ins build on: its encryption drop-in reads busyboxencryptas a legacycryptdevice=Mac and leaves such a line alone, so without this an encrypted Mac built an image with nosd-encryptand couldn't unlock. A Mac whose ownmkinitcpio.confcarriesasahior busyboxencryptkeeps its line. x86, Snapdragon and generic aarch64 get exactly the busybox line, with or without the detector. Without the runtime's detector, the baseline uses the copy omarchy-settings ships for the guard; a detector that can't place the machine stops the build.lsblk -sprinted tree glyphs, so owner setup and factory reset stopped with "Could not locate the LUKS device to re-key". It now readslsblk -r. The lookup test is Scott Jones's (@scottjones), extended to LVM on LUKS.--token-type passphrase-only, so an enrolled TPM2 or FIDO2 token can't approve a wrong passphrase.install/provisioning/luks-rekey.sh). The staged-key → owner-password re-key used to run in one pass with no record of progress. Killed after the staged slot was retired, every retry failed. Withluks-keymissing, setup could finish with the disk still unlocking unattended. It now runs as a journaled sequence: record the staged slot, add the owner's key, rebuild boot without the auto-unlock, retire the other slots, verify, destroy the staged key. The journal holds phases and slot numbers only. The staged key is destroyed only once it provably opens nothing. LUKS1 slots are retired too, and key checks ignore LUKS2 tokens.omarchy-drive-passwordon the disk holding/checks the current password, changes the LUKS key, confirms the new key opens the disk and the old one doesn't, and only then sets the login and root passwords (setup gives all three one password). A journal lets the next run finish an interrupted change. Other drives change their LUKS key only.--pbkdf argon2idis now passed only to LUKS2, so LUKS1 drives can change their password again. The manual's security page says so.mkinitcpio-hooks-test.shandnvidia-kms-hook-test.sh(the drop-ins composed the way mkinitcpio does, for plain, NVIDIA, hybrid, T2, SPI MacBook and Surface machines, on every platform and on legacy Mac lines, plus the migration),mkinitcpio-apple-drop-ins-test.sh(the baseline with omarchy-mac-boot's real drop-ins, as fixtures, gives exactly the HOOKS an encrypted M1 Pro boots today),luks-parent-detection-test.sh,luks-rekey-journal-test.shanddrive-password-test.sh. The last two kill the flow after every durable step and rerun it with the old or new password, against a slot-table fake and against real file-backed LUKS2 and LUKS1 volumes.3. Lifecycle dispatch (4 commits)
bin/omarchy-lifecycle-dispatch <operation>calls a fixed set of operations:provision-prepare,provision-commit,provision-verify,reset-prepare,reset-verify,reset-commit,reset-rollback,update-verify,luks-slots(andmigrate, below, and the setup and app operations in sections 8 and 10). Registration is code:apple-silicon→/usr/lib/omarchy/mac-boot, shipped byomarchy-mac-boot.generic,generic-aarch64andqualcommregister nothing, so every call is a no-op there. A required operation with no entrypoint fails and names the package. As root it runs underbash -pwith a fixedPATHand trusts only root-owned, non-symlinked entrypoints in root-owned directories, run underenv -i.provision-prepare, and usesprovision-commit/provision-verifywhere the platform has both (the Limine UKI callbacks otherwise), andluks-slotsbefore the staged key is destroyed. On x86 there's no new screen.omarchy updaterunsomarchy-update-boot(update-verify) after AUR packages.omarchy-update-bootresolves as the user first, so nothing asks for root where the platform has nothing to run. On a platform that implementsupdate-verifywithout passwordless sudo, that's one more prompt. If you'd rather verify inside the shared authorization before AUR, it's a one-line move, at the cost of not covering AUR rebuilds.limine-updateon every platform, as before.docs/lifecycle-dispatch.mdis the contract, including how a Qualcomm boot package would plug in.lifecycle-dispatch-test.sh,luks-rekey-journal-test.sh(the x86 path, and an Apple fixture with a fake boot package),drive-password-test.sh,factory-reset-dispatch-test.shandupdate-boot-verify-test.sh(inside the sudo boundary fixture: no root and no prompt on x86, generic aarch64 and Qualcomm).4. Migration caller (2 commits)
migrations/1790347292.shresolves the new optionalmigrateoperation and, when the platform's boot package implements it, runssudo omarchy-lifecycle-dispatch migrate. Macs installed before the official packages move onto them this way, insideomarchy-mac-boot. Everywhere else nothing resolves, so it completes without running anything or asking for root. An undetermined platform stays pending. A root-owned marker spares other accounts a second run. The filename matches the one Mac testers already run from omarchy-mac.EX_TEMPFAIL) is deferred: it changed nothing and can't finish yet, soomarchy-migrateleaves it pending with its login notification, runs the migrations after it and exits 0, andomarchy updatecarries on. Any other failure still stops the queue. Migration 1790347292 passes a deferred refusal from the platform's entrypoint through, and defers itself when the platform can't be told, so the update still reaches verification.platform-migration-test.sh, with a stub and with the real dispatcher on every platform fixture, andmigrate-deferred-test.sh.5. Pacman platform guard (1 commit)
groups=('omarchy-platform-<platform>'). On aarch64,omarchy-settingsships00-omarchy-platform-guard.hook, the guard script and a copy of the detector (/usr/share/libalpm/{hooks,scripts}/), so the guard is resident before the runtime or any platform package. Before each install or upgrade it reads tags from the synced databases and aborts a transaction that would install a package tagged for another platform. A transaction with no tagged package passes without asking the detector, and an unreadable database is reported and skipped, so it can't wedge pacman. No platform package is built for x86_64, and pacman refuses another architecture's package there anyway, so the x86_64omarchy-settingsships none of the three files (omarchy-settings: ship the full set on aarch64 for runtime-profile sources omarchy-pkgs#638 and Boot loop after update #691): x86 transactions run no hook and pay nothing. (Measured before that change, one guard run on x86 took about 0.36 s.)install/hardware/platform-guard.sh) checks the guard is resident and audits what the installer already placed. On generic aarch64 a missing guard is logged, not fatal; on x86 it is expected and says nothing.config-test.shchecks that.docs/platform-guard.mdis the contract.platform-guard-test.sh(fixtures for all four platforms, image builds, invalid manifests, a masked hook, and fresh-install ordering),config-test.shagainst omarchy-pkgs master, and on the x86 VM below.6. Generic fixes (3 commits)
/usr/lib/voxtype/voxtype-vulkanexists. aarch64voxtype-binhas none, so setup errored mid-install on Snapdragon and Macs. x86 is unchanged. Co-authored with @oliverlukschander (voxtype: require the Vulkan backend binary before enabling GPU omarchy-mac#483). It overlaps Enable Voxtype GPU backend through sudo #12901, Fix Voxtype GPU setup failing silently #7129 and Default dictation to verified Cohere Vulkan, paste and Atreyu visuals #13098 in the sameifblock; whichever lands second keeps both conditions./opt/WidevineCdm/chromiuminto Brave and Brave Origin, throughas_root, plus a migration. This only happens when thewidevinepackage is installed and the browser has no CDM of its own, so a standard x86 install is unchanged. Co-authored with @cajomar (Register the Widevine CDM for Brave omarchy-mac#474). Brave Origin's path is untried on hardware.run_loggedstep now also printsError: setup failed in <script> (exit code: N). See <log> for details.on stderr. Co-authored with @scottjones (Require Snapper for Mac installs and report setup failures omarchy-mac#389).voxtype-install-test.sh,brave-widevine-test.sh,logging-test.sh.7. Generic helpers from omarchy-mac (6 commits)
Helpers omarchy-mac grew for aarch64 that any machine can use, one commit each with its callers and tests. None of them adds an Apple branch.
omarchy-pkg-availablechecks the sync databases (onepacman -Slqper menu batch,pacman -Spfor a provided name or a constraint). Each Install row gets awhen:naming every package its install command adds, derived from the recipes, so a row with nothing to install on this architecture hides instead of failing mid-transaction. AUR-built browsers and NordVPN are guarded on the architectures their vendors ship.omarchy-reinstall-pkgsreports and skips a default no configured repository offers. All 47 package-guarded rows resolve against x86_64 stable and edge today, so the x86 menu is unchanged. While any configured repository has no sync database yet (a fresh ISO install has only its offline one until the first update), availability is unknown, so every row shows as before and reinstall skips nothing. Co-authored with @ryanrhughes.omarchy-hw-render-gpu,omarchy-cmd-electron-gl-args,omarchy-cmd-electron-gl-wrap(a marked/usr/local/binwrapper that adds--ozone-platform=wayland --disable-gpuonly while there is norenderD*node, refuses to replace a launcher it didn't write) andomarchy-cmd-desktop-exec-repair(points the user's desktop entry at the wrapper, keeping arguments and customizations). The 1Password installer uses them only where there is no render node (VMs, headless GPUs, Apple M3 and later). Co-authored with @scottjones.omarchy-capture-screenrecording-process, which matches by executable and signals through a pidfd, instead ofpgrep -f ^gpu-screen-recorder; the bar indicator and the Stop row use it too. The finalize pass pins 48 kHz (the same line as Pin recording audio sample rate at 48 kHz #11092; whichever lands second drops it). Co-authored with @scottjones and @ijt.USB(Apple Silicon's USB-C displays) and fuses DVI-A with Composite.omarchy-system-lid-inhibit, run by the monitor watcher, holds ahandle-lid-switchinhibitor while such a display is connected and enabled, whereHandleLidSwitchDockedis ignore. It changes nothing when Hyprland or logind doesn't answer, and it is bound to the watcher's unit.default/hypr/monitor-removal.luarefocuses the workspace you were on when its monitor is unplugged or the lid turns the panel off (Hyprland warps focus first and moves the workspaces after, so yours ended up hidden).ExecConditionmakes it a no-op without both. First run enables it, and migration 1789135842 enables it for existing installs. That migration keeps the name it has in omarchy-mac, so Macs that already ran it skip it; it sorts before newer migrations on purpose. Co-authored with @scottjones and @6abe.optional-availability-test.sh,optional-packages-test.sh,optional-transactions-{x86_64,aarch64}-test.sh,menu-guards-test.sh,menu-test.sh,platform-packages-test.sh,electron-gl-test.sh,install-1password-software-gl-test.sh,screenrecording-test.sh,screenrecording-process-test.sh,screenrecording-sample-rate-test.sh,lid-inhibit-test.sh,hyprland-monitor-removal-test.sh,brightness-keyboard-auto-test.sh,systemd-test.sh.8. Image builds and platform setup (3 commits)
Prebuilt images need what the ISO does at install time done on the machine instead, and a platform package needs one place to hook its own setup. Image-build deferral never runs on an ISO install; the setup seam runs on every install.
/var/lib/omarchy/image/target) exists,omarchy-apply-hardwarequeues every leaf ofinstall/hardware/all.shinstead of running it and armsomarchy-provision-hardware.service. On the first boot, before owner setup and the login screen,omarchy-provision-hardwareretires the manifest totarget.bootedand runs the queue on the real hardware. A failed step stays queued for the next boot (exit 75), and the initramfs is rebuilt once after the last step when a step changed the mkinitcpio configuration or the Limine command line, or asked for it. Bluetooth starts its service on that boot, since its target is already up.install/helpers/image-target.shholds the contract; root ignores any environment override of its paths. Nothing on that boot fetches package databases: an image carries its sync databases and every package its steps install, since a Mac has no network until the owner is on the desktop. Without a manifest, hardware setup runs exactly as before.LANG=C) never went through the ISO's locale step. The config phase selectsen_US.UTF-8only whenLANGis unset,CorPOSIX, and changes only that line. The ISO writes the locale first, so an ISO install is unchanged. Co-authored with @scottjones.setup-bootand thensetup-systemrun as root from the last hardware leaf, so an image build queues it and its first boot runs it (withimage-first-boot: possibly offline, and asking for the one rebuild instead of building).setup-userruns as the user being set up, refuses root and gets only a fixedPATH,HOME,USER,XDG_CONFIG_HOME,XDG_STATE_HOME,XDG_RUNTIME_DIR,DBUS_SESSION_BUS_ADDRESS,WAYLAND_DISPLAYandOMARCHY_PATH(the two XDG directories from section 9); it runs from the last user leaf at finalization (skipped inside an image build, where the detector would read the build host) and again as a first-run step once the session is up. On Apple Siliconsetup-bootresolves in/usr/lib/omarchy/mac-bootand is required: the Mac's boot setup (GRUB console, Limine activation) has no other path, so a boot package without it stops the leaf.setup-systemandsetup-userresolve in/usr/lib/omarchy/mac, shipped byomarchy-mac, and are optional. Every other platform registers none, so all three are no-ops.docs/lifecycle-dispatch.mdhas the contract. With it comes @scottjones's first-run fix: a failed finalization now keeps first run pending instead of letting the later steps mark it complete.image-deferred-hardware-test.sh(queueing, a first boot racing a rerun, refused manifests, replay after a failed step, one rebuild for mkinitcpio or Limine command-line changes or a request, no database fetch, Bluetooth, the keyring an image build defers to the first boot, root ignoring fixture roots),locale-setup-test.sh,lifecycle-dispatch-test.sh,platform-setup-test.sh(both leaves and first run through the real dispatcher,setup-bootbeforesetup-system, and a Mac whose boot package lacks it) andfirst-run-test.sh.9. Hardware without PC names, platform desktop defaults, quirks (6 commits)
omarchy-mac carried Apple Silicon lines in files Omarchy already has. Here detection becomes generic, Mac-only desktop defaults get generic places a platform package fills (so they live in omarchy-mac), and the PC and Intel Mac quirks that misfire on Apple Silicon skip it behind
omarchy-hw-apple-silicon, like the otheromarchy-hw-*predicates in hardware setup.BAT*name, and ignores a peripheral's battery (scopedDevice); battery status takes the first UPower battery that powers the machine, reads its own thresholds and cycles (BAT*stays the fallback), shows the magnitude of a signedpower_now, and rounds the percentage half-up like the bar while the charge-hold check keeps the raw value. A laptop is also one with any input device reporting a lid switch (SW_LID), whatever its name; whether the lid is closed comes from ACPI where there is an ACPI lid, and otherwise from logind (a 2 s timeout, since the check also runs inside sudo's PAM stack where fingerprint login is set up). A device named touchpad or trackpad wins; otherwise the touchpad is a mouse udev marks as a touchpad (Apple's multi-touch trackpad), and the backlight and external-monitor brightness follow a platform'sdisplays.conf(backlight nodes to skip or prefer, and whether an external monitor needs its connector's DDC channel), so Omarchy names no Mac devices; without the file they behave exactly as before. A Mac's file skips the Touch Bar nodes, prefersapple-panel-bland spares the 3-second DDC probe over the SoC's SMBus.XDG_CONFIG_HOMEandXDG_STATE_HOME. Section 8's user operations dropped them, so a platform's user setup looked in the default directories for a user who sets either./usr/share/omarchy-platform/, which the one installed platform package owns and Omarchy ships nothing into, read by literal path (no environment variable). Missing files mean no platform additions.hypr/defaults/*.lualoads before Omarchy's defaults: a chord bound there replaces Omarchy's default for it, and a decorator added too.bind_decoratorsruns before every later bind, so it can bind what must run first. A decorator sees the command a bind runs, including the one a shell shortcut such as{ menu = "root" }stands for when it binds the shell's global shortcut.hypr/settings/*.lualoads after Omarchy's defaults and before the theme and the user's files. A platform sets there throughhl.configanything a user might set globally, since Hyprland lets anhl.devicevalue win over the user's global one, and keepshl.devicefor what applies to that device alone.hypr/gestures/*.lualoads after the user's files, only for gestures: the gesture registry, which now records on every platform and knows every direction alias Hyprland accepts, lets a default gesture step aside for the user's own. The user's files can unbind or rebind anything set in the first two. Each platform file loads by path underpcall(never throughpackage.path, so it can't shadow a module), and a failing file or decorator is reported and skipped, so Omarchy's defaults and the user's files still load.key-namesin the platform root (<keysym> <name>lines) renames a key where the keyboard prints something else, in the key column only (a MacBook'sXF86MonBrightnessUpis F2). It is part of the menu cache's key. The menu's own config scan runslua -E, so nothing in the user's environment reaches it.display-cutouts.jsonin the platform root (connector, physical mode, rows covered). On a described panel a top bar is never shorter than the cutout, its center section sits beside the right one, and hiding it parks all of it;[bar] notch-heightsets the floor by hand on that panel only.fnmode=2for Apple-like keyboards is left to the Mac's platform package there. The SPI keyboard check survives a missing DMI product name. The Windows VM (an x86_64 KVM guest) and direct boot (U-Boot makes its own boot entries) refuse Apple Silicon and the menu hides both; hibernation setup skips it.battery-present-test.sh,battery-status-test.sh,hw-laptop-test.sh(lid capability words, a Mac mini's SMC device without a lid),hw-touchpad-test.sh,hw-display-test.sh,brightness-display-test.sh,lifecycle-dispatch-test.sh,hyprland-platform-defaults-test.sh(fixture platform files: early binds replacing a default in any spelling, a decorator's bind running first and not recursing, a decorator picking a global-shortcut menu bind by its command, the user's rebind and unbind winning, default bindings off, a late gesture stepping aside, the development-checkout path),menu-keybindings-key-names-test.sh(names in the key column only, never in what a row runs),bar-notch-test.sh,bar-test.sh,apple-silicon-quirks-test.sh,brcmfmac-supplicant-test.sh,spi-keyboard-test.sh,menu-test.sh. Every case says which platform it runs on, and tests never read a machine's installed platform files.10. Platform hooks for app installs and update takeovers (2 commits)
omarchy-mac's inline branches in installers and the update were Apple policy, so they move onto the dispatch seam from section 8 and into omarchy-mac.
post-install <app>andpre-remove <app>. Optional user operations, likesetup-user(refuse root, same session allowlist). Every browser install runspost-install <browser>after its flags file and before it says it's installed; Steam's install runspost-install steamafter the package, and its removal runspre-remove steambefore its packages go. On a Mac they resolve in/usr/lib/omarchy/mac(browser flags for software video decode, Steam's FEX launcher, which depends on Steam and so must go first). Everywhere else they are no-ops. Steam's 32-bit driver step also stops failing the install on a machine with no Intel, AMD or NVIDIA GPU.update-takeover <path>.... When an Omarchy package's upgrade stops only on files no package owns, the update asks the platform's boot package before moving them aside for the retry. It is resolved as the user and run withsudoonly where it resolves. It's required on Apple Silicon (omarchy-mac-boot): a Mac's boot chain and image write files no package owns, so a Mac whose boot package can't vouch for the takeover keeps them and the update stops as it did before the retry existed. Nothing resolves elsewhere, so the takeover goes ahead as before.platform-app-hooks-test.sh(every browser, Steam install and removal through the real dispatcher on Apple and x86 fixtures),lifecycle-dispatch-test.sh,update-file-conflict-test.sh(a vouched, a refused and an unanswered takeover on Apple; x86 asking no one).11. Mac package set (1 commit)
install/omarchy-apple-silicon.packages, whichomarchy-pkg-defaultsalready composes after the base and aarch64 lists:omarchy-macandomarchy-mac-boot(whose entrypoints the dispatcher requires on a Mac), plus defaults an owner may remove: the startup-volume tool, video decode, Widevine, andwf-recorder, sincegpu-screen-recordercan't capture on Apple Silicon (its display and GPU are separate DRM devices) and section 7's fallback records with it. What a Mac can't work without (its speaker stack, PipeWire's PulseAudio server and realtime scheduling, the Vulkan driver) comes asomarchy-mac's dependencies, so a new Mac driver needs no Omarchy change.platform-packages-test.sh.12. aarch64 repositories, keys and zram (3 commits)
omarchy-refresh-pacman(and soomarchy-channel-set) wrote the x86_64 templates everywhere, so on aarch64 it replaced Arch Linux ARM and a platform's repositories with Arch's x86 ones. It now asks the platform. x86_64 runs exactly the same copies as before. On aarch64 the machine'spacman.conf, mirrors and signature policies stay, and only the[omarchy]server moves to the new channel (dragon's approach); a configuration whose Omarchy server can't be identified is refused unchanged, and one with no Omarchy repository gets it at the end (except on Apple Silicon, whose own repository must not come first, or where an included file already defines it). Onlypacman.confis backed up and rewritten, piped from the command straight tosudo tee, never through a file another process could change.dragondoes; Apple Silicon takes none until the Mac packages qualify on edge, which is then a one-line change ininstall/helpers/pacman.sh. Before touching/etc, the refresh checks as the user that the channel'somarchy.dbpublishes the runtime pair, and on Apple Siliconomarchy-macandomarchy-mac-boot.omarchy-channel-setrefuses an unqualified channel before anything else, the dev confirmation included; the dev checkout is still linked before the refresh, as today, and on aarch64 a checkout from before this PR is refused. An unreadablepacman.confis refused, not taken for one with no Omarchy section.dragon'spacman-aarch64.confandmirrorlist-aarch64(byte for byte), with Arch Linux ARM's keyring installed and populated first (in an image build, on the machine's first boot, so machines flashed from one image don't share a pacman master key), plus Omarchy on a qualified channel, and a message saying why when the channel isn't qualified there. Such a machine also says so inomarchy update's confirmation,omarchy-refresh-pacmanandomarchy-channel-set, pointing toomarchy-channel-set edge. On aarch64,omarchy-reinstall-pkgsrefreshes on the channel the machine's configuration names, or keeps its repositories where that channel isn't qualified. Apple Silicon getsomarchy-mac's template (/usr/share/omarchy-mac/pacman) on a qualified channel and keeps its image's configuration otherwise.omarchy-update-keyringalso reinstallsarchlinuxarm-keyringon aarch64 platforms where it's installed, so a rotated ALARM key doesn't fail the upgrade after it. x86_64 is unchanged, even with that package installed.zram-generatorwhere the platform's default packages name it (aarch64 only; x86_64 gets it from its installer) and starts the zram swap when it's down, unless no device is configured or the unit is masked. A failed install defers it (75) to the next update; a swap that won't start only warns, since its unit starts on every boot, so it never stops an update. An undetermined platform defers it too. It keeps the name it has in omarchy-mac, so Macs that ran it skip it, and retires an/etccopy of the drop-in identical to the packaged one.pacman-arm-channel-test.sh(the gate per platform; keeping every repository, mirror, signature policy, look-alike server and trailing line; refusing unknown, included, duplicated or missing Omarchy servers; appending, but not on a Mac or through an include; each platform's finalization and that a channel change reads it; the preflight against a fixtureomarchy.db; the refresh through the sudo boundary fixture: refusals before anything else, the order check, backup, write, cold hook, upgrade, and a failed check changing nothing),channel-sudo-boundary-test.sh(unqualified channels refused before any change),update-keyring-test.sh,zram-aarch64-migration-test.sh. The Thunderboltmodinfoform is in section 1, tested bymkinitcpio-hooks-test.sh.13. omarchy-settings on every architecture (1 commit)
default/settings-runtime-profiletells the omarchy-settings recipe (omarchy-settings: ship the full set on aarch64 for runtime-profile sources omarchy-pkgs#638) that this source's platform files decide at runtime, so it can ship the same files on aarch64 instead of stripping the mkinitcpio, Limine, memory and USB drop-ins. It lists each file and what it decides from: the HOOKS baseline asks the platform, Thunderbolt the kernel (section 1), the Limine files are read only where Limine is installed, the oomd drop-ins are inert without systemd-oomd, aarch64 installs the zram generator the zram drop-in needs (section 12), and a kernel that buildsusbcorein ignores the USB autosuspend option. Older sources keep today's aarch64 package.settings-runtime-profile-test.sh(every listed file exists, and each runtime decision is in place),config-test.shagainst omarchy-pkgs master.14. Wireless regulatory domain at first-boot setup (1 commit)
install/hardware/set-wireless-regdom.shleft the regulatory domain unset. Owner setup now runs that step again once the owner's timezone is set, and applies it to the radios through wireless-regdb'sset-wireless-regdom, since no reboot follows setup. An up-front install is unchanged.provision-owner-regdom-test.sh.15. Keyboard layout at first-boot setup (1 commit)
loadkeysmust succeed, the keymap must be inlocalectl's list exactly, and aftersystemd-firstbootor thelocalectlfallback,/etc/vconsole.confis read back in a clean shell and must name the keymap with an XKB layout. A failure is logged, the owner is told, and the layout is asked for again; after three in a row the attempt fails and setup's retry-or-console screen takes over, so a machine that can't set any layout doesn't loop. The journaled re-key (section 2) now records a fingerprint of the layout lines and rebuilds the boot files when it changes, including after a completed re-key.provision-owner-keyboard-test.sh, andluks-rekey-journal-test.shfor the fingerprint.16. Platform keyrings (1 commit)
/usr/share/omarchy-platform/keyrings, one package name per line (asahi-alarm-keyringon Apple Silicon).omarchy-update-keyringreinstalls each one that is installed, in the same transaction as Arch's. It adds no repository the machine didn't already trust, and a line that isn't one keyring package name is skipped with a warning. Without the file, as on x86, nothing changes.update-keyring-test.sh.17. Untyped inputs in the audio panel (1 commit)
Audio/Source/Virtual: EasyEffects' source, or a platform's microphone mapping) had no volume, meter or mute in the shell. Such an input now goes throughwpctl(shell/Commons/UntypedInput.qml, onepactl subscribefor the whole shell), is metered by the newomarchy-audio-source-level, and is listed when PulseAudio lists it as a source./usr/share/omarchy-platform/audio.json(hidden, orreplacedwhile a replacement exists). The panel and microphone widget leave them out, except the current default. Omarchy ships none.audio-test.sh,audio-input-set-default-test.sh,audio-source-availability-test.sh,audio-source-level-test.sh.Testing
./test/allas a normal user in a native x86_64 Arch container (archlinux:base-devel, cryptsetup, omarchy-pkgs master checked out for the packaging checks), onquattroe1614f2 and on each of the first 20 commits: every commit fails the same 8 shell files and the sametest/clichecks asquattro, and nothing else. Those need an installed system, mise, an omarchy-iso checkout or namespaces the container lacks. Each commit's new tests pass at that commit.The last two commits (migration deferral, Apple HOOKS) against commit 20, with
./test/allas a normal user on an installed x86_64 Omarchy machine: all three fail the same 12 shell files and the sametest/clicheck, and each commit's new tests pass. The HOOKS commit's tests also pass natively on aarch64, as a normal user on an M1 Pro, where its shell suite fails no file that its parent passes.x86 VM (KVM, OVMF, ISO built from this branch with omarchy-iso, installed through the configurator): the ISO was built from an earlier state of this branch whose tree differs from the head only in
test/shell.d/mkinitcpio-hooks-test.sh.omarchy-hw-platformsaysgeneric, and every dispatch operation resolves to nothing. HOOKS compose from00-omarchy-hooks.confandmkinitcpio -Psucceeds.omarchy update -yasks for the sudo password once and finishes, with the boot checks running nothing.omarchy-drive-passwordmoves the disk, the login and root to the new password: the old one is refused and one key slot is left.omarchy-platform-apple-siliconwas refused ("This machine is generic") and an untagged one installed. With core, extra, multilib and the offline repository synced, one guard run takes about 0.36 s.cryptkey=left, and no recovery-key screen. Factory reset on that machine staged through the generic path (the passphrase check now ignores tokens), rebooted unattended into owner setup, re-keyed to one slot, and the next boot asked for the new password.Earlier, on the separate branches: the detector, image-manifest and package-list tests natively on aarch64 (an Arch Linux ARM container), as a normal user and as root.
The six helper commits (section 7):
./test/allas a normal user in a fresh x86_64 Arch container (archlinux:latestwith the test tools, no ripgrep, cryptsetup or omarchy-pkgs checkout, so more files fail for want of tools than in the runs above), on commit 22 and on each of the six: every commit fails exactly the same 26 shell files andtest/clicheck as commit 22 (all for missing tools: ripgrep, mise, gum, ssh-keygen, an omarchy-pkgs checkout, namespaces), and its own tests pass. Their Apple-relevant test files also passed natively on aarch64, as a normal user on an M2 Max where the render node, light sensor, keyboard LED and USB connectors the helpers look for are present, on the revision before the last review fixes. With that Mac's real sync databases the availability guards hide the 15 Install rows that have no aarch64 package there (RetroArch, Lutris, Heroic, Spotify and others), and each guarded row also resolved on x86_64 as above.The five commits of section 8:
./test/allas a normal user in a fresh x86_64 Arch container (archlinux:latestwith the test tools and cryptsetup, no mise, gum, ssh-keygen, namespaces or omarchy-pkgs checkout), on commit 28 and on each of the five: every commit fails exactly the same 25 shell files andtest/clicheck as commit 28, all for missing tools, and its own tests pass. Their Apple-relevant test files (16, the LUKS, dispatch, image and first-run ones included) also pass natively on aarch64, as a normal user on an M2 Max, at the last commit. Read-only on that Mac, the branch's dispatcher then resolved both setup operations to nothing (noomarchy-macentrypoints yet); section 8's requiredsetup-bootnow needs anomarchy-mac-bootthat ships it (omarchy-mac has it since Run the Mac's boot setup through the platform setup seam omarchy-mac#635).The eight commits of sections 9 and 10:
./test/allas a normal user in the same x86_64 Arch container as section 8, on commit 33 and on each of the eight: every commit fails exactly the same 25 shell files andtest/clicheck as commit 33, all for missing tools, and its own tests pass. Their Apple-relevant test files (38) also pass natively on aarch64, as a normal user on an M2 Max that has omarchy-mac's current files installed. Read-only on that Mac, the branch finds the laptop, lid, battery,apple-panel-blandapple-mtp-multi-touch, gives its 16" panel a 32 px floor with the cutout file omarchy-mac is to ship (none without it), and resolvespost-installandpre-removeto nothing (noomarchy-macentrypoints yet) andupdate-takeoverto an error naming theomarchy-mac-bootupdate it needs.The seven commits sections 11 to 13 had then (setup-boot and Thunderbolt have since moved into sections 8 and 1):
./test/allas a normal user in the same x86_64 Arch container, on commit 41 and on each of the seven: every commit fails exactly the same 25 shell files andtest/clicheck as commit 41, all for missing tools, and its own tests pass. Their Apple-relevant test files (19, the dispatch, image, LUKS, HOOKS, channel and sudo-boundary ones included, plusconfig-test.shagainst omarchy-pkgs master) also pass natively on aarch64, as a normal user on an M2 Max. Read-only on that Mac, the branch places it onapple-silicon, refuses every channel for it, would leave itspacman.confbyte for byte on edge and change only the Omarchy server on rc, finds edge'somarchy.dbpublishing the runtime pair and both Mac packages, liststhunderboltfor its kernel, and resolvessetup-bootto an error naming theomarchy-mac-bootupdate it needs.This revision (after review: timezone toast dropped,
update-preflightandboot-rebuildremoved,setup-bootand the Thunderboltmodinfoform folded into sections 8 and 1, guard silent on x86): the runs above predate it, and the section 8 counts there are from when it had five commits. At the new head, every shell test file andtest/cliin an Arch container as a normal user: every file that fails at the head also fails at the previous head (7fabb9b) there, all for the container (no omarchy-pkgs checkout, namespaces, an installed system);system-sleep-ownership-migration-test.shand onetest/clitheme check fail intermittently at both. Each of the commits then in the PR passes the test files it adds or changes, apart from those same container failures.Round 2 (the disk recovery key dropped to match Omarchy's single password, and the second review's fixes folded into their commits): at the new head, every shell test file in an Arch container as a normal user fails only where the previous head (39a9909) fails there, and passes two fewer files, the two recovery-key tests that went with the feature. Each of the 44 commits passes the test files it adds or changes, apart from those container failures, with the root probes run under
unshare. On an M2 Max, the touchpad and lid fixes were checked live, and so was what the notch fix reads (Quickshell's whole-number ratio and Hyprland's 3456x2234 mode); a fractional scale itself couldn't be set there.Round 3 (the third review's fixes folded into their commits, plus the wireless regulatory domain at first-boot setup as a new commit): at the new head every shell test file in an Arch container fails only where the previous head fails there, and each of the 45 commits passes the test files it adds or changes. The fresh-install menu case runs real pacman on a root holding only
offline.db.Round 4 (the keyboard layout at first-boot setup, platform keyrings and untyped audio inputs, sections 15 to 17): at the new head every shell test file in an Arch container fails only where the round-3 head fails there, and each of the 48 commits passes the test files it adds or changes, apart from those container failures.
End to end at f22c43f (this head), x86: a fresh encrypted ISO install in a VM with a UK layout. The UK keymap is in the boot image, and a password with
@unlocks on the first try. One key slot, platformgeneric, every dispatch operation resolves to nothing,omarchy updategives no keyring warnings,omarchy-drive-passwordand the reboot unlock work, and all 47 Install rows show. In the audio panel an empty-jack input is hidden unless it's the default, a filter's capture stays put when choosing an input, the shell's meters don't light the microphone widget while a realpw-recorddoes, and a virtual default input shows and sets its real volume with a moving meter. The in-guest suite fails only its known files.End to end at f22c43f, Apple Silicon: a lab image with omarchy-mac 0.1.0-10 and omarchy-mac-boot 20260928-3 passes all eight VM scenarios on an M1 Pro.
audio.jsonis in the image andomarchy updaterefreshesasahi-alarm-keyring. The M2 Max hardware install below is from the round-3 head.End to end at df41281 (the round-3 head), x86: a fresh encrypted ISO install and a provisioned one in a VM. At first login, before any update or
pacman -Sy,/var/lib/pacman/syncholds onlyoffline.db, and all 47 guarded Install rows show, none hidden. The platform isgenericand every dispatch operation resolves to nothing. Owner setup leaves one key slot.omarchy-drive-passwordfinds the disk right after boot with the rootblkidcache empty, the regulatory domain follows the timezone,omarchy updateexits 0 with no failed units, and the in-guest suite fails only its 17 known files.End to end at df41281, Apple Silicon: a lab image from this runtime with omarchy-mac 0.1.0-9 and omarchy-mac-boot 20260928-2 passes all seven VM acceptance scenarios on an M1 Pro (first boot, conversion, second boot, password change, update, snapshot restore, factory reset) and an offline first boot, with no failures. The two skips are the audio sink, since a VM has no Apple audio, and the restore itself, which the generic kernel refuses; the snapshot entry boots. The owner-only disk (one key slot) holds through conversion and factory reset, the password change works on the first try, and the regulatory domain follows the timezone.
End to end at df41281, Apple Silicon hardware: a full install on an M2 Max with omarchy-mac 0.1.0-9, omarchy-mac-boot 20260928-2 and the Aurora boot chain, through the installer app: remove the previous Omarchy (macOS gets all its space back and is the startup disk again), install on edge with encryption, Recovery handoff, first boot and first login. Lab acceptance passes 42 of 42 with no warnings: Limine in U-Boot's slot, a LUKS2 root with one key slot (the owner's) and no recovery key or boot-time key left, the regulatory domain set, and the expected services active.
End to end at b0d870c (the round-2 head): an x86 ISO install in a VM passes. An Apple Silicon lab image built from this runtime passes its VM scenarios (first boot, conversion to an owner-only key slot, second boot) apart from the drive listing and the regulatory domain, both fixed in round 3. The Mac hardware install is still to run on this head.
Risk and rollback
sudoinstall; the boot, system and user setup operations; the update's boot check; migration 1790347292; the 1Password wrapper with a render node; the recording fallback where gpu-screen-recorder works; the lid inhibitor without USB, DVI-A or Composite displays; image-build deferral without an image manifest; the locale step after the ISO wrote one; in sections 9 to 12 every Apple Silicon and aarch64 guard, the platform directories and files (empty or absent without a platform package), the two app hooks and the takeover check) or read-only (the menu guards). The platform guard isn't installed on x86.dragon: a configuration without an[omarchy]section gets one appended instead of being refused, and a refresh fetches the channel'somarchy.dbas the user first. Compared with this PR's base, Snapdragon refreshes stop writing x86 repositories, and finalization, the keyring and zram follow section 12.omarchy-mac-boot20260928-2 or later, withsetup-boot,update-takeoverandluks-slots --owner(exit 4 when no owner slot is recorded), andomarchy-mac0.1.0-9 or later (the hardware stack as dependencies,vulkan-asahiincluded, and its files under/usr/share/omarchy-platform), publish with, or before, this runtime. Otherwise a Mac stops its hardware leaf and refuses every takeover, a new Mac image has no Vulkan driver, and a Mac loses its platform files.omarchy-mac0.1.0-10 adds thekeyringsandaudio.jsonfiles; before it, updates don't refreshasahi-alarm-keyringand the audio panel has no hints for the Mac's processing nodes.etc/mkinitcpio.conf.d/00-omarchy-hooks.confto omarchy-settings'backuplist, next toomarchy_hooks.conf, and install the platform guard's three files only whenCARCHisaarch64(follow-up PR linked in the comments). For Fix: restrict Steam centering to only the main window #380:omarchy_hooks.confno longer has a top-levelHOOKS=line here, so its asahi guard should apply only to the old layout, and this layout ships unchanged.What stays in omarchy-mac
The Apple entrypoints (
omarchy-mac-boot: boot chain, boot-partition key, key-slot records, the migration from older Mac setups,update-takeover,setup-boot;omarchy-mac:setup-system,setup-user,post-installandpre-remove, and its Hyprland defaults, key names, cutout file and display hints under/usr/share/omarchy-platform), theomarchy-machardware package, the Apple package tags, the Asahi repositories and the pacman templates finalization reads fromomarchy-mac, the Apple initramfs drop-ins, the Mac installer and image builder, and Mac-only migrations. None of it is needed on other hardware. The Apple-aware lines here are the detector'sapple-siliconanswer,omarchy-hw-apple-silicon, the dispatcher's two registrations (boot operations toomarchy-mac-boot, setup and app hooks toomarchy-mac), the HOOKS baseline's Apple line, the Apple package list, the Apple row of the channel gate (none yet) with the path ofomarchy-mac's pacman templates, and section 9's hardware facts: comments naming the Mac devices generic detection now covers, and the quirks and two menu rowsomarchy-hw-apple-silicongates. The Mac's own binds, gestures, key names, notch sizes and backlight choices are omarchy-mac's files under the platform root. Repairs for Macs set up before this (their locale) stay in omarchy-mac too.For the Dragon maintainers
The detector's
qualcommanswer followsdragon: @JimmayVV'sqcom,device-tree check and @birkskyum's Snapdragon detection. Both co-author the detector and guard commits. You decide what counts as a Qualcomm machine, so push back on anything here.qualcommuses the same evidence asomarchy-hw-qualcomm-soc(aqcom,token in the boot device tree), and the fixtures check that the two agree. They differ only on contradictory evidence, where the detector fails. Once both land,omarchy-hw-qualcomm-soccan become[[ $(omarchy-hw-platform) == "qualcomm" ]].qualcommregisters no dispatch entrypoints, so Snapdragon machines take today's paths.dragon's keep-and-swap refresh and ARM finalization, behind the detector instead ofuname -m. Mergingdragon: keep this PR'sbin/omarchy-refresh-pacman,install/helpers/pacman.shandinstall/post-install/pacman.sh(they stay inside the hardened sudo boundary, and the lint has nothing to review there);default/pacman/pacman-aarch64.confandmirrorlist-aarch64are identical;refresh-pacman-arm-test.shandpacman-aarch64-test.shtest the old interface, andpacman-arm-channel-test.shreplaces them.install/user/mise-work.shstill needs an entry in the lint's reviewed list.thunderbolt_module.confconflicts: keep this PR'smodinfoform.dragon's refresh, for you to accept or push back on: a configuration with no[omarchy]section gets one appended instead of being refused (a stable install finalized bydragonhas none, so it could never move to edge), and the refresh first checks, as the user, that the channel'somarchy.dbpublishes the runtime pair.omarchy-qualcomm.packagesis a first cut (onlylinux-firmware-qcom, whichdragon's hardware setup already installs), and Qualcomm packages can adopt the guard tag whenever you like.Review of round 4: no blocker. It asked for the keyring change to be its own commit, for the keyboard step to hand over to setup's retry-or-console screen instead of asking forever (both done, with a test), and for the docs to say a hidden audio node still shows while it's the default (done). Second review of round 2: no blocker; two doc wordings tightened. Earlier rounds: no blocker. It confirmed that verify after AUR never reuses a timestamp, and asked for a revocation right after AUR (added) and for the guard's per-transaction cost to be stated (above). For section 8: no blocker. It asked for the recovery-key reset (since removed) to be documented in
docs/lifecycle-dispatch.md(added), and for root to ignore the locale step's and the reset's path overrides (done); a design review before that had the deferred rebuild also watch the Limine command line, the reset (since removed) refuse snapshot roots when started by hand, and the locale step keepLC_*lines (all done, with tests). For sections 9 and 10: no blocker, one test cleanup fixed. Design reviews before that had lid detection go by the lid switch capability (a Mac mini has the SMC device without a lid), the platform binds load before Omarchy's defaults so they can replace a default and run before a menu bind, key names apply to the key column only, decorators not recurse, the cutout calibration stay off other screens, a hidden bar park by its full height, Steam's removal get its own hook, and the takeover check added instead of dropping the Mac's protection (all done, with tests). For sections 11 to 13: no blocker; it asked for a clearer refusal when a Mac has no Omarchy repository, keyring setup kept off a Mac's finalization, and a doc row (all done). Design reviews before that kept Apple Silicon off every channel until its packages qualify, replaced a rootpacmansync into a user-writable directory with a user-level package-list check and a configuration written straight throughsudo, made the zram migration retry a swap that doesn't start, and kept Arch Linux ARM's keyring off x86 (all done, with tests).Credits
This brings upstream work that started in omacom/omarchy-mac:
modinfocheck, which the Thunderbolt commit carries. He also first diagnosedomarchy_hooks.confoverwriting platform hooks, which the HOOKS commits fix another way.aarch64in omarchy-mac (Detect architecture so x86 stays upstream and aarch64 stays Mac omarchy-mac#331, Separate platform detection and pin Mac package builds omarchy-mac#353), which the detector's approach follows.qcom,device-tree check indragon'somarchy-hw-qualcomm-soc, the evidence the detector'squalcommanswer uses; co-author of the detector and guard.dragon's Snapdragon detection, which definesqualcommfor the detector and the platform guard.pacman -Spand keeping the AUR browsers on x86_64.dragon's keep-and-swap pacman refresh and ARM finalization, which section 12 carries.Their commits carry
Co-authored-bytrailers where their code or fix is in this PR.