5f25ef1da81619d7aebbf297ef37ae9d9a2dba2f
370
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
+12 |
e1b0e5e9bb |
Converge omarchy-mac and omarchy-mx-mac into upstream Omarchy (#14431)
* Add omarchy-hw-platform to tell Apple Silicon and Qualcomm machines apart
aarch64 covers Apple Silicon Macs, Snapdragon laptops, Raspberry Pis and
VMs, so the CPU architecture can't pick platform setup. omarchy-hw-platform
prints apple-silicon, qualcomm, generic-aarch64 or generic from the vendor
prefixes in the device tree's root compatible (/proc/device-tree, then
/sys/firmware/devicetree/base) and the CPU, and fails when they contradict
each other. Its qualcomm answer uses the same evidence as the dragon
branch's omarchy-hw-qualcomm-soc, and the fixtures check the two agree.
omarchy-hw-apple-silicon is the Apple predicate on top of it.
An image built away from its hardware names its target in a root-owned
manifest, /var/lib/omarchy/image/target (format=1, platform=). While the
root is being built rather than booted, the detector answers from it and
never reads the build host's device tree; a booted system always answers
from its hardware. As root it restarts in an empty environment, so no
variable picks the platform for privileged setup.
Co-authored-by: Birk Skyum <74932975+birkskyum@users.noreply.github.com>
Co-authored-by: Jimmy Van Veen <8206925+JimmayVV@users.noreply.github.com>
* Reject platform gates keyed only on the CPU architecture
An architecture check is right for an ABI, a binary or a repository's
$arch, not for picking a platform. The lint lists each shipped check after
review and fails on a new one, so platform setup goes through
omarchy-hw-platform.
* Compose default packages from base, architecture and platform lists
omarchy-reinstall-pkgs installed the base list on every machine. A
platform's default set is now the base list, then install/omarchy-aarch64.packages
on aarch64, then the platform's own list when it has one
(install/omarchy-qualcomm.packages adds linux-firmware-qcom).
omarchy-pkg-defaults prints the set for the detected platform, or for the
one named, and reinstall installs it. x86_64 still gets exactly the base
list, and an image build gets its target's set.
* Early-load thunderbolt only where the kernel builds the module
linux-aarch64 has no thunderbolt module, and mkinitcpio fails the whole
image over a MODULES entry it cannot find. The optional form, thunderbolt?,
is not enough: a systemd initramfs copies MODULES as written into
modules-load.d, where "thunderbolt?" names no module, and a kernel without
the module would still list it there. thunderbolt_module.conf now adds plain
thunderbolt only when modinfo finds it as a module for the kernel being
built.
Co-authored-by: Scott Jones <444693+scottjones@users.noreply.github.com>
* Compose mkinitcpio HOOKS from an early baseline drop-in
omarchy_hooks.conf assigned HOOKS outright, and mkinitcpio sources drop-ins in
name order, so it ran after any numbered drop-in (90-*.conf) and threw its
hooks away. HOOKS now comes from 00-omarchy-hooks.conf, which sorts first, and
later drop-ins add to it. The NVIDIA kms filter and the vconsole handling stay
in omarchy_hooks.conf. With the drop-ins Omarchy writes, machines keep the
same HOOKS, MODULES and FILES; a user drop-in that sets HOOKS and sorts before
omarchy_hooks.conf now takes effect instead of being overwritten.
Migration 1786605598 now sources the baseline first, since without it the
migration would read empty HOOKS and also rebuild hybrid systems. It skips a
machine that lacks the baseline.
* Resolve the LUKS parent from raw lsblk output
lsblk -s prints the ancestor tree with box-drawing prefixes ("└─/dev/nvme0n1p6"), so the crypto_LUKS parent came back as a path that does not exist and first-boot setup stopped with "Could not locate the LUKS device to re-key". -r prints raw names. Factory reset uses the same lookup.
* Check the factory-reset passphrase against keyslots only
cryptsetup open tries enrolled tokens before the key file, so a TPM2 or
FIDO2 token could authorize the re-key with a wrong passphrase.
* Test LUKS parent lookup during owner setup and factory reset
Exercise raw ancestry output without invoking provisioning or reset. Cover btrfs subvolume roots, absent encryption, failed probes, and explicit cryptdevice specifications.
* Cover LUKS parent lookup through an LVM volume group
* Journal the first-boot LUKS re-key so an interrupted attempt resumes
A first boot killed after the staged install key's slot was retired left the
key file behind, and every retry then stopped at "the staged LUKS key no
longer unlocks". A lost key file with the boot-time auto-unlock still
configured let setup finish with the disk unlocking unattended.
The re-key now runs from install/provisioning/luks-rekey.sh and records its
phase and slot numbers (never key material) in
/var/lib/omarchy/provisioning/luks-rekey.state. It reuses the owner's slot
instead of adding a duplicate, retires LUKS1 slots too, and destroys the
staged key only after the volume proves it opens nothing. Setup refuses to
finish while any part of the provisioning unlock remains. The journal ends at
phase=done and leaves together with pending, so a retry after the staged key
is retired must use the password the disk already holds.
Key checks exclude LUKS2 tokens: cryptsetup open tries an enrolled token
(say a TPM2 slot a previous owner left behind) before the key and reports its
slot whatever key it was given. Slot listings read only the keyslot section,
since a luks2-keyring token looks like a keyslot in luksDump.
* Change the root volume's LUKS key before the login and root passwords
Installation gives the login user, root and the disk holding / one password,
but omarchy-drive-password changed only the LUKS key, so the three drifted
apart. For the disk holding / it now checks the current password opens the
disk, changes the LUKS key, confirms the new key opens the disk and the old
one no longer does, and only then sets the login and root passwords. Any other
encrypted drive changes its LUKS key alone. Every drive now asks for the
current password with gum instead of cryptsetup's prompt.
A journal in ~/.local/state/omarchy/drive-password.state (disk UUID, key slots
and phase, never a password, written with the re-key journal helpers) lets the
next run finish an interrupted change. The rerun accepts only the old key
(removing the slot the interrupted change added) or the new one (retiring the
old slot), so another key such as a recovery passphrase never becomes the login
password. luksChangeKey is judged by whether the new key opens the disk, not
by its exit status, and key checks exclude LUKS2 tokens, which cryptsetup
open would otherwise accept in place of any password.
Runs are serialised, cryptsetup calls hold a disk lock, a / whose LUKS
partition cannot be resolved fails closed, and passwords are never traced. A
new password equal to the current one is refused, and --pbkdf argon2id is
passed only to LUKS2, so LUKS1 drives can change their password again.
* Add omarchy-lifecycle-dispatch for platform boot operations
Provisioning, factory reset and update call a fixed set of operations
through it. A platform whose boot chain the generic Limine path can't drive
registers a directory of root-owned entrypoints in the dispatcher; every
other platform gets a no-op and keeps its generic path. Apple Silicon is
registered to omarchy-mac-boot's /usr/lib/omarchy/mac-boot, with its
required operations failing clearly when the package or an entrypoint is
missing. docs/lifecycle-dispatch.md is the contract, including how a
Qualcomm boot package would plug in.
* Let the platform's boot package own first-boot setup's boot chain and key slots
Owner provisioning asks provision-prepare before the owner form, hands the
staged unlock to provision-commit and provision-verify where the platform
implements both, and records the kept LUKS slot through luks-slots before
the staged key is destroyed; the disk password change records the owner's
new slot the same way. On x86, Snapdragon and generic aarch64 every call is
a no-op and first boot is unchanged.
* Reset through the platform's boot package where it owns the boot chain
Where a platform implements the reset operations, reset-prepare and
reset-verify stage and prove the factory root's boot files, the throwaway
slot is added only after that, and reset-commit gets the key on standard
input once the factory root is active. A failure before the switch rolls the
boot state back and revokes the slot. Elsewhere the Limine UKI path is
unchanged.
* Check the platform's boot chain after an update
omarchy-update-boot runs update-verify after AUR packages, the last
sudo-capable step, so it also covers the initramfs rebuilds they trigger.
It follows third-party build code, so like AUR it authenticates through the
no-update wrapper. A failed verification finishes the update's remaining
steps, then exits non-zero without offering the reboot. Where the platform
does not implement it nothing runs and nothing asks for root.
* Hand a machine to its platform's migration through lifecycle dispatch
migrations/1790347292.sh resolves the new optional migrate operation and,
where the platform's boot package implements it, runs it as root. The
entrypoint moves the machine onto the platform's official package set,
idempotently and resumably; its failure leaves the migration pending. Once
it succeeds, a root-owned marker spares other accounts the migration and its
root prompt. Everywhere else, Macs without the boot package included, the
migration is a no-op, and an undetermined platform keeps it pending.
* Refuse packages tagged for another platform in a pacman hook
A platform package names its platform with groups=('omarchy-platform-<name>'),
<name> being what omarchy-hw-platform prints. omarchy-settings ships a
pre-transaction hook, the guard it runs and a copy of the detector, so the
guard is resident before the runtime and any platform package. The guard
reads tags from the synced databases and refuses a transaction that installs
a package tagged for another platform; a transaction without a tagged
package passes without asking which machine this is. Image builds answer
from the image's root-owned target manifest, as the detector does.
The guard ships on aarch64 only: no platform package is built for x86_64,
so x86 transactions run no hook. Hardware setup starts by proving the guard
is resident and checking the packages an installer placed without it. On
generic aarch64, where no platform packages exist, a missing guard is
logged, not fatal, and on x86 it is expected.
docs/platform-guard.md is the contract.
Co-authored-by: Birk Skyum <74932975+birkskyum@users.noreply.github.com>
Co-authored-by: Jimmy Van Veen <8206925+JimmayVV@users.noreply.github.com>
* Enable Voxtype's Vulkan backend only when it is installed
omarchy-hw-vulkan reports a Vulkan runtime, not whether this voxtype build
has a Vulkan backend. The aarch64 voxtype-bin package ships only the CPU and
ONNX binaries, so on any aarch64 machine with a Vulkan driver setup ran
`voxtype setup gpu --enable` and printed "Vulkan backend not installed" in
the middle of an otherwise working install. Require the backend binary too.
x86_64 voxtype-bin always ships /usr/lib/voxtype/voxtype-vulkan, so x86
installs still switch to the GPU backend as before.
Ported from omacom/omarchy-mac#483.
Co-authored-by: Oliver Lukschander <33756270+oliverlukschander@users.noreply.github.com>
* Link the system Widevine CDM into Brave
The widevine package registers its CDM for Chromium and Firefox only.
Brave looks for the CDM in its own install directory, finds nothing, and
DRM sites (Netflix, Apple TV+, Spotify) fail with a blank player and no
useful error. This hits machines where Widevine comes from that package,
such as aarch64 ones, since no Widevine component is published for them.
Link /opt/WidevineCdm/chromium into /opt/brave-bin and /opt/brave-origin-bin
through as_root when Brave or Brave Origin is installed, and add a migration
that repairs existing installs. Both do nothing when the widevine package is
absent or the browser already has a CDM. A standard x86 install has no
widevine package, so nothing changes there.
Ported from omacom/omarchy-mac#474, extended to Brave Origin.
Co-authored-by: Caleb Marshall <68087341+cajomar@users.noreply.github.com>
* Report failed setup steps on the console
With file logging, run_logged sends a failing leaf's output and its
"Failed:" marker to the install log only, so the caller sees setup stop
with an exit status and nothing else. A missing command (exit 127) was the
case that made this hard to diagnose.
Print the failed script, its exit status and the log path on stderr. Stdout
logging mode already shows the failure marker and is unchanged, and
successful steps stay quiet.
Ported from omacom/omarchy-mac#389 (the logging part).
Co-authored-by: Scott Jones <444693+scottjones@users.noreply.github.com>
* Let a migration defer itself without stopping the update
A migration that exits 75 changed nothing and cannot finish yet: omarchy-migrate
leaves it pending with its login notification, runs the migrations after it and
exits 0, so omarchy update carries on. Any other failure still stops the queue.
The platform migration passes a deferred refusal of its entrypoint through, and
defers itself where the dispatcher can't resolve its entrypoint (the platform
can't be told, or the entrypoint isn't trusted): nothing has run then, so the
update goes on to its boot verification, which fails there, as documented.
* Keep Apple Silicon's systemd initramfs on the HOOKS baseline
00-omarchy-hooks.conf set the busybox line on every machine. On a Mac,
omarchy-mac-boot's drop-ins then add the Asahi firmware hooks, but its
encryption drop-in reads busybox encrypt as a Mac unlocked through
cryptdevice= and leaves the line alone. The image came out as
"... block encrypt asahi omarchy-vendorfw filesystems ...", with no
systemd, sd-encrypt or omarchy-mac-encrypt, so an encrypted Mac could not
unlock its disk. Reproduced against an M1 Pro's installed drop-ins.
The baseline now asks omarchy-hw-platform. Apple Silicon starts from the
systemd line its boot package builds on. A Mac whose own mkinitcpio.conf
carries the asahi hook, or busybox encrypt, keeps that line, as a legacy
install needs. x86, Snapdragon and generic aarch64 keep today's busybox
line, as does a machine with no detector. The detector is the runtime's,
or else the copy omarchy-settings ships for its platform guard, so a
settings package newer than the runtime still places a Mac. A detector
that cannot place the machine stops the build.
The HOOKS test now composes the baseline on each platform and on legacy
Mac lines. A new test composes it with omarchy-mac-boot 20260926-1.45's
drop-ins, kept as fixtures, and checks the exact HOOKS the M1 Pro builds.
The NVIDIA test pins its platform.
* Hide optional installs that have no package on this machine
Not every optional install exists on every architecture: some vendors ship no
aarch64 build, and some repositories don't carry a package at all. Each
Install row now carries a `when:` guard naming every package its install
command adds, checked with omarchy-pkg-available, so a row with nothing to
install disappears instead of failing halfway through a pacman transaction.
The rows that build from the AUR (Chrome, Edge, Brave, Brave Origin, Zen,
NordVPN) are guarded on the CPU architectures their vendors publish for.
omarchy-pkg-available asks the sync databases: one `pacman -Slq` per batch,
and `pacman -Sp` for a name that list doesn't hold, so a provided name
(libappindicator-gtk3) and a version constraint resolve the way `pacman -S`
will. The menu's guard prelude sources the same function, so the whole batch
still costs one fork. omarchy-reinstall-pkgs reports and skips a default
that no configured repository offers instead of failing the transaction.
On x86_64 every guarded row resolves against the stable and edge
repositories, so the menu is unchanged there.
Tests derive each row's packages from its install command on x86_64 and
aarch64 and fail when the guard names different ones.
Co-authored-by: Ryan Hughes <1630358+ryanrhughes@users.noreply.github.com>
* Run 1Password with software GL where there is no render GPU
Electron draws a blank window when the machine has no DRM render node: a VM,
a headless or passthrough GPU, or a GPU whose driver isn't up yet (Apple M3
and later on Linux today). omarchy-hw-render-gpu tells whether a renderD node
exists, and omarchy-cmd-electron-gl-args prints --ozone-platform=wayland
--disable-gpu only when it doesn't.
omarchy-cmd-electron-gl-wrap installs a marked PATH wrapper in /usr/local/bin
that execs the real binary with those flags, so it follows the machine rather
than the moment it was installed. It refuses to replace a launcher it didn't
write, or to wrap a binary over itself, and stages the write so a failure
leaves the old launcher in place. omarchy-cmd-desktop-exec-repair points the
user's desktop entry at the wrapper by replacing only the executable token,
keeping arguments, other actions and customizations, with a backup.
The 1Password installer uses them when the machine has no render node. With
one, which is every x86 machine with a working GPU, nothing changes.
Co-authored-by: Scott Jones <444693+scottjones@users.noreply.github.com>
* Record with wf-recorder when gpu-screen-recorder can't start
gpu-screen-recorder knows NVIDIA, AMD, Intel and Broadcom GPUs and aborts
during GL init on anything else, such as Apple Silicon's, before a recording
starts. Screen recording now falls back to wf-recorder, when it is installed,
if gpu-screen-recorder is missing or exits before the file appears. The
picker, file naming, notifications and post-processing are shared. wf-recorder
records one audio device, so desktop plus microphone go through a temporary
null sink that stop unloads, and its track is pinned to 48 kHz. Portal
capture and --resolution stay gpu-screen-recorder only.
The finalize pass keeps 48 kHz too: loudnorm declares 192 kHz output, so
without -ar the AAC encoder wrote 96 kHz from a 48 kHz recording, which many
editors decode as silence, and which on Apple Silicon makes the speaker
safety daemon lock the amps. #11092 makes the same one-line change; whichever
lands second drops it.
Stop and status matched `pgrep -f ^gpu-screen-recorder`, which misses
wf-recorder and matches any command line that starts with that path. The
script now records the recorder's pid, and the new
omarchy-capture-screenrecording-process checks or signals it by its
executable, through a pidfd opened before the check so a reused pid can't be
signalled. When that pid is no longer a recorder (a recording started before
this change, or one that died), every recorder the user runs counts, as it
does for the bar indicator and the Stop row, which use the same helper.
Where gpu-screen-recorder works, which is every x86 GPU it supports today, it
records as before.
Co-authored-by: Scott Jones <444693+scottjones@users.noreply.github.com>
Co-authored-by: Issac Trotts <15530+ijt@users.noreply.github.com>
* Hold logind's lid switch while a display it doesn't count is in use
systemd-logind treats a closed lid as docked only when an external display
is on a connector type it lists (HDMI, DisplayPort, DVI, VGA...). Displays on
"USB" connectors, which Apple Silicon uses for USB-C displays, aren't on that
list, and a missing comma fuses DVI-A and Composite into one entry. With such
a display in use, closing the lid suspended a laptop that was still being
used on it.
omarchy-system-lid-inhibit holds a handle-lid-switch inhibitor while one of
those connectors is connected and enabled in Hyprland, on a laptop where
HandleLidSwitchDocked is ignore, which is exactly the case logind would have
ignored had it counted the display. It releases the inhibitor when the display
goes. A compositor or logind that doesn't answer changes nothing, since
releasing then would suspend a closed lid. The inhibitor runs as a transient
user unit bound to the monitor watcher's unit, so a watcher that dies can't
leave the lid inhibited until logout.
The monitor watcher runs it alongside the clamshell sync. On a machine whose
external displays are all on connectors logind counts, it does nothing.
* Keep the focused workspace in front when a monitor goes away
When a monitor is unplugged, or the lid turns off the laptop panel, Hyprland
first warps focus to whichever monitor it lists first and only then moves the
removed monitor's workspaces over. The workspace you were on lands hidden
behind that monitor's own (Hyprland 0.56.2, CMonitor::onDisconnect).
monitor.focused fires before Hyprland records the new focus, so the monitor
still reported as active is the one being left: its workspace is remembered
until the event loop next turns, and a monitor.removed in that window focuses
it again once the removal has finished. An open special workspace already
comes along, and any focus or workspace change made before the restore runs
wins.
* Drive the keyboard backlight from the ambient light sensor
Laptops with an ambient light sensor and a keyboard backlight LED now light
the keys in the dark and dim them as the room brightens, inverse to display
auto-brightness. omarchy-brightness-keyboard-auto polls the sensor every five
seconds (preferring an IIO device that names itself ALS, and converting a raw
channel with its offset and scale) and maps lux onto the LED, with a deadband
so it doesn't chase noise. It pauses while the screen is locked or the lid is
closed.
A level set with the keyboard-brightness keys wins until the light changes
enough that it no longer fits. omarchy-brightness-keyboard records each level
it sets in the session's runtime directory (a private state directory without
one), so the loop can tell keys turned off on purpose from keys left off by
the lock screen or a restored zero, which it lights again.
The user unit runs it in the graphical session. Its ExecCondition asks
--available, so it is a no-op on machines without both a sensor and a
keyboard LED. First run enables it, and a migration enables it for existing
installs, writing the enable symlink itself when there is no live user
manager.
Co-authored-by: Scott Jones <444693+scottjones@users.noreply.github.com>
Co-authored-by: Gabe Ohlson <3355909+6abe@users.noreply.github.com>
* Defer an image build's hardware setup to the machine's first boot
An image is built away from the machine it will run on, so its hardware
leaves would probe the builder. While the image manifest the detector
already reads (/var/lib/omarchy/image/target) exists, omarchy-apply-hardware
queues every leaf of install/hardware/all.sh instead of running it and arms
omarchy-provision-hardware.service. On the first boot, before owner setup
and the login screen, omarchy-provision-hardware retires the manifest and
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 its inputs or asked for it. Bluetooth starts its
service on that boot, whose target is already up. Root ignores any
environment override of these paths. Without a manifest, as on every
ISO install, hardware setup runs exactly as before. Nothing here fetches
package databases: an image carries its sync databases and every package
its steps install.
* Give an image-built root a UTF-8 locale when LANG is still C
A root built from a distribution tarball instead of the ISO (Arch Linux
ARM's ships LANG=C) never went through the ISO's locale step, so it ran
non-UTF-8. The config phase now selects en_US.UTF-8, generating it if
needed, but only when LANG is unset, C or POSIX: any named locale is
somebody's choice and stays. The ISO writes the locale before this runs,
so an ISO install is unchanged.
Co-authored-by: Scott Jones <444693+scottjones@users.noreply.github.com>
* Let a platform's packages run their own boot, system and user setup
Three dispatch operations give a platform one place for the setup it
needs beyond Omarchy's, instead of inline platform branches in the setup
leaves. The last hardware leaf runs setup-boot, then setup-system, as
root, so an image build queues them with the others and its first boot
runs them, with image-first-boot (offline-safe, asking for the one boot
rebuild instead of building). setup-boot belongs to the boot package and
is required on Apple Silicon, where hardware setup has no other way to
run the Mac's boot setup; a failed setup-boot stops the leaf before
setup-system. setup-user runs as the user being set up, refuses root,
and gets only the user's home and session variables: from the last user
leaf at finalization (skipped inside an image build, where the detector
would read the build host) and again from first run once the session is
up. On Apple Silicon setup-boot resolves in omarchy-mac-boot's directory
and the other two, both optional, in omarchy-mac's, /usr/lib/omarchy/mac;
x86, generic aarch64 and Qualcomm register none, so all three are no-ops
there.
A failed finalization now keeps first run pending, like any failed
first-run step, instead of letting the other steps mark it complete.
Co-authored-by: Scott Jones <444693+scottjones@users.noreply.github.com>
* Find batteries, lids and panels that aren't named like a PC's
Laptop detection assumed PC names: a battery called BAT*, a lid in /proc/acpi, a
touchpad or trackpad in the device name, a GPU backlight. Apple Silicon has
none of them (macsmc-battery, the SMC lid switch, apple-mtp-multi-touch,
apple-panel-bl), and some Framework and Chromebook firmware calls its battery
CMB0, so those machines lost the battery panel, laptop-only services, lid
handling, the touchpad toggle and display brightness.
- Battery presence goes by type instead of name, and skips a battery scoped
Device (a wireless mouse or keyboard), so a desktop with one isn't a laptop.
- Battery status takes the first UPower battery that powers the machine, reads
thresholds and cycles from it (BAT* stays the fallback), shows the magnitude
of a signed power_now, and rounds the percentage half-up for display like the
bar, while the charge-hold check keeps the unrounded value.
- A laptop is also one with any input device that reports a lid switch
(SW_LID), whatever its name: Apple's SMC input device has the same name on a
Mac mini, where it reports none. Whether the lid is closed comes from ACPI
where there is an ACPI lid, as before; otherwise logind is asked, with a
short timeout, only when a device reports a lid switch.
- A device named touchpad or trackpad still wins; only when there is none does
the touchpad match take a mouse udev marks as a touchpad (Apple's
multi-touch trackpad), never a touchscreen.
- The platform package can describe its displays in
/usr/share/omarchy-platform/displays.conf: backlights that never drive the
panel (a Touch Bar's), the panel's own where there is no GPU backlight, and
a display driver without DDC channels, where a probe walks unrelated I2C
buses for about 3 s: there only a connector with a ddc node is probed, and
a monitor without one reports no brightness instead of dimming the built-in
panel. Omarchy ships no such file and names no device in it; without it the
backlight choice and DDC probing are unchanged.
Co-authored-by: Scott Jones <444693+scottjones@users.noreply.github.com>
Co-authored-by: Ryan Hughes <1630358+ryanrhughes@users.noreply.github.com>
Co-authored-by: Sparsh Kumar <22640187+skkumarsparsh@users.noreply.github.com>
Co-authored-by: dl-alexandre <166029845+dl-alexandre@users.noreply.github.com>
* Keep the user's XDG config and state directories in platform user setup
setup-user runs with an allowlisted environment, which dropped
XDG_CONFIG_HOME and XDG_STATE_HOME. A platform's user setup reads the user's
configuration and keeps its setup markers there, so for a user who sets
either it looked in, and wrote to, the default directories instead. Both now
pass through with the rest of the session; XDG_DATA_HOME and everything else
still don't.
* Let a platform package add Hyprland defaults of its own
A platform's runtime package may need Hyprland defaults of its own (a Mac's
capture keys and three-finger workspace swipe, say), and Omarchy's config
should carry no branch for them. Three directories under the platform root,
/usr/share/omarchy-platform, now take them. The one installed platform package
owns that root, Omarchy reads it by literal path and ships nothing there, so
without a platform package nothing changes. Each file is loaded by its path,
so it can't shadow a module, and one that fails is logged and shown as a
notification while the rest of the config loads.
- hypr/defaults/*.lua loads before Omarchy's defaults. A
chord bound there replaces Omarchy's default for it, and a decorator it adds
runs before every later bind, so it can bind what has to run first. It sees
the command a bind runs, including the command a shell shortcut such as
{ menu = "root" } stands for when it binds the shell's global shortcut.
- hypr/settings/*.lua loads after Omarchy's defaults and
before the theme, for settings that replace Omarchy's.
- hypr/gestures/*.lua loads after the user's files, only for what must
see them: the gesture registry, which now records on every platform, lets a
default gesture step aside for the user's own.
The user's files load after the first two and can unbind or rebind any of it.
* Let a platform package name keys in the keybindings menu
The keybindings menu shows a key by its keysym, which on some keyboards is not
what the key says: on a MacBook, XF86MonBrightnessUp and Down are the F2 and
F1 keys, so the menu listed rows like "SHIFT + XF86MonBrightnessUp". A
platform package can now list names for such keys in /usr/share/omarchy-
platform/key-names, one "<keysym> <name>" per line, and the menu shows those
instead. The file is part of the menu cache's key, so installing or changing
it refreshes the menu. Without it the menu is as before.
Co-authored-by: Scott Jones <444693+scottjones@users.noreply.github.com>
Co-authored-by: kx0101 <90087463+kx0101@users.noreply.github.com>
* Keep the top bar out of a panel's camera cutout
A laptop panel with a camera notch at its top (Apple Silicon MacBooks, for
one) covered the middle of the top bar, and a bar shorter than the notch left
a sliver of every window beside the camera. Omarchy knows no panel's cutout
itself: the platform's own package describes them in
/usr/share/omarchy-platform/display-cutouts.json, by
connector, physical mode and the rows the cutout covers. 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-height sets that
floor by hand, on that panel only. Without a description, which is every
machine without such a package, the bar is as before.
Co-authored-by: Scott Jones <444693+scottjones@users.noreply.github.com>
* Keep PC and Intel Mac quirks off Apple Silicon
A few hardware steps and commands written for PCs and Intel Macs do the wrong
thing on Apple Silicon:
- The Intel Mac Wi-Fi quirk turns off the Broadcom firmware supplicant for
every Mac whose DMI vendor is Apple and whose chip is on its list. Apple
Silicon reports Apple Inc. through U-Boot's DMI tables, and the M1 Pro and
Max's BCM4387 is on the list, but there the firmware supplicant is the one
that works: turning it off makes firmware commands time out and breaks
scanning. The install step and its migration now skip Apple Silicon.
- fnmode=2 for Apple-like keyboards is left to the Mac's own platform package
on Apple Silicon, where the built-in keyboard's top row depends on it.
- The SPI keyboard check reads the DMI product name without failing the
hardware pass where there is none.
- The Windows VM, an x86_64 guest under KVM, runs on x86_64 only, and direct
boot (U-Boot finds the bootloader and makes its boot entries itself)
refuses Apple Silicon; the menu hides both there. Hibernation setup skips
it; its kernel has no hibernation today, and resume there is not wired.
Everywhere else each step runs as before.
Co-authored-by: Scott Jones <444693+scottjones@users.noreply.github.com>
* Let a platform's runtime package adjust the apps it needs to
Some apps need a platform's own touch once they are installed. On Apple
Silicon, Chromium-family browsers must decode video in software (the hardware
decoder renders green frames in them), and Steam only runs through a
FEX launcher, which then depends on Steam and must go before Steam can be
removed. Until now the Mac runtime did this with inline branches in the
installers.
Two optional dispatch operations take their place. post-install <app> runs
as the user once an installer has installed the app and finished its own
setup of it: every browser install (after its flags file, before it says the
browser is installed) and Steam's (after the package, before the 32-bit
drivers and the first launch). pre-remove <app> runs before Steam's removal
drops its packages. Where a platform registers them they refuse root (a
platform with nothing registered is a no-op, so sudo installs still work
there) and get the same home and session variables as setup-user, and a
failure fails the install or stops the removal. On Apple Silicon they
resolve in omarchy-mac's directory; every other platform registers none, so
installs and removal run as before there.
Steam's 32-bit driver step also stops failing the install on a machine with no
Intel, AMD or NVIDIA GPU (Apple Silicon, but also Snapdragon or a VM): it has
nothing to add there and now says so.
Co-authored-by: Scott Jones <444693+scottjones@users.noreply.github.com>
* Ask the platform's boot package before an update takes over its files
When an Omarchy package's upgrade stops only on files no package owns, the
update moves them aside and retries. On a Mac some of those files belong to its
boot chain or were written by its image (initramfs and pacman configuration,
say), and moving them aside can leave it unable to boot or update. The Mac
runtime refused those paths with an inline list.
update-takeover <path>... asks the platform's boot package instead, before
anything moves: read-only, exit 0 lets the takeover go ahead, anything else
keeps every file and the update fails as it did before the retry existed. The
update resolves it as the user and runs it with sudo only where it resolves,
inside the authorization the move needs anyway. On Apple Silicon it is
required: a Mac without its boot package, or with one too old to answer, keeps
its files. Every other platform registers none, so the takeover goes ahead as
before, asking no one.
* Install the Mac's package set on Apple Silicon
omarchy-pkg-defaults already composes install/omarchy-<platform>.packages
after the base and aarch64 lists, but Apple Silicon had no list, so a Mac got
the generic aarch64 set: no omarchy-mac or omarchy-mac-boot, whose entrypoints
the dispatcher requires there.
install/omarchy-apple-silicon.packages names the Mac's runtime and boot
packages, plus the defaults an owner may remove: the startup-volume tool,
hardware video decode, Widevine, and wf-recorder, since gpu-screen-recorder
can't capture on Apple Silicon and screen recording falls back to it. What a
Mac can't work without (its speaker stack, PipeWire's PulseAudio server and
realtime scheduling, the GPU's Vulkan driver) comes as omarchy-mac's
dependencies, so a new Mac driver needs no Omarchy change. Other platforms
compose exactly what they did.
Co-authored-by: Scott Jones <444693+scottjones@users.noreply.github.com>
* Give existing aarch64 machines the zram swap Omarchy configures
omarchy-settings configures swap on zram and tunes memory reclaim for it.
x86_64 gets zram-generator from its installer and new aarch64 installs from
their default packages, but an aarch64 machine installed before
omarchy-aarch64.packages named it has no generator, so the configuration asks
for a device nothing creates.
Migration 1790328426 installs zram-generator where the platform's default
packages name it and it is missing, and starts the zram swap wherever it is
down, unless no device is configured (then the generator makes no swap unit)
or the administrator masked it. A swap that won't start, or whose unit can't
be read, only warns: the generator's unit starts with every boot, so a reboot
retries it, and failing the migration would stop every update. A failed
install waits (75) for the next migrate, as it does where the platform can't
be told, changing nothing. It keeps the name it has in omarchy-mac, so Macs
that already ran it skip it. It also retires an /etc copy of the drop-in
identical to the packaged one, which earlier Mac setups made and which would
hide the packaged file's updates; an edited copy stays. On x86_64 the default
packages don't name the generator and there is no copy, so it does nothing.
* Keep an ARM machine's repositories when it changes channel
omarchy-refresh-pacman and install finalization copied x86_64 templates
everywhere, so on an aarch64 machine a channel change or a finished install
wrote Arch Linux's x86 [core]/[extra]/[multilib] and dropped Arch Linux ARM
and the platform's own repositories.
Channel changes now tell the platform apart. x86_64 is unchanged. On aarch64
the machine's configuration is kept, with its repositories, mirrors and
signature policies, and only the [omarchy] server moves to the new channel;
a configuration whose Omarchy server can't be identified is refused
unchanged, and one with no Omarchy repository gets it at the end (not on
Apple Silicon, whose own repository must not come first). Only pacman.conf is
backed up and rewritten, straight from this process through sudo, never
through a file another process could change first.
Before that, a channel must be qualified for the platform: a signed upgrade
and reboot tested there, not only a published repository. x86_64 keeps
stable, rc and edge; Snapdragon and other aarch64 machines take edge, as
dragon does; Apple Silicon takes none until the Mac packages qualify on edge.
The refresh then checks, as the user, that the channel's omarchy.db
publishes the runtime pair, and on Apple Silicon omarchy-mac and
omarchy-mac-boot. omarchy-channel-set refuses an unqualified channel before
anything else, the dev confirmation included.
Install finalization writes a whole template, as before on x86_64. Other
aarch64 platforms get Arch Linux ARM (dragon's pacman-aarch64.conf and
mirrorlist-aarch64, byte for byte) with its keyring, plus Omarchy on a
qualified channel. Apple Silicon gets omarchy-mac's template on a qualified
channel and keeps its image's configuration otherwise. In an image build,
finalization leaves the keyring to the machine's first boot, so machines
flashed from one image don't share a pacman master key. On an unqualified
channel, a machine that gets no Omarchy repository is told why.
Co-authored-by: Birk Skyum <74932975+birkskyum@users.noreply.github.com>
Co-authored-by: Jim Martin <1334144+jdvmi00@users.noreply.github.com>
* Keep Arch Linux ARM's signing keys current on ARM machines
omarchy-update-keyring reinstalls archlinux-keyring before every system
upgrade, since keys change without a version bump. An aarch64 machine's Arch
Linux ARM repositories are signed with keys from archlinuxarm-keyring, which
nothing refreshed, so a rotated ALARM key failed the upgrade that followed.
On an aarch64 platform where archlinuxarm-keyring is installed, it is
reinstalled in the same transaction. On x86_64 the keyring step runs exactly
as before, even where that package happens to be installed.
* Mark the runtime's platform files as deciding at runtime
The omarchy-settings recipe leaves the mkinitcpio, Limine, memory and USB
drop-ins out of its aarch64 package, because they used to assume x86_64. That
leaves an aarch64 install without the HOOKS baseline its initramfs needs, and
without the zram and reclaim settings every other Omarchy machine gets.
Each of those files now decides at runtime whether it applies: the HOOKS
baseline asks the platform, thunderbolt is added only where the kernel has the
module, 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, and the USB autosuspend option is ignored by a kernel
that builds usbcore in. default/settings-runtime-profile says so, file by
file; a recipe that finds it ships the same files on every architecture
(omacom/omarchy-pkgs#638), and older sources keep today's aarch64 package. A
test checks that every file it names exists and that each runtime decision is
in place.
* Set the wireless regulatory domain from the owner's timezone at first-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.
* Ask again for a keyboard layout first-boot setup could not apply
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.
* Refresh a platform's own signing keyrings before an update
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.
* Drive an untyped default input from the audio panel
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.
* Give first-boot setup an XKB layout for keymaps systemd cannot map
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>
* Leave keys a firmware key turned off dark
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>
* Drop the optional-install availability guards
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 aea001cbde4d0852b311ef42b5e8c380c719f833.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>
* Put the current root back when the factory root cannot take its place
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.
* Leave other recorders alone when the saved recorder pid is stale
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.
* Name the audio a wf-recorder recording could not capture
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.
* Show the Edge, Spotify and Dropbox installers on x86_64 only
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.
* Revoke the generic reset's throwaway slot when the reset fails
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.
* Clear a stale recorder pid when a recording starts
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.
* Word the dropped-audio notice for every reason a source is left out
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.
* Show the Heroic and Minecraft installers on x86_64 only
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.
* Ask the recorder script whether its stop has a recording to end
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.
* Copy every platform's pacman templates into place, as x86_64 does
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>
* Revert "Copy every platform's pacman templates into place, as x86_64 does"
This reverts commit 9a07e138cc6c3a19b58d2f3d7eb536dd3042ccc5.
* Copy every platform's pacman templates into place, as x86_64 does
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>
* Drop the migrations no installed machine needs
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>
* Drop the generic changes Mac support doesn't need
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>
* Drop the platform Hyprland slots
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>
* Keep aarch64 machines off the release channels until a release supports 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.
* Leave a filter's own capture alone when choosing an input again
d0b94d98c 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.
* Say aarch64 offers edge alone where the templates are described
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.
* Point the Mac packages at omacom/omarchy-mac-pkgs
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.
* Stop naming a platform migration among the dispatcher's callers
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.
* Keep the Intel Mac Broadcom migration off Apple Silicon again
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.
* Say when Steam's post-install hook runs now that the drivers go first
Steam's installer now adds the 32-bit drivers before Steam itself, so the hook runs after both and before the first launch.
* Release fallback audio after the recorder exits
When wf-recorder ends outside the normal Stop path, status rejects the saved PID before unloading the combined-audio loopbacks. Release those owned modules when the saved recorder is gone, so the next status or stop call ends microphone capture without signaling another recorder. Leave a mix without a saved PID alone: its recorder can still be starting.
Co-Authored-By: GPT-6 in Codex <noreply@openai.com>
Co-Authored-By: Codex Medium <noreply@openai.com>
* Serialize recording state changes and stale audio cleanup
Status can finish checking an exited recorder after another command has replaced its audio modules, and stop finalization can outlive the recorder while a new recording starts. Share a lock across start, stop and cleanup so each command finishes updating its resources before another changes them. Status uses a read-only check when the lock is busy, keeping the bar responsive during the picker. Close the lock descriptor in persistent children so recording and preview cleanup cannot retain it.
Co-Authored-By: GPT-6 in Codex <noreply@openai.com>
Co-Authored-By: Greptile <165735046+greptile-apps[bot]@users.noreply.github.com>
* Keep automatic and manual keyboard brightness updates together
A brightness key can update the LED and its chosen-level record after the automatic loop checks for a manual change but before it applies a new target. The automatic write then overwrites the user's choice and deletes the record. Take the manual command's lock for the whole tick, skipping a busy tick and releasing the descriptor on every return. Create the private fallback directory before opening the lock outside a session runtime directory.
The normal lock screen waits five seconds before blanking, so an ordinary tick should already see the session locked. The regression exercises a brightness key arriving within a tick instead of relying on an implausibly delayed lock-state check.
Co-Authored-By: GPT-6 in Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 High via Pi <noreply@anthropic.com>
* Read the split hook baseline in the NVIDIA migration
The NVIDIA firmware migration decides whether to rebuild by sourcing the hardware and filter drop-ins. With HOOKS now defined in the earlier baseline, that partial read treats every hybrid machine as if kms had been removed. Source the new baseline first when it exists, keeping the legacy two-file layout working and skipping rebuilds when the effective hooks still include kms.
Co-Authored-By: GPT-6 in Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 High via Pi <noreply@anthropic.com>
* Use a hardware helper for x86-only menu entries
Keep the x86_64 availability checks for Windows and vendor-specific installers in a hardware predicate, so menu conditions use the same command style as other hardware checks.
Co-Authored-By: GPT-6 in Codex <noreply@openai.com>
* Keep restored keyboard levels from pausing automatic brightness
Idle wake, quick unlock and hibernate can restore a saved level older than the ambient loop current level without the lock blanking first. Treat that restoration as a one-tick event, preserving existing manual pauses and the normal blank-and-restore path. Consume unmatched and unchanged restore records too, so a later firmware key cannot look like the earlier restore.
Co-Authored-By: GPT-6 in Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 High via Pi <noreply@anthropic.com>
* Preserve restored keyboard levels across a later lock blank
The ambient loop skips a locked session, so a restored level may still be unconsumed when the next blank saves it. Carry that origin through blanking and restore failures so fingerprint unlock cannot make the old saved level look like a manual choice. A brightness key replaces the marker with its chosen level and retains the ordinary blank behavior.
Co-Authored-By: GPT-6 in Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 High via Pi <noreply@anthropic.com>
* Preserve firmware brightness choices before a lock blank
Firmware keys change the LED without updating the record. Carry a pending restoration through the next blank only if the observed LED still matches that restoration, or is still zero from its previous blank. A firmware change otherwise follows the ordinary blank-and-restore path so automatic lighting pauses on the chosen level.
Co-Authored-By: GPT-6 in Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 High via Pi <noreply@anthropic.com>
* Change only the disk password in omarchy-drive-password
Changing the system disk's password also set the login and root passwords
to match. That changes account-password policy on every platform, x86
included, and overwrites passwords someone chose to keep different, so it
moves to its own change with an explicit confirm.
The disk change itself stays as it was: the new key must open the disk and
the old one must not before the change counts, the journal finishes an
interrupted change, and where the platform's boot checks prove the key
slots, the owner's new slot is recorded before the run finishes. The
journal's confirmed phase is now "record" and no longer needs a login user.
* Cancel a pending recording start instead of queueing behind it
Starting a recording holds the recorder lock through the picker and until the
recorder creates its file. A second toggle or a stop then waited on that lock,
with no end while a portal pick or a stuck recorder never finished, and once
the start gave up the queued toggle began another recording.
While a start is pending, a toggle or stop that cannot take the lock within a
second now leaves a cancel marker and returns. The start checks it after the
picker, after the webcam overlay and while waiting on its recorder, then stops
that recorder and releases its audio. A recorder other than the portal's that
has not created its file after 15 seconds is stopped and the next backend
tried.
* Move automatic keyboard lighting to its own change
Ambient-light keyboard backlight is a new feature on every laptop with the
sensor, not something Apple hardware needs to run Omarchy, so it leaves this
change for a separate review. The keyboard-brightness command returns to
upstream's version, and first run no longer enables the user service.
* Move workspace refocus on monitor removal to its own change
Keeping the viewed workspace in front after a monitor is unplugged changes
desktop behaviour on every machine, not just Apple hardware, so it leaves
this change for a separate review.
* Move prebuilt-image hardware deferral to its own change
Building an image away from its machine needs a manifest the detector reads,
a queue of hardware steps for the first boot, a first-boot service and a
per-machine pacman keyring. An install on the machine itself needs none of
it, so it leaves this change for a separate review with an installer and
package boundary of its own. Hardware and user setup now run where they are
installed, and the platform setup operations take no image argument.
* Move the Qualcomm platform to its own change
Snapdragon support is separable from Apple compatibility, so the detector no
longer names a qualcomm platform: a "qcom," device tree is generic aarch64,
which Snapdragon already behaves as everywhere else here, and a tree naming
both Apple and Qualcomm is still refused. linux-firmware-qcom's platform list
leaves with it.
* Keep a cancel that arrives while a recording start finishes
A stop could land after the start's last cancel check, while it saved its
recording as started, and be dropped with the marker. The start now removes
its starting marker before a final check, a request reads that marker only
after leaving its own, and one that finds the start gone waits for the lock
and acts unless the start already used its request. A recorder ended by a
cancel or a readiness timeout gets two seconds after TERM before KILL, so a
recorder ignoring TERM cannot hold the start and its lock.
* Defer an image build's hardware setup to the machine's first boot
Brings back prebuilt-image support split out of #14431 so it gets its own review. An image built away from its machine names its target in a root-owned manifest the detector reads; hardware setup is queued for the machine's first boot, run there by omarchy-provision-hardware, which also makes the machine's own pacman keyring; and the platform setup operations learn they run on an image's first boot. Apple Silicon images built by the omarchy-mac installer need this; an install on the machine itself does not.
* Rebuild the initramfs when deferred setup changes module options
mkinitcpio's modconf hook copies /etc/modprobe.d into the initramfs, but the
deferred first-boot setup only compared mkinitcpio's configuration and the
kernel command line when deciding whether to rebuild. A step that only wrote
module options, as nvidia.sh does, left the old ones in the boot image.
* Put the Omarchy repository first on aarch64, as on x86_64
quattro now searches [omarchy] before the Arch repositories (
|
||
|
|
c3cdcb1e82 | Keep USB approvals portable and preserve approval prompts | ||
|
|
60d6b255da | Require approval for new Thunderbolt accessories | ||
|
|
67d173c9f9 | Defer USB enrollment until owner provisioning completes | ||
|
|
44f68f4329 |
Require approval for new USB devices by default
Co-authored-by: Outfoxxed <outfoxxed@outfoxxed.me> |
||
|
|
04b0a47c9b |
Configure locate through the packaged service
Reported-by: uiop / @wasdhjklxyz <uiop@wasdhjkl.xyz> |
||
|
|
c720f0b981 |
Merge pull request #8951 from omacom/cups-browsed-temporarily-removed
Temporarily remove automatic printer discovery |
||
|
|
bf20c94ea0 |
Merge quattro into the Chromium first-run EULA branch
Quattro stopped making the Chromium managed-policy directory world-writable while this branch was open, and the block it deleted from the theme install leaf sat directly above the comment this branch rewrites, so the two edits landed in one hunk. The resolution keeps the hardening — the policy directory is set up through install/config/browser-policy.sh now — along with the first-run seed and the comment that names both things the seed does. |
||
|
|
24c18df5b7 |
Temporarily remove automatic printer discovery
cups-browsed is the daemon that watches the network and creates print queues by itself. Hardening it took a root daemon with a predictable cache down to a confined service account, but a daemon that turns anything advertising itself on the network into a print queue is a lot of exposure for a convenience, so it comes out of the default install while that is reworked. Only the discovery half: CUPS itself stays and printing keeps working, with each printer added by hand in Print Settings. The migration disables the unit before removing the package because that is the only order that works: pacman deletes the unit file but not the enable symlink, and once the unit is gone systemd can no longer resolve it by name to clean that up. It then removes the queues discovery generated. cups-browsed keeps those when it stops, since KeepGeneratedQueuesOnShutdown defaults to Yes, and they route through its own implicitclass backend, which goes with the package, so they cannot print again. Idle ones go. A queue with jobs on it is left alone and named: implicitclass only needs cups-browsed to choose a destination, so a job already past that point finishes on its own, and deleting the queue would abort it. One printer's job does not hold up the removal. A printer added by hand has an ipp:// or usb:// device and is left where it is. A queue whose jobs cannot be asked about is left alone rather than assumed idle, including one named so that lpstat would misread it -- "all" is its word for every destination, and a leading dash or a comma reads as another option or a list. Where CUPS does not answer at all, or a queue will not delete, discovery is still stopped but the package stays and no marker is written. omarchy-migrate records a migration for the user as soon as it exits zero, so that is where the machine stays until someone removes the package by hand, and the message says so rather than implying a retry. The queue list is read under LC_ALL=C because lpstat translates "device for", and captured rather than piped, so a cupsd it cannot reach is reported instead of reading like a machine with nothing to clean up. It removes with plain pacman -R rather than omarchy-pkg-drop, which passes -n and would discard /etc/cups/cups-browsed.conf instead of keeping it as a .pacsave. A removal meant to be temporary should not delete the machine's copy of its own configuration. Without -s either, so it only ever removes the package it names: sweeping newly unneeded dependencies is nothing today, but it is not a promise a rolling dependency graph can keep. Queue names come off the network, since cups-browsed names its queues after what the printer advertised. CUPS allows every printable character but space, tab, / and #, and lpstat and lpadmin take a destination as an option value, so a name with a leading dash or a comma is reported rather than passed to them and guessed at. Migration state is per user, so a machine-wide marker records the one removal. Without it, an account whose first migration run came after someone deliberately reinstalled discovery would quietly take it back out again. The install-time override for cups-browsed.conf now waits for cups-browsed rather than for CUPS. Guarding it on a file CUPS still ships would write a configuration file for a package nothing installed, and pacman would later land the package's own copy beside it as a .pacnew. The hardened configuration stays in the tree. omarchy-settings still ships the cups-browsed.conf override, the sysusers account and the service drop-in, so they are what discovery returns onto. Co-Authored-By: Codex XHigh <noreply@openai.com> |
||
|
|
e9ba17e52e |
Keep the explanation for the Chromium color scheme defaults
The comment above the seed was the only thing recording that color_scheme and color_scheme2 are both zero in order to follow system appearance rather than force dark. Generalizing it to "first-run defaults" left two magic numbers with nothing to explain them, so the next person touching an unrelated first-run setting has no way to tell that changing them regresses theme following. Name both things the seed does. Co-Authored-By: Codex XHigh <noreply@openai.com> |
||
|
|
bafc9a1000 |
Write browser theme colour through a passwordless helper
Managed policy dirs are enterprise trust roots, so they stay 0755 root:root. The menu path takes root for that one write through a sudoers glob of six hex digits, the same shape as omarchy-dns, and falls back to pkexec where the grant is not installed. Drop omarchy-browser-policy; a group member could plant any JSON, not just a colour. |
||
|
|
95b791af16 |
Stop world-writable browser policy directories
Chromium managed policy is mandatory for every profile. World-writable dirs let any local uid plant policy, including force-installed extensions. Write goes through the omarchy-browser-policy group at 2775 so theme colour still works without other-write. |
||
|
|
b91180a808 | Skip Chromium EULA on first run | ||
|
|
b5ded31e2f |
Don't put the user in the docker group; make it opt-in (#8056)
* Don't put the user in the docker group; make it opt-in The docker group is root-equivalent: anything in it can `docker run -v /:/host` and rewrite the host as root with no password. On a single-user box that's not an escalation (the owner is already a wheel/sudo user), but it hands any code running as the user — a rogue plugin, a poisoned dependency — a silent, headless, passwordless path to root that sudo's password prompt would otherwise gate. Stop granting the docker group by default. The daemon still runs (docker.socket); the Docker TUI and the Windows VM reach it through a polkit prompt, and the plain `docker` CLI runs under sudo. Sudoless Docker is a warned opt-in via Setup > Security (omarchy-setup-security-sudoless-docker). No automatic path may re-grant it: install and first-boot provisioning never record or apply the group (provisioning also filters a docker line left in an older factory snapshot), and the Quattro upgrade no longer adds it. The Windows VM keeps needing the root daemon for a privileged container (KVM, NET_ADMIN), so it is reworked to run without the group and without becoming a new way in: - The compose lives in a root-owned dir and is only written by an elevated, input-validated writer. A root-invoked bring-up must never consume a file a user-process could rewrite to bind-mount / into the guest — the old ~/.config/windows compose was exactly that. Volume paths are rebuilt from $HOME on migration rather than trusted from the (user-writable) legacy file, path validation rejects traversal, and the privileged sub-action is checked against an allowlist before dispatch (a slash in it would otherwise run as a path). - pkexec elevates a verified root-owned command path, not a PATH-resolved one, so an authorized prompt can't be redirected to an attacker's binary. - The guest password is kept in a private 0600 per-user file for RDP instead of a world-readable compose, and a declined authorization is reported as such, never as a completed stop. Existing installs auto-migrate the VM (no redownload) and refresh the stale Docker launcher entry. 🤖 Generated by Opus 4.8 in Claude Code. Reviewed by Codex XHigh. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-Authored-By: Codex XHigh <codex@openai.com> Claude-Session: https://claude.ai/code/session_01Gb7x6poap4hGCndPx5qt5T * Migrate existing installs off the docker group The default flip only reaches new installs; existing users keep their docker group membership and stay exposed. Extend the migration that already refreshes the Docker launcher to also remove the current user from the group when present, reusing omarchy-remove-security-sudoless-docker so there is one source of truth for the change and its notice. It takes effect at next login (the current session keeps working), and passwordless docker can be turned back on from Setup > Security > Sudoless Docker. Migrations run with sudo available — during `omarchy update`, or in the terminal the pending-migrations notification opens — so the privileged removal does not prompt at an unattended login. The no-op path (already out of the group) needs no privilege. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gb7x6poap4hGCndPx5qt5T * Refuse symlinked VM mount sources; correct the docker CLI docs Review follow-ups. valid_path keeps a traversal string (/./, //, ..) out of the compose, but it is a string check: a symlink planted at ~/.windows or ~/Windows redirects the privileged bind mount exactly as traversal would, because docker follows it. So verify the mount sources as root immediately before bringing the VM up — refuse a source that is a symlink or resolves through one — which is where the string check cannot help. A missing source stays fine (docker creates a plain dir). Also correct the development-tools manual: the CLI is not transparently elevated (there is no docker wrapper and `d` is still plain docker), so say plainly that docker on the command line takes `sudo` until sudoless Docker is enabled. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gb7x6poap4hGCndPx5qt5T --------- Co-authored-by: David Heinemeier Hansson <david@hey.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Codex XHigh <codex@openai.com> |
||
|
|
536fcd5c6c |
Move install-time plumbing out of the setup namespace
setup is where a user goes to configure something: direct boot, security keys, hibernation. These three are not that. omarchy-apply-system is the ISO's entry point in the target chroot, omarchy-apply-hardware is what it calls for device quirks, and omarchy-apply-lock is called by install/config/lockscreen-pam.sh. apply is the verb they already used to describe themselves, and it carries the contract: declared state under install/ converged onto the machine, idempotent, safe to repeat. The group gets no GROUP_DESCRIPTIONS entry on purpose. That table drives the top-level group list on its own, so an entry would put apply back in front of users even with every command in it hidden, the way provision already stays out. A test covers it. The ISO installs the runtime from the mirror it ships with, so it moves to the new names in lockstep and no compatibility route is needed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
6fa4f78ee1 |
Add deferred first-boot provisioning and factory reset (#6621)
* Add OEM first-boot setup and factory reset An OEM-mode ISO install (or omarchy-reset-computer) leaves the machine in OEM state: fully installed, no user, /var/lib/omarchy/oem/pending armed. On the next boot omarchy-oem-setup.service runs the configurator's user form on tty1, creates the user with the groups system setup recorded, finalizes it offline from the stashed Node tarball, re-keys LUKS from the throwaway install passphrase to the user's password, and hands off to SDDM. omarchy-reset-computer returns a machine to that state: it swaps the running root for a fresh clone of the @factory snapshot the ISO takes at install time, scrubs machine identity and prior users, and stages omarchy-factory-wipe to drop the old root and recreate @home/@log on the next boot. Machines installed before @factory existed get a degraded reset (current system kept, users and state wiped) with that caveat surfaced in the confirmation. omarchy-setup-system/-hardware gain --oem to run without an install user; the group-granting install scripts now record their groups in /var/lib/omarchy/oem/groups and only call usermod when the user exists. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Harden OEM setup: correct cryptsetup key-file usage, retry on failure cryptsetup reads --test-passphrase/--key-file inputs byte-for-byte, so feed passphrases through process substitution consistently instead of positional args or stdin (which has different newline semantics). Run each first-boot setup attempt as its own process so a failure offers a retry instead of stranding the machine at a user-less login screen — bash ignores errexit inside `while !` conditions, a child process does not. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Always grant wheel sudo in OEM first-boot setup Detecting an existing %wheel grant by grepping sudoers is error-prone: omarchy ships narrow '%wheel ALL=(ALL) NOPASSWD: <command>' rules (e.g. asdcontrol) that match the naive pattern, which left the OEM-created user matching sudoers entries but unable to run anything. Write the drop-in unconditionally — a duplicate of an existing full grant is harmless. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Fix LUKS re-key device resolution and OEM state readability archinstall's encrypted installs put cryptdevice=PARTUUID=... on the kernel cmdline, not UUID=, so the first-boot re-key never found its device and silently skipped — leaving the throwaway auto-unlock keyfile in place, i.e. the disk effectively unencrypted. Parse every cryptdevice= source spec form and make any re-key failure abort the attempt loudly: a retry prompt beats a machine that quietly boots without a passphrase forever. The OEM state directory also has to be world-readable (its one secret, luks-key, stays 0600): user finalization reads the stashed Node tarball as the new user, and the 0700 directory forced it onto the network fallback. Step markers now land in /var/log/omarchy-oem-setup.log for debuggability. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Purge stale machine-id boot entries when resetting or re-keying limine-entry-tool keys its limine.conf OS entries by machine-id. A factory reset gives the machine a fresh identity, so the previous system's entry survived every rebuild, sorted first, and made Limine stop at a Blake2b hash-mismatch warning once the UKI was rebuilt. Start limine.conf over from the shipped template (and drop foreign machine-id history directories on the ESP) before any post-reset rebuild: in the staged chroot rebuild, in the first-boot LUKS re-key, and — for unencrypted resets, where nothing else rebuilds — in a dedicated first-boot refresh when foreign entries are found. The staged rebuild also verifies every UKI hash referenced by limine.conf against the file on the ESP before the subvolume swap, and the running system's limine-snapper-sync is runtime-masked during staging so it cannot rewrite the config behind the rebuild. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Harden reset and first-boot setup failure paths Review findings from codex and Copilot: - Generate throwaway passphrases without a trailing head stage: under pipefail, SIGPIPE from the infinite tr failed the substitution and errexit aborted every encrypted reset before it could stage anything. - Stage the fallible parts of a degraded reset (LUKS re-key, boot rebuild) before arming the wipe, so a staging failure leaves the machine untouched instead of scheduling a wipe for a reset that never finished. - Gate first-boot setup on the factory wipe having succeeded (ConditionPathExists=!wipe-pending plus an in-script guard): creating the new user on a half-wiped system would hand their data to the wipe retry. - Abort the wipe (keeping its retry marker) when deleting the old root or recreating @home/@log fails, and abort resets that cannot remove a prior account — a surviving account keeps its password and wheel membership. - Resume a partially-created account on setup retry instead of rejecting the username the failed attempt just created. - Only purge machine-id directories the old limine.conf actually referenced; a shared ESP may hold other installations' boot artifacts. - Recreate the hibernation swapfile (nested subvolume, so never captured by the factory snapshot) inside the factory root before its UKI rebuild, so a reset machine keeps disk-backed swap and a valid resume offset. - Source base-test.sh in the OEM groups test per test conventions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Recreate the hibernation swapfile even when resume drop-ins survive omarchy-hibernation-setup short-circuits as 'already set up' when the resume mkinitcpio drop-in exists — which it always does in a factory root, while the swapfile itself never survives the snapshot (nested subvolume). Drop the marker when the swapfile is gone so setup reconfigures from scratch, and verify the swapfile actually exists before proceeding with the reset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Second review pass: encrypted-config coverage, factory-baseline sanitization, recoverable rekey Codex xhigh round 2: - Detect the LUKS backing device by walking the root's device tree, not only the cmdline cryptdevice=; reset/first-boot now re-key roots reached via rd.luks/crypttab too, instead of silently leaving the seller's slots valid. - Sanitize the retained @factory baseline (accounts, /etc/shadow, machine identity) during a full reset: the new wheel user could otherwise mount it to recover the seller's data, and a second reset would restore the account. - Re-key the disk recoverably: rebuild the no-auto-unlock UKI before killing the throwaway slot or destroying the staged key, and restore the keyfile if that rebuild fails, so a retry with a different password can never leave the disk locked to the first attempt's password. - Roll back a degraded reset's live-root auto-unlock material if its boot rebuild fails, instead of leaving it for a later rebuild to embed. - Treat a missing current-machine limine entry as stale so a retry after a failed rebuild repairs the config instead of clearing OEM state over it. - Erase fingerprint enrollments (/var/lib/fprint) in degraded wipes. - Remove the resume-offset drop-in too when recreating the factory swapfile, so the rebuilt UKI gets a correct offset. - Pin first-boot retries to the account the first attempt created. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Expose factory reset in the Setup menu Add a 'Reset Computer' entry under Setup (Omarchy's Settings menu, where OS factory resets conventionally live), guarded to btrfs roots and launched in a floating terminal. omarchy-reset-computer now self-elevates via sudo so the menu entry needs no sudo prefix, forwarding the caller's gum theme env as env arguments so styling survives an env_reset sudoers. The typed 'reset' confirmation and the sudo password prompt remain as the guards against accidental triggering. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Defer keyboard selection to first boot for OEM installs The OEM first-boot setup now runs a keyboard step before the user form, mirroring the ISO configurator: it loads the chosen layout on the live VT so the password (and the LUKS re-key that follows) are typed under it, and persists it with systemd-firstboot so the installed system gets both the console KEYMAP and the XKB layout Hyprland reads — exactly what a normal install writes. Layouts localectl doesn't know keep the default, same as the installer. This lets the OEM operator set nothing user-specific: the machine's owner picks their keyboard alongside their account at first boot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Rename factory-reset commands to omarchy-system-factory-reset[-finish] omarchy-reset-computer -> omarchy-system-factory-reset omarchy-factory-wipe -> omarchy-system-factory-reset-finish (and its systemd unit, log path, and temp mount to match) Pure rename: every reference — the Setup menu action, the first-boot finish service the reset stages and enables, the oem-setup ordering/gating, comments, and the menu test — moves together, with no behavior change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Rename OEM vocabulary to provisioning (runtime) Commands unify under the provisioning family: omarchy-oem-setup → omarchy-provision-owner omarchy-finalize-user → omarchy-provision-user omarchy-first-run → omarchy-provision-first-run And the deferred-provisioning state/vocabulary replaces 'OEM': /var/lib/omarchy/oem/ → /var/lib/omarchy/provisioning/ /etc/omarchy/oem.key → /etc/omarchy/provisioning.key install/oem/ → install/provisioning/ OMARCHY_SETUP_CONTEXT=oem-firstboot → provision-owner omarchy-setup-system/-hardware --oem → --defer-provisioning All callers (provision-first-run→provision-user, autostart, factory-reset staging the provisioning units, the group-recording scripts) and comments move together. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Drop remaining OEM mentions from the provisioning groups test Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Finish the omarchy-first-run rename in the docs Two doc references to omarchy-first-run were missed when the script was renamed to omarchy-provision-first-run; update them to match. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
6ddc39520d |
Clean up the terminal and reconnect when SSH connections drop (#6661)
* Clean up the terminal and reconnect when SSH connections drop A remote tmux, herdr, or editor arms terminal modes over the SSH pipe (mouse tracking, focus reporting, the alternate screen) that only it can disarm. When the connection dies instead of exiting cleanly, those modes stay armed on the local terminal, and every mouse move floods the prompt with escape-sequence junk. Wrap ssh in a shell function that disarms those modes after every exit, and automatically reconnects when an established interactive session drops. Remote commands, configured RemoteCommands, and redirected stdin never reconnect, so their side effects cannot replay, and the retry loop runs in a subshell so Ctrl-C cancels both the in-flight attempt and the loop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Detect dead SSH connections within a minute Without keepalives, ssh does not notice a dead peer until TCP gives up, which can take hours of sitting on a hung terminal with remote-armed terminal modes stuck on. Ship a client keepalive default so drops are detected in about 45 seconds, letting the shell's ssh wrapper clean up and reconnect. ~/.ssh/config is read first and wins, so per-host overrides still apply. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Fail closed when ssh -G cannot resolve the effective config An unresolvable configuration could hide a RemoteCommand, so treat it as non-interactive rather than reconnectable. Also strengthen the tests from Copilot review: assert the complete disarm sequence, and verify on a real interactive pty that Ctrl-C during a retry attempt kills the reconnect loop itself, not just the in-flight attempt. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Tolerate the explicit RemoteCommand none when probing ssh -G The literal "none" is how ssh_config cancels a configured RemoteCommand, and some OpenSSH versions emit it even when unset, which would have silently disabled reconnecting entirely. Treat it as no remote command while still failing closed on real ones and unresolvable configs, and make the fake ssh -G emit the "none" form so the behavior tests cover it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
b925431025 |
Give SSH commands the user-level tool paths (#6632)
* Give SSH commands the user-level tool paths
ssh host cmd runs neither a login nor an interactive shell, so on Arch it
gets the bare sshd PATH and can't find mise-managed tools like the agent
CLIs herdr scans for. Set PATH in the PAM environment (per-user via
@{HOME}), append the user-level dirs in env-bootstrap so login shells and
the uwsm session get them too, and source env-bootstrap before bashrc's
interactive guard for bash variants that read it non-interactively.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Don't let an empty PATH turn into a cwd entry
Appending with a bare "$PATH:" prefix leaves a leading colon when PATH
is unset, which shells treat as the current directory.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
1ea910f662 |
Let systemd-oomd kill a runaway app instead of losing the session (#6445)
Nothing stood between "memory is tight" and "processes die at random": the kernel OOM killer only fires after an allocation has already failed, so a machine under pressure thrashes in reclaim until something breaks somewhere fatal — seen in practice as Hyprland taking SIGBUS mid-memcpy from a client shm pool that memory pressure was tearing down. Enable systemd-oomd, which keys on PSI stall time rather than free pages, and mark app.slice — and only app.slice — as its kill candidate. Hyprland runs in session.slice, so the compositor is structurally ineligible as a victim: oomd takes the app that caused the pressure and the session survives. Thresholds (50% stall over 20s, Fedora's desktop defaults) live in an oomd.conf.d drop-in; candidacy ships as a vendor drop-in under /usr/lib/systemd/user so existing users get it on package upgrade with no per-user seeding. New installs enable the daemon from enable-services.sh; a migration covers existing ones, restarting an already-running oomd so it doesn't keep stale thresholds until reboot. Deliberately not earlyoom: it triggers only when free RAM and free swap are both under threshold, so Omarchy's large, mostly-idle swapfiles keep it asleep through exactly this failure. Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
9b9d4b39eb |
Never leave updatedb.conf with two definitions of the same setting
updatedb refuses to run at all on a config that defines a variable twice
("variable `PRUNEPATHS' was already defined"), so any rewrite that misses
an existing line and appends a second one takes the locate index down
rather than fixing it. Two shapes updatedb accepts got missed: a trailing
comment after the value, and a setting indented by whitespace.
Read the existing paths out of the quoted value and write the whole
setting back canonically instead of splicing into a line of unknown
shape. Quotes are not optional to updatedb ("value in quotes expected
after `='"), so a bare value is already a broken config: rewriting it
quoted repairs the file as a side effect.
The tests now hand every rewritten file to the real parser through
`updatedb --config-file`, which is what caught this.
Read the Snapper config as root when the running user cannot read it.
snapper create-config leaves the config root-only, and a config the user
cannot read was passing for one that wants its timeline snapshots kept.
Report the snapshots the drain could not delete. omarchy-migrate writes
the completion marker whether or not the batches succeeded, so there is
no later run to pick up the remainder, whatever the comment claimed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
a6a13cf3e6 |
Replace the in-flight updatedb and read PRUNEPATHS out of any quoting
The machines this targets are the ones with an updatedb already grinding through every snapshot, and `systemctl start` on an active unit is a no-op. updatedb reads /etc/updatedb.conf once at startup, so a run that began before the rewrite keeps burning CPU on the old config until it finishes. Restart the service instead: it's Type=oneshot and plocate builds into a temp db, so nothing is lost by replacing the run. Quotes are optional in updatedb.conf, so parse the existing paths out of whatever quoting the file uses and write the setting back in one canonical form. `PRUNEPATHS=/tmp` previously fell through to the append branch and got a second PRUNEPATHS line, which drops /tmp from the pruned set. Comparing whole paths rather than substrings also keeps a config that already prunes something like /var/lib/machines/.snapshots from being mistaken for one that prunes /.snapshots. Prefer $OMARCHY_PATH over the packaged copy when locating the config script, per docs/migrations.md, so the migration test exercises the checked-out script rather than whatever release is installed. Skip when neither exists: omarchy-migrate runs under set -e, so a missing script would take down every migration queued behind it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
8ef4eb24a2 |
Keep Btrfs snapshots out of the locate index and put /home in it
The stock Arch updatedb.conf interacts badly with Omarchy's Btrfs layout in both directions: - Snapper snapshots under /.snapshots are nested subvolumes reached by plain directory traversal, so updatedb indexes the entire system once per snapshot. On machines that accumulated snapshots this means multi-hour updatedb runs at full CPU, gigabytes of RAM, and a multi-gigabyte plocate.db (observed: 18 GB db, 7.5 h runs at 96% CPU with 592 snapshots; 43 MB and ~1 min after the fix). - PRUNE_BIND_MOUNTS="yes" treats Btrfs subvolume mounts like /home as bind mounts, so locate finds nothing in home directories at all. Configure updatedb.conf at install time and migrate existing installs, then rebuild the index in the background. Both settings are matched tolerantly and appended when absent, so a hand-edited updatedb.conf is fixed rather than silently skipped. |
||
|
|
5232505c12 |
Don't block the desktop on network-online at boot
graphical.target was gated on network-online.target: cups-browsed orders itself After=network-online.target and sits in multi-user.target, so the session waited for NetworkManager-wait-online (DHCP/Wi-Fi association) before coming up. On the bench VM that was ~140ms, but it's the classic multi-second boot stall on real Wi-Fi. Mask NetworkManager-wait-online.service so network-online.target is reached immediately and nothing in the boot waits for connectivity; NetworkManager still comes up and cups-browsed browses once the link is live. Mirrors the existing systemd-networkd-wait-online mask. Enabled at install (enable-services.sh) and masked on existing installs via migration. Verified on a fresh boot: the graphical.target critical chain no longer passes through network-online.target / NetworkManager-wait-online. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c048b2c745 | Normalize Snapper snapshot setup | ||
|
|
06db866467 | Prepare installer for ISO-owned finalization | ||
|
|
75cb4f7195 |
Make setup ISO-only
Remove legacy online installer entrypoints, collapse migrations for 4.0, and move setup responsibilities into target-side system, hardware, and user commands. |
||
|
|
b45e8464ef |
Move NVIDIA env setup to Hyprland Lua
Evaluate NVIDIA session env vars from default/hypr/nvidia.lua during Hyprland startup instead of appending them to each user's envs.lua during setup. This removes the per-user NVIDIA setup script execution while preserving the GSP/non-GSP detection. |
||
|
|
27f6d9d364 | migrations: keep system helpers sudo-compatible | ||
|
|
bf14f69017 | installer: require target user for system finalizer | ||
|
|
d12d449b03 | install: split and harden hardware config scripts | ||
|
|
6056f8800c | install: drop helpers replaced by package-owned config | ||
|
|
f451b504eb | install: route theme setup through split scripts | ||
|
|
e393a3a836 | install: centralize service enablement | ||
|
|
7ef5bc56fd | install: make system scripts root-finalizer aware | ||
|
|
0cfa1b66c4 | installer: route install through system and user phases | ||
|
|
53e2611507 | install: add split system and user targets | ||
|
|
b29747a54b | installer: reduce offline finalizer work | ||
|
|
a086b03dd1 |
Replace ~/.local/share/omarchy runtime paths with $OMARCHY_PATH
The git-era flow installed Omarchy to ~/.local/share/omarchy. In the package-based flow it lives at /usr/share/omarchy (or, in dev mode, at the path /etc/omarchy.conf's OMARCHY_PATH points at). Files that hard- coded the old path broke on package installs: - default/bash/rc: sourced ~/.local/share/omarchy/default/bash/*, so a fresh user's terminal logged ENOENT for every line. Now sources from $OMARCHY_PATH with /usr/share/omarchy as the safe default if the var is unset. - config/systemd/user/omarchy-recover-internal-monitor.service: ExecStart pointed at %h/.local/share/omarchy/bin/. The script ships to /usr/bin via the omarchy-installer package; point straight there. - install/config/xcompose.sh: wrote an XCompose include line pointing at the user-home path; use /usr/share/omarchy/ directly. - default/hypr/paths.lua and config/hypr/hyprland.lua: fallback when OMARCHY_PATH is unset is /usr/share/omarchy, not the home path. Dev-only scripts (omarchy-dev-add-migration, omarchy-reinstall-git) and the SKILL.md docs still reference the old path; those are separate cleanups since they don't affect a fresh install's runtime. |
||
|
|
f852edfbd6 |
Split user-level setup into bin/omarchy-setup-user
User-level files (~/.config, ~/.local/share, ~/.agents, etc.) shouldn't
be written by install.sh — it runs as root or with system-level sudo,
and in offline (ISO chroot) mode the user doesn't exist yet. Moved into
a per-user idempotent command, called from omarchy-first-run.
Moved into bin/omarchy-setup-user (deleted from install/config/):
- omarchy-ai-skill.sh AI skill symlinks
- omarchy-toggles.sh hypr toggle flags
- nautilus-python.sh nautilus extensions
- branding.sh ~/.config/omarchy/branding/{about,screensaver}.txt
- user-dirs.sh xdg-user-dirs-update + gtk bookmarks
- detect-keyboard-layout.sh layout/variant sed into ~/.config/hypr/input.lua
- toggles.sh ~/.local/state/omarchy/toggles mkdir
- mimetypes.sh omarchy-refresh-applications + xdg-mime/xdg-settings
Kept in install/config/ (rely on OMARCHY_USER_NAME / OMARCHY_USER_EMAIL
that only exist during install):
- git.sh git config --global user.{name,email}
- xcompose.sh ~/.XCompose with name/email substituted
omarchy-setup-user:
- Refuses to run as root
- Idempotent via ~/.local/state/omarchy/setup-user.done marker
- --force escape hatch for re-running after dev-link or upstream changes
- Defaults OMARCHY_PATH to /usr/share/omarchy so it works outside install
bin/omarchy-first-run now invokes omarchy-setup-user unconditionally
(it self-gates), so first user login picks up the user setup.
install/config/all.sh: dropped the eight deleted entries.
All three packages (omarchy, omarchy-settings, omarchy-installer) still
build clean.
|
||
|
|
7fffc5f3c4 |
Simplify OMARCHY_INSTALL_MODE to online/offline only
Drop online-git: the new world has a single package-backed install path that's either online (pacman pulls from omacom-pkgs.org) or offline (ISO chroot pulls from the bundled mirror). The git-clone-and-run-installer path is gone — boot.sh becomes a thin bootstrap that installs the omarchy-installer package and invokes its installer. - install/helpers/mode.sh: two modes, validation message updated. Default fallback is 'online' (the boot.sh path); OMARCHY_CHROOT_INSTALL=1 still shims to offline, OMARCHY_ONLINE_INSTALL=true still shims to online. - install/preflight/all.sh: first-run-mode + disable-mkinitcpio gated on offline (offline is the from-scratch chroot path; online runs on an existing system). - install/preflight/pacman.sh: DELETED. boot.sh now handles repo config before install.sh runs. - install/packaging/all.sh: drop base.sh entirely. Both modes have base packages installed via omarchy-installer's depends before install.sh runs. base.sh remains on disk in case the ISO mirror build flow wants to invoke it directly. - install/helpers/chroot.sh, errors.sh, post-install/finished.sh, config/mise-work.sh: rename mode checks to use online/offline. |
||
|
|
6f74091fb6 |
Make install.sh mode-aware with OMARCHY_INSTALL_MODE
Three modes the installer now branches on:
iso-chroot Running inside the new system's chroot from the ISO build.
pacman is configured by archinstall; systemd isn't running,
so service enables skip --now.
online-package Running on an existing Arch where the omarchy-* packages
are already installed. Skip base.sh and the bootstrap
preflight steps; only the per-host runtime ops in
config/login/post-install need to run.
online-git boot.sh path: clone into $HOME/.local/share/omarchy and
bootstrap everything from scratch.
install.sh derives OMARCHY_PATH from its own location, so the same script
works whether it's at /usr/share/omarchy/install.sh (package mode) or
$HOME/.local/share/omarchy/install.sh (git mode). install_mode_is helper
replaces direct ${OMARCHY_CHROOT_INSTALL:-} / ${OMARCHY_ONLINE_INSTALL:-}
checks in chroot.sh, finished.sh, errors.sh, mise-work.sh, preflight/pacman.sh.
Legacy vars still work through export_legacy_mode_flags, which sets
OMARCHY_CHROOT_INSTALL=1 / OMARCHY_ONLINE_INSTALL=true based on the
canonical mode for any caller that hasn't been updated.
bin/omarchy-install-mode prints the current mode for scripts/users that
need to introspect.
Smoke-tested all four entry paths (explicit mode, both legacy shims,
auto-detection from OMARCHY_PATH); each resolves correctly and the
legacy flags are exported in matching modes.
|
||
|
|
b887d18b84 |
Trim over-commented Chunk 3+/4 work
A pass over the install scripts, dev-tools commands, and Hyprland Lua files that I had stuffed with explain-everything preambles. Most of those rationales (which files ship where, why hyprctl setenv doesn't suffice, etc.) belong in commit messages or PR descriptions, not in code people have to read forever. Kept the few comments that document genuinely non-obvious behaviour: the keybind-env reason for hl.env in envs.lua, why the runtime PAM seds stay scripted in increase-lockout-limit, the chroot/--now distinction in chroot.sh, and the dev-pkg-test split-install reason. |
||
|
|
0ebbe34760 |
Add chrootable_systemctl_enable_only for services we shouldn't start during install
The previous centralization into enable-services.sh accidentally changed semantics for three services: docker.socket, iwd.service, and power-profiles-daemon.service used to be enabled with bare 'sudo systemctl enable' (no --now); chrootable_systemctl_enable promoted them to 'enable --now' outside chroot. For iwd this is the riskiest: it's typically what's keeping the installer online, so starting it mid-install is at best a no-op and at worst can disrupt the active network connection. For docker.socket and power-profiles-daemon the change is cosmetic (the socket is already inactive, the daemon does no harm to start) but the original intent was deferral to first boot. New helper in install/helpers/chroot.sh: chrootable_systemctl_enable_only <unit> # plain enable, no --now enable-services.sh uses it for the three services that were previously bare-enabled. The other five (bluetooth, cups, cups-browsed, avahi-daemon, linux-modules-cleanup) keep the --now behavior they had under chrootable_systemctl_enable. |
||
|
|
510636b8c9 |
Normalize hard-coded ~/.local/share/omarchy refs to $OMARCHY_PATH
The package-installed paths live at /usr/share/omarchy; the script-install
paths live at ~/.local/share/omarchy. $OMARCHY_PATH is set by install.sh
during the install flow and by /etc/profile.d/omarchy.sh in package mode.
Scripts that hard-code the script-install path don't honour that and will
misbehave once shipped to /usr/bin.
16 files migrated via sed s|~/\.local/share/omarchy|$OMARCHY_PATH|g
and s|$HOME/\.local/share/omarchy|$OMARCHY_PATH|g:
bin/:
- omarchy-plymouth-{preview,reset,set}
- omarchy-refresh-{limine,plymouth}
- omarchy-reinstall-configs
- omarchy-show-logo
- omarchy-games-retro-install
- omarchy-install-gaming-battlenet
install/:
- config/branding.sh
- packaging/{fonts,icons}.sh
- post-install/{finished,pacman}.sh
- preflight/{migrations,pacman}.sh
Deliberately NOT migrated:
- bin/omarchy-dev-add-migration: uses 'cd ~/.local/share/omarchy' to
resolve a git repo for 'git log'. The packaged binary doesn't have a
git repo to read; this command only makes sense in dev mode where
the home path is the right one.
- bin/omarchy-install-browser:69: writes a string into a chromium
config file that chromium itself interprets; not a bash-resolved path.
- install/helpers/errors.sh:125: the boot.sh-style relaunch behaviour
needs a separate redesign.
|
||
|
|
12826d4076 |
Centralize service enables into install/config/enable-services.sh
The previous setup scattered systemctl enables across docker.sh,
printer.sh, bluetooth.sh, network.sh, powerprofilesctl-rules.sh, and
kernel-modules-hook.sh. Some used chrootable_systemctl_enable; others
used bare 'sudo systemctl enable'. Centralizing makes the install-time
service surface auditable in one place and consistent in chroot/non-chroot
behavior.
install/config/enable-services.sh enables:
- bluetooth.service
- cups.service, cups-browsed.service, avahi-daemon.service
- docker.socket
- iwd.service
- linux-modules-cleanup.service
- power-profiles-daemon.service
Each via chrootable_systemctl_enable, which uses 'enable --now' on a live
system and bare 'enable' in chroot (set OMARCHY_CHROOT_INSTALL=1).
Stays in original script (deliberately):
- sddm.sh: bare 'systemctl enable sddm.service' (no --now during install
would log the user out; lives in install/login/)
- limine-snapper.sh: limine-snapper-sync (bootloader-specific path)
- first-run/firewall.sh: ufw (deferred to first-run for UX)
- hardware/{t2,intel/lpmd,intel/thermald,apple/fix-suspend-nvme}: gated
on hardware detection
Side cleanups:
- install/config/kernel-modules-hook.sh: DELETED (sole line was the enable
for linux-modules-cleanup, now in enable-services.sh).
- install/config/hardware/printer.sh: DELETED (sole purpose was the
three cups/avahi enables; nothing else to do).
- install/config/hardware/network.sh: keep the systemd-networkd-wait-online
disable+mask; drop the iwd enable.
- install/config/hardware/bluetooth.sh: keep the AutoEnable=false sed and
the wireplumber/bt-agent user-session setup; drop the system enable.
- install/config/docker.sh: drop the docker.socket enable.
- install/config/powerprofilesctl-rules.sh: drop the
power-profiles-daemon enable.
- install/config/all.sh: register enable-services.sh; remove the two
deleted entries.
|
||
|
|
080c8ba38c |
omarchy-wifi-powersave: nullglob; plocate drop-in daemon-reload; idempotent legacy cleanup
- bin/omarchy-wifi-powersave: shopt -s nullglob. Previously, machines
with no wireless interfaces ran the loop once with the literal glob
('iface=*'), failed iw, and exited 237. With the new always-installed
udev rule that invokes this on every AC transition, the failure
would surface as failed transient omarchy-wifi-powersave-* units on
desktops. Now it cleanly no-ops.
- migrations/1779307845.sh: add 'systemctl daemon-reload' so the
plocate-updatedb.service.d/ac-only.conf drop-in is picked up on
upgrade. Arch's systemd pacman hook only triggers on
/usr/lib/systemd/system/*, not /etc/systemd/system/*.
- install/config/powerprofilesctl-rules.sh and wifi-powersave-rules.sh:
rm -f the pre-rename legacy paths before udevadm reload, so the
cleanup is idempotent outside the one-shot migration (matters for
re-install/downgrade testing).
|
||
|
|
dcac0ed953 |
Convert plocate-ac-only, power-profile, wifi-powersave, unmount-fuse to package files
Four scripts that wrote static /etc or /usr files become package-shipped files. The other config-script audit candidates (omarchy-ai-skill, nautilus-python, omarchy-toggles, input-group) correctly stay scripts — they're user-level operations, not /etc writes. New package-owned files (omarchy-installer/etc/, shipped by omarchy-settings): - etc/systemd/system/plocate-updatedb.service.d/ac-only.conf - etc/udev/rules.d/99-omarchy-power-profile.rules - etc/udev/rules.d/99-omarchy-wifi-powersave.rules The two udev rule files are renamed for namespacing (99-power-profile -> 99-omarchy-power-profile; 99-wifi-powersave -> 99-omarchy-wifi-powersave) and rewritten to invoke /usr/bin/omarchy-powerprofiles-set and /usr/bin/omarchy-wifi-powersave instead of $HOME/.local/share/omarchy/bin/... (both binaries ship in the omarchy package at /usr/bin/). The battery-present gate from the original scripts is dropped — the rules trigger on power_supply udev events, which are benign on desktops without batteries. (The runtime commands no-op on AC-only systems.) Script changes: - install/config/plocate-ac-only.sh: DELETED (file ships, daemon-reload happens via pacman hook). - install/config/unmount-fuse.sh: DELETED (file ships at /usr/lib/systemd/system-sleep/unmount-fuse via omarchy-settings). - install/config/powerprofilesctl-rules.sh: SHRINK to runtime ops (enable power-profiles-daemon, udevadm reload+trigger). - install/config/wifi-powersave-rules.sh: SHRINK to udevadm reload+trigger. - install/config/all.sh: drop the two deleted entries. bin/omarchy-update-system-pkgs: add --overwrite for plocate-updatedb drop-in and unmount-fuse paths (the udev rule renames need no overwrite since the new paths are virgin). migrations/1779307845.sh: remove the legacy 99-power-profile.rules and 99-wifi-powersave.rules paths on existing installs, then reload udev. |
||
|
|
5683750b29 |
Add pacman --overwrite for transition paths; fix mimeapps/HEY and PAM idempotency
Four corrections to the omarchy-settings transition: - bin/omarchy-update-system-pkgs: pass --overwrite for the 13 paths omarchy-settings now owns. Existing Omarchy installs would otherwise fail pacman conflict checks on the upgrade that ships the package (the files exist as unowned filesystem entries from the previous install scripts). The flags are no-ops once the transition release is everyone's baseline; remove then. - config/mimeapps.list: drop the HEY.desktop mailto mapping. HEY.desktop is generated by install/packaging/webapps.sh at install time, not shipped under applications/, so it isn't valid for a fresh /etc/skel user before the installer runs. - install/config/mimetypes.sh: add 'xdg-mime default HEY.desktop x-scheme-handler/mailto' as a runtime op since the mapping no longer lives in mimeapps.list. - install/config/increase-lockout-limit.sh: delete existing pam_faillock.so authsucc lines before re-adding, so re-running the installer doesn't duplicate the authsucc entry in /etc/pam.d/sddm-autologin. |
||
|
|
89242fafc6 |
Ship mimeapps.list via /etc/skel; shrink mimetypes.sh
config/mimeapps.list ships at /etc/skel/.config/mimeapps.list (via omarchy-settings's existing config/** -> /etc/skel/.config copy). New users get the full Omarchy MIME defaults on first login without running install scripts. install/config/mimetypes.sh shrinks to two runtime ops that a static file can't replace: - omarchy-refresh-applications: copies .desktop entries and icons into the user home and refreshes the desktop database - xdg-settings set default-web-browser chromium.desktop: sets the system-default browser; omarchy-install-browser overrides this if the user later picks a different browser. |
||
|
|
993e6a0812 |
Shrink printer.sh to service enables only
The three /etc writes (resolved.conf.d drop-in, nsswitch.conf override, cups-browsed.conf override) now ship via omarchy-settings. The service enables stay scripted because they need chrootable_systemctl_enable to work both inside the ISO chroot and on a live system. |