Arch Installation
lyona is Arch Linux-only. Arch Linux with Xorg is required for every supported installation, package, test, and release path.
Install from the image
For a new, dedicated machine, with UEFI or a legacy BIOS. It installs GRUB, with the CyberRe boot menu theme, and the lyona boot splash.
-
Download the newest image,
lyona-VERSION-x86_64.iso, and itslyona-VERSION-SHA256SUMSfrom the Releases page. Images are pre-releases while lyona is in beta. Check the download, in the folder that holds both:sha256sum -c lyona-VERSION-SHA256SUMS --ignore-missingThe file also lists the source archive;
--ignore-missingskips it when you did not download it.Releases from
2026.10.0-beta.2on are signed. Withcosign, and the release’slyona-VERSION.sigstore.jsonbeside the image, check that it was built by lyona’s own release workflow:cosign verify-blob-attestation --bundle lyona-VERSION.sigstore.json \ --type https://slsa.dev/provenance/v1 \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ --certificate-identity https://github.com/technicks89/Lyona/.github/workflows/build-iso.yml@refs/heads/main \ lyona-VERSION-x86_64.isoLogged in to the GitHub CLI,
gh attestation verify lyona-VERSION-x86_64.iso --repo technicks89/Lyonachecks the same.Or build one yourself (see Releasing).
-
Write it to a USB stick, which erases the stick. Replace
/dev/sdXwith the stick, aslsblkshows it:sudo dd if=lyona-VERSION-x86_64.iso of=/dev/sdX bs=4M status=progress oflag=sync -
Boot it. The
lyona-installwizard starts on its own. It checks the network first. With no wired connection and a Wi-Fi card, it offers to connect to Wi-Fi. It lists the networks it finds, with signal strength and security, plus Other (hidden network), and asks for the passphrase. Open and WPA personal networks are supported, but enterprise (802.1X) and WEP networks aren’t. The new system keeps the connection, so its first boot is online. If a Wi-Fi chip has no driver on the image (some Broadcom chips in older Macs needbroadcom-wl), the wizard says so; install over a cable or USB tethering instead. Then it asks:- the keyboard layout, from a list you can type in to search (for example
“German” or
fr). It applies at once, so the passwords you type next use it, as they will at the disk-encryption prompt and the login screen; - the disk to install to, which it erases;
- the filesystem: btrfs (the default) or ext4, either optionally encrypted with LUKS, which then asks for the encryption password;
- your user name and password, and the hostname. Your user administers the
machine with
sudo; root has no password and cannot log in. A system that will not boot is repaired from the live medium (arch-chroot), as systemd’s emergency shell needs root’s password; - the timezone: it asks first whether to detect it online (that sends your IP address to ipinfo.io or ipapi.co), then lets you confirm or change it;
- the package mirrors: those in your timezone’s country, or worldwide for a
zone with no country such as
UTC. Choose another country, or worldwide, when you are installing somewhere else. The fastest of them, measured from your machine, are ranked before anything is downloaded, and the new system keeps the list. When too few mirrors are in the country, worldwide ones are added; when they cannot be ranked (no network, or it takes more than 30 seconds), the medium’s own list is used; - the Wi-Fi country is not asked: it is the timezone’s country, shown on
the summary, and the new system’s Wi-Fi uses that country’s channels and
power limits from the first boot. A zone with no country, such as
UTC, sets none, and Wi-Fi follows the country the access point names; - on an NVIDIA GPU, the driver: the proprietary driver, recommended when it supports the card (a legacy branch for an older card), or the open-source nouveau.
In the timezone and country lists, Esc goes back to the question before them (with no detected timezone, it asks whether to choose one or cancel). It shows a summary, mirrors included, where Change an answer… asks any one question again (a new keyboard layout asks for the passwords again too), and nothing is written until you choose Wipe DISK and install. Cancelling at any point changes nothing; run
lyona-installto start again. - the keyboard layout, from a list you can type in to search (for example
“German” or
-
It installs on its own: Arch with
archinstall, then lyona’s full profile as your user, the CachyOS repositories and thelinux-cachyoskernel (normally the only kernel; see “CachyOS repositories and kernel” below), and Topgrade. A progress bar shows each step. If something did not go as chosen (a driver that could not be installed, for example), the last screen lists it and waits for Enter; otherwise it reboots after 15 seconds. Leave the USB stick in until then; if the installer starts again instead of lyona, remove it and restart. The full log is/var/log/lyona-postinstall.logon the new system. It gives each step’s start and duration, and ends with a table of where the install’s time went, archinstall included.
If a step fails, a menu offers to retry it, show the log, or drop to a shell,
and says what state the machine is in. If archinstall fails, Retry runs
it again with your answers; the disk may already be erased by then.
Without the wizard (partitioning of your own): run archinstall
yourself from the live medium, then /root/lyona-postinstall.sh to install
lyona onto it.
Boot splash
An image install boots with the lyona splash, the one the install medium boots with: the logo on the theme’s background, drawn by Plymouth. On an encrypted disk it is also where you type the encryption password, in a box under the logo, with the keyboard layout you chose. With the splash, the desktop’s login screen comes up about a tenth of a second later (measured in a VM).
The install sets it up with:
- the
plymouthpackage, and the generated theme in/usr/share/plymouth/themes/lyona, selected in/etc/plymouth/plymouthd.conf; - the
plymouthhook in/etc/mkinitcpio.conf, afterudevand so beforeencrypt; splashon the kernel command line, added by/etc/default/grub.d/90-lyona-splash.cfgrather than an edit of/etc/default/grub.
If any of it fails, the install puts the hooks back, says so on its last screen, and the system boots without the splash.
To turn it off, delete the drop-in and the hook, then rebuild the initramfs and the GRUB menu:
sudo rm /etc/default/grub.d/90-lyona-splash.cfg
sudo sed -i -E '/^HOOKS=/ s/ plymouth([ )])/\1/' /etc/mkinitcpio.conf
sudo mkinitcpio -P
sudo grub-mkconfig -o /boot/grub/grub.cfg
sudo pacman -Rns plymouth # optional: its services also run without the splash
install.sh on an existing system does not add the splash.
Install on an existing Arch system
1. Clone
Everything below runs from the checkout:
git clone https://github.com/technicks89/Lyona.git lyona
cd lyona
2. Run the installer
The installer installs the packages, builds dwm, installs it and sets up your account, all from the checkout. See its plan first, then install:
./install.sh --dry-run
./install.sh
It installs the full profile unless you choose another with --profile:
core for the required build/X11/session packages and Alacritty,
recommended for the complete desktop layer, or full for optional extras
such as wallpapers and display-manager setup. On x86_64 Arch, full can also
install Steam, Gamescope, GameMode, and MangoHud after repository approval.
See Dependencies and Package Profiles for exactly which
packages each profile installs.
The installer separately asks before enabling the multilib repository for
Steam, Gamescope, GameMode, and MangoHud. Declining skips the gaming subset
without affecting other full-profile extras.
The script requires ID=arch before handling dependency installation, font
copying, display-manager integration, or config placement. Every other
operating-system identity is rejected before changes are made.
Existing user configuration and .xinitrc files are preserved. Upgrades remove
the known legacy dwm-graphical-session.service and
wm-graphical-session.service early-start configuration so XDG applications
start only after the X11 display environment is available; customized user
units are disabled from early startup but otherwise preserved.
System files are installed with sudo, while configuration and data under the
user’s XDG directories are installed as that user.
Time synchronization is on by default, in every profile. When no
other time service keeps the clock, the installer enables and starts
systemd-timesyncd, which comes with systemd, so nothing is downloaded for
it; the summary says so first. If chronyd, ntpd or openntpd is enabled or
running, it is kept and systemd-timesyncd is not enabled beside it, and a
masked systemd-timesyncd is left masked. Running the installer again changes
nothing. An image install has it from archinstall already. Once lyona has
seen it on, it records that in /var/lib/lyona/time-sync, so if you turn it
off later, in Settings or with timedatectl set-ntp false, running the
installer again leaves it off and says so. An existing install gets it
the next time the installer runs.
Every profile and Arch image defaults to Alacritty without Herdr. With the
explicit --install-herdr option, the repository downloads the official
https://herdr.dev/install.sh into an isolated staging directory and verifies
repository-pinned SHA-256 checksums for both that installer and its resulting
Herdr binary before copying it into ~/.local/bin. A checksum mismatch or
network failure leaves Alacritty usable and reports the Herdr failure. When the
codex or claude command is already available, the helper also runs Herdr’s
matching integration install command so native Codex and Claude Code sessions
can be restored. Integration failures are reported separately from binary
installation failures.
When matching vendor XDG entries exist for Picom, the polkit agent, or Light Locker, the installer copies each entry to the user autostart directory and adds only the dwm session exclusion. Original commands and vendor session guards remain intact, no entry is created when the vendor entry is absent, and existing user entries are preserved.
Installer package profiles are selected with DWM_INSTALL_PROFILE:
core: required build packages, X11/session runtime, and Alacritty. Herdr is skipped unless--install-herdris provided.recommended:coreplus the recommended desktop layer such as Quickshell, Picom, Feh, Dex, fonts, theming, screenshot, audio, Bluetooth control and tray tools, brightness tools, Flatpak, the GTK desktop portal, GNOME Keyring, which a display-manager login unlocks, the Thunar file manager (Super+E), and NetworkManager with the Wi-Fi regulatory database (wireless-regdb). NetworkManager is enabled only when no other network manager (systemd-networkd, iwd, ConnMan, dhcpcd or netctl) is in use, and starts at the next boot. Bluetooth (bluetooth.service, frombluez) is enabled and started when the unit is installed, unless it is masked. The installer does not set your Wi-Fi country on an existing system; when none is set it says how to (see Troubleshooting). It also installs Celluloid, mpv, and sxiv, and gives a fresh account Celluloid for audio and video and sxiv for images throughscripts/seed-default-apps.sh, which also makes Thunar the folder handler when Thunar is installed. An existing MIME preference file is never replaced; change these in Settings > Defaults when updating an existing account. It makeslyona-appimagethe AppImage handler unless another is set (see below), and installs the available Arch GTK theme packages. A matching GTK theme is generated for every palette inconfig/themes.toml, so GTK applications follow the active theme without a downloaded theme pack. It also installs the mybash shell configuration: a Starship prompt, Fastfetch,fzfandzoxide, cloned into~/.local/share/mybashand linked from~/.bashrc,~/.config/starship.toml,~/.config/fastfetch/config.jsonc, and~/.local/bin/starship-theme. Any of those files that was there before is kept beside it, as for example~/.bashrc.bak.20261003-142501; re-running the installer leaves links that are already in place alone. Those links point into the checkout, so editing~/.bashrcedits the checkout: running the installer again updates a checkout without changes to the reviewed mybash version in place, and leaves one with your edits as it is. Offline, the existing checkout is kept.- Topgrade. It also installs Topgrade,
which updates everything with one
topgradecommand. Topgrade is only in the AUR on Arch, so the installer builds the AUR’stopgrade-binpackage, which repackages upstream’s release binary, withmakepkgand installs it withpacman. It takes seconds and needs no Rust toolchain. - What is trusted: the PKGBUILD is pinned to a reviewed AUR commit, and
every file it downloads has a checksum.
makepkgruns as you, never as root; only the built package is installed withsudo pacman -U. Seedocs/AUR-PACKAGES.md. - When: it is installed last, after every other step that needs
sudo. Thesudotimestamp is closed first, sosudoasks for your password again to install the built package. If it fails, the install carries on. - If it cannot be built (the AUR or GitHub unreachable, say), the
install says so and carries on; run
install-topgradelater to try again. - Updates:
pacman -Syudoes not update AUR packages. Topgrade updates itself, throughyay, each time it runs. - Skipping it: pass
--skip-topgrade(or setDWM_INSTALL_TOPGRADE=false). - Later, or on an existing install: run
install-topgrade(orscripts/install-topgradefrom the checkout). It does nothing when a Topgrade package is already installed;install-topgrade --forcereinstalls it, and--dry-runshows what it would do. - Upgrading from a cargo-built Topgrade: an older lyona built Topgrade
with cargo into
~/.cargo/bin, which comes before the package onPATH.install-topgradeoffers to remove it when run in a terminal, and otherwise says how:cargo uninstall topgrade. Nothing removes it silently. lyona no longer installsrustuporcargo-update; if you have no other use for them, remove them withsudo pacman -Rns rustup cargo-update.
- Topgrade. It also installs Topgrade,
which updates everything with one
full:recommendedplus optional extras such as wallpapers, display-manager setup,rsyncandautorandr. x86_64 Arch full installs also include Steam, Gamescope, and 64-bit and 32-bit GameMode and MangoHud support after separate repository approval. The installer enables themultilibrepository for Steam, Gamescope, GameMode, and MangoHud, and installs them, with this machine’s Vulkan drivers, in the same transaction as everything else. It then adds the invoking user to thegamemodegroup; log out and back in before using its privileged tuning helpers.
The default is full to preserve the historical automated installer behavior.
The installer installs every package of the chosen profile in one pacman -Syu --needed transaction, so it also upgrades the system, as installing on an
out-of-date Arch system should, never leaving a partial upgrade. Packages already
installed are left alone, so re-running it is safe. The gaming packages are in
the same transaction: multilib is enabled first, once you approve it, and the
transaction syncs it with the other repositories.
- A package missing from the repositories: an optional one (
maim, a GTK theme,qt6ct, Firefox and so on) is left out with a warning, and the transaction is retried once without it. Withoutmaim, for example, the screenshot hotkeys stay disabled. - A required one (the build tools, X11, the session’s runtime and the desktop itself) stops the install before anything of lyona’s is installed.
- Interactive runs let
pacmanask before it installs;--non-interactiveruns it with--noconfirm.
For a minimal install:
DWM_INSTALL_PROFILE=core ./install.sh
The same profile can be selected with a flag:
./install.sh --profile core
Interactive runs print the resolved package plan before prompting. For CI, packaging checks, or scripted validation, use the non-interactive flags:
./install.sh --dry-run --non-interactive --profile core
./install.sh --non-interactive --yes --profile recommended
./install.sh --non-interactive --yes --profile full --enable-arch-gaming-repos
./install.sh --non-interactive --yes --profile full --cachyos-kernel
A non-interactive run cannot type a password, so it installs yay only where
sudo needs none; otherwise it says so in its summary and its closing warnings,
and install-yay adds yay later from a terminal.
dwm build settings. A new config.h uses config.def.h’s defaults: the
monitor’s refresh rate, font size 12, Super as the modifier, and the usual
layout. To choose them, add --configure-build. The installer then asks
before its summary, and asks again when an answer isn’t valid. Your answers
become config.h only once you accept the summary. Unattended, set
DWM_REFRESH_RATE, DWM_FONT_SIZE, DWM_MODKEY and the other values in
scripts/configure-build.sh --help. An existing config.h is always kept.
Without --enable-arch-gaming-repos, unattended Arch full installs skip
Steam, Gamescope, GameMode, and MangoHud rather than changing repository trust.
An already-enabled multilib counts as approval, since nothing in
pacman.conf has to change – this is what installs from the lyona ISO get,
because the ISO ships multilib enabled.
AppImages
Opening an AppImage file, for example from Thunar or your browser’s downloads,
asks first: Add and run, Add only or Cancel, with where it was
downloaded from when the browser recorded it. Only run programs you trust.
Closing the question is Cancel, and the file stays where it was. Run from a
terminal, lyona-appimage open FILE asks there instead.
Adding moves it to ~/Applications, makes it executable, and writes a launcher
entry with the name and icon from inside the AppImage. lyona-appimage reads
them with unsquashfs and never runs the file to do so. Add and run then
starts it; opening it again later just starts it, without asking. Take one out
again with lyona-appimage remove NAME (lyona-appimage list shows them): the
file goes to the trash, and its entry and icon are removed. fuse2 lets
the classic AppImages run, and both it and squashfs-tools come with the
recommended desktop.
Gear Lever is no longer installed by default: it needs about 1.7 GB of Flatpak
runtimes. Add --with-gearlever (or set DWM_INSTALL_GEARLEVER=true)
to install it from Flathub; it then opens AppImages instead, with in-place
updates and its own window. An existing
Gear Lever is kept, and stays the AppImage handler. If an earlier image install
left Gear Lever pending for the first login, the next install.sh run cancels
that unless --with-gearlever is given.
Flatpak prerequisites
The recommended and full profiles install the flatpak package. With
--with-gearlever, Gear Lever sets up the official Flathub remote for the
target user before it installs anything. The remote is verified, not just present: setup stops with an error
if a flathub remote points anywhere but https://dl.flathub.org/repo, has
signature verification disabled, or is disabled. If there is no flathub
remote it adds the official one and checks it again. Repeated setup keeps
existing apps and remotes, and an app that is already installed never needs the
remote, so it reports as installed even when the remote is not healthy.
After fixing a setup error, retry scripts/install-gearlever from the source
checkout. To prepare and verify only the user remote, run
scripts/dwm-flatpak-setup --user. If Flatpak is missing, rerun
./install.sh --profile recommended first.
CachyOS repositories and kernel
Installs from the lyona ISO get this automatically and are not asked about
it. The baseline CachyOS repository is added to the live medium before
archinstall runs (only that one: it needs no CachyOS pacman, so the live
medium is never half upgraded), and pacstrap fetches the base system as
CachyOS baseline builds. The postinstall then moves the new system to your
CPU’s level (v3 or v4) with lyona-cachyos raise-level, a full upgrade
that downloads the base packages a second time: about 340 MiB, under a minute
on a fast connection. A CPU at the baseline level skips that step; if it was
skipped for another reason, sudo lyona-cachyos raise-level does it later. The
installed system inherits the live medium’s pacman.conf along with the
CachyOS mirrorlists and keyring, and archinstall installs linux-cachyos as
the only kernel. If the CachyOS mirror cannot be reached,
the install continues on the stock Arch repositories, with the stock Arch
kernel, instead of failing. If the repositories can be reached again later in
the install, linux-cachyos is added then and made the default, and the stock
kernel stays beside it, in the boot menu.
To keep installs fast, there is one kernel, apart from that case, and no fallback initramfs. CPU microcode comes with the base system on real hardware, and the boot menu is generated once. Where the stock kernel was kept, it is also a way back: choose it in the boot menu.
Qt part way through an update. The CachyOS repositories come before Arch’s,
and can publish some Qt modules of a new release before the rest. pacman would
install the mix, and Quickshell would not start. install.sh checks the
installed Qt modules after its package transaction: when they are from
different Qt releases, it installs them again from Arch’s extra repository,
which publishes each release whole, and says so. A later pacman -Syu brings
back CachyOS’s builds once theirs is newer. The check covers installs only. If
the panel disappears after a system update, a mixed Qt is the likely cause:
update again once CachyOS has finished, usually within a day, or run
sudo pacman -S extra/qt6-base extra/qt6-declarative with every other installed
qt6-* module of that release.
If the new system does not boot, recover it from the install medium. Boot
it, press Ctrl+C at the installer’s first question, which cancels it and leaves
a root shell, and find the disk with lsblk. The installer made two partitions on it: the first is
/boot (the EFI system partition on UEFI, ext4 on legacy BIOS), the second is
the root filesystem. With the disk at /dev/sda (an NVMe disk’s partitions are
/dev/nvme0n1p1 and /dev/nvme0n1p2):
cryptsetup open /dev/sda2 root # only for an encrypted install; then use /dev/mapper/root below
mount /dev/sda2 /mnt # or: mount /dev/mapper/root /mnt
mount /dev/sda1 /mnt/boot
arch-chroot /mnt
To keep a second kernel or the fallback image for recovery, add them after
installing. The fallback image is set per kernel, in that kernel’s preset under
/etc/mkinitcpio.d/: linux-cachyos.preset, or linux.preset on an install
without the CachyOS repositories. The second kernel here is the CachyOS LTS
one; on an install without CachyOS, use linux-lts instead.
sudo pacman -S linux-cachyos-lts linux-cachyos-lts-headers # a second kernel (linux-lts linux-lts-headers without CachyOS)
sudo sed -i "s/^PRESETS=.*/PRESETS=('default' 'fallback')/" /etc/mkinitcpio.d/*.preset
sudo mkinitcpio -P # build every kernel's images
sudo grub-mkconfig -o /boot/grub/grub.cfg # list them in the boot menu
Installs from earlier images keep their linux-cachyos-lts, stock kernel and
fallback images; nothing removes them.
On an existing system, the installer can do the same, but both steps are opt-in and are never enabled by default:
./install.sh --profile full --enable-cachyos-repos
./install.sh --profile full --cachyos-kernel
--cachyos-kernel implies --enable-cachyos-repos. Interactive runs ask for
both separately; DWM_INSTALL_CACHYOS_REPOS=true and
DWM_INSTALL_CACHYOS_KERNEL=true are the environment equivalents.
Adding the repositories imports and locally signs the CachyOS signing key,
installs the CachyOS keyring and mirrorlists, replaces pacman with the
CachyOS build that understands the ISA-specific mirrorlists, adds the
repository set matching this CPU (znver4, x86-64-v4, x86-64-v3, or the
plain cachyos repository) above [core], and upgrades the system to the
optimized packages. pacman.conf is backed up first and restored if any step
fails.
The kernel step installs linux-cachyos and makes it bootable: GRUB configurations are regenerated, and systemd-boot installs
get a copy of the existing loader entry pointing at the new kernel image. Any
other bootloader is reported so the entry can be added by hand. The existing
kernel is left installed and bootable.
Kernel headers are only needed to build out-of-tree modules, so they are not
installed by default. Pass --with-headers to lyona-cachyos install-kernel
to include them; they are also included automatically when DKMS is already
present, which is what the NVIDIA driver path relies on.
The same steps are available on their own afterwards:
lyona-cachyos status
lyona-cachyos add-repos # --no-upgrade to skip the system upgrade
lyona-cachyos raise-level # from the baseline repository to your CPU's level
lyona-cachyos install-kernel # --with-headers to include kernel headers
Herdr is skipped for every profile unless --install-herdr or
DWM_INSTALL_HERDR=true is provided. Its published Linux binaries support
x86_64 and aarch64. Installation alone does not change the terminal default;
set DWM_HERDR=1 and run dwm-terminal to enter the optional workspace.
Herdr can also be installed or repaired separately:
install-herdr
install-herdr --force
Upgrades preserve an existing hotkeys.toml. If an earlier installer seeded
its terminal variable to dwm-terminal, set it to alacritty to adopt the
current direct-terminal default. The installer does not overwrite that
user-owned choice.
Updates reach existing accounts
install.sh and lyona-update (through make install-user) both run
scripts/lyona-reconcile-user, so an updated account gets the same per-user
changes as a fresh install of the same profile. Running it again changes
nothing.
- The install profile is recorded in
${XDG_STATE_HOME:-$HOME/.local/state}/lyona/install-profile. An account installed before it was recorded counts asrecommendedwhen Quickshell is installed,coreotherwise. recommendedandfull: the browser, media and image defaults for an account with none yet, andlyona-appimageas the AppImage handler unless another is set.- Every profile: a key binding in
~/.config/lyona/hotkeys.tomlthat is still exactly an earlier release’s default is moved to this release’s, for example the raw Quickshell IPC calls tolyona-shelland Super+Shift+Q to the logout that asks first. A line you changed is never touched, the previous file is kept ashotkeys.toml.bak.DATE, and a symlinked file is left alone. The old defaults are listed inscripts/hotkeys-migrations.
An AUR helper (yay) is installed for you as a standing convenience tool, by
scripts/install-yay, the one script that builds it (the image installs it the
same way, before anything has passwordless sudo, and passes --skip-yay to
install.sh; a non-interactive run installs it only where sudo needs no
password, and install-yay from a terminal adds it later), independent of the package profiles above — none of the
required, recommended, or optional packages need it, since everything the
installer selects is available directly through official pacman repos
(core/extra/multilib). Lyona limits the AUR to where it is needed: today,
this yay helper, Topgrade’s pinned topgrade-bin, the live medium’s driver
for an older NVIDIA card, and the yay -Syu that Settings -> System ->
Update packages runs for you (see docs/AUR-PACKAGES.md).
GRUB boot menu theme
The installer ships the CyberRe GRUB theme and selects it by default on
machines that boot with GRUB, so the boot menu matches the rest of the
desktop instead of the stock text list.
Installing the theme files (make install-system) changes nothing about
booting — they are just data under /usr/share/grub/themes/CyberRe.
Selecting the theme is a separate step, because it edits the bootloader:
/etc/default/grubis copied to/etc/default/grub.lyona-backup-<timestamp>before the first edit.GRUB_THEMEis pointed at the installed theme.GRUB_TERMINAL_OUTPUTis commented out if present. GRUB draws themes only ongfxterm, so aconsolesetting would leave the theme installed and invisible.GRUB_GFXMODEis set toautoif it is not already set, since the 640x480 fallback letterboxes the theme’s 1920x1080 background./etc/default/grub.d/90-lyona-menu.cfgsetsGRUB_DISABLE_BOOTNEXT=true. Since GRUB 2.16, every firmware boot entry (the firmware’s boot manager, a DVD drive, network boot) otherwise gets its own top-level... (EFI BootNext)menu entry. This is a drop-in file, so/etc/default/grubisn’t edited for it. If you setGRUB_DISABLE_BOOTNEXTin/etc/default/grub, your setting is kept. If you set it after the drop-in was written, the nextapplyremoves the drop-in. A file at that path that isn’t lyona’s copy is never replaced.grub-mkconfigregenerates/boot/grub/grub.cfg.
Every one of those is printed as it happens. Replaced lines are commented out rather than deleted, so the previous values stay readable in the file next to the backup.
The lyona image’s own installs boot with GRUB, so they get the theme. Machines that do not boot with GRUB are reported and left completely alone. A theme step that fails does not fail the install.
Skip the bootloader edit with --skip-grub-theme (or
DWM_INSTALL_GRUB_THEME=false); the theme files are still installed, so it
can be selected later.
Manage it afterwards with:
lyona-grub-theme status # detected bootloader and selected theme
lyona-grub-theme list # installed themes
lyona-grub-theme apply # select CyberRe (or apply <name>)
lyona-grub-theme remove # back to the default GRUB appearance and entries
The theme is vendored from ChrisTitusTech/bootloader-themes (MIT) so it is available during an offline install.
Starting the session
Display manager (SDDM, GDM, LightDM): log out and select lyona from the session list (its file is /usr/share/xsessions/dwm.desktop).
When the interactive installer runs inside an active X11 session, it offers
the dwm-display-setup wizard after installation. The wizard previews the
chosen resolution and multi-monitor layout, then installs a backed-up Xorg
fragment. Installations run from a TTY or in non-interactive mode defer this
step; after the first X11 login, run:
dwm-display-setup
The installed Settings display provider is machine-oriented. Its actions are:
dwm-settings-display discover
dwm-settings-display watch OWNER_PID OWNER_START
dwm-settings-display save NAME SPEC...
dwm-settings-display preview TOKEN SECONDS SPEC...
dwm-settings-display preview-profile TOKEN SECONDS NAME
dwm-settings-display keep TOKEN [NAME]
dwm-settings-display apply-kept
dwm-settings-display revert TOKEN
dwm-settings-display discard TOKEN
dwm-settings-display preview-status [TOKEN]
dwm-settings-display install-profile NAME
dwm-settings-display rollback-system
dwm-settings-display dpi-set VALUE
dwm-settings-display dpi-reset
dwm-settings-display dpi-apply-saved
Discovery and live previews require xrandr, and the hotplug watch requires
udevadm. Persistent install and rollback additionally require pkexec plus
the root-owned helper installed at ${PREFIX}/libexec/lyona/. Profiles are
stored under
${XDG_CONFIG_HOME:-$HOME/.config}/lyona/display-profiles/. No move is
needed for profiles created by dwm-display-profile, which uses the same
directory. If DWM_DISPLAY_PROFILE_DIR previously pointed elsewhere, either
keep that environment override or move those .conf files into the default
directory before using Settings.
The input provider exposes the corresponding session actions:
dwm-settings-input discover
dwm-settings-input watch OWNER_PID OWNER_START
dwm-settings-input watch-apply
dwm-settings-input apply-saved
dwm-settings-input preview TOKEN SECONDS DEVICE SETTING VALUE
dwm-settings-input keep TOKEN
dwm-settings-input revert TOKEN
dwm-settings-input preview-status [TOKEN]
dwm-settings-input reset DEVICE SETTING
All input actions require xinput; keyboard layout and modifier operations
also require setxkbmap; stable hardware identity and hotplug watching use
udevadm, and the session watcher uses flock from util-linux to prevent
duplicate replay workers. Kept values default to
${XDG_CONFIG_HOME:-$HOME/.config}/lyona/input-settings.conf. Set
DWM_INPUT_SETTINGS_FILE to use a different file. The normal session startup
invokes apply-saved idempotently and runs watch-apply to debounce input
hotplug events before replaying saved values for returning devices.
startx:
startx
The provided .xinitrc only runs dwm inside a D-Bus session
(dbus-run-session). Everything else, the panel, the wallpaper and the power
settings among it, is dwm’s own session startup (autostart.sh), the same as
from a display manager.
Minimal Session Profile
The minimal supported profile is useful for lean Arch systems, recovery sessions, and minimal Arch qualification. It keeps only:
- an X11 server and either a display-manager session or
startx - D-Bus session support
dwm- Alacritty as the default terminal, with
dwm-terminalavailable to delegated tools that require fallback selection - required X11 helpers used by core startup and display commands, such as
xrandr,xset, andxsetroot
Quickshell, Picom, Feh, Dex, a polkit agent, screenshot tools, wallpapers, tray
utilities, and audio or brightness helpers are optional in this profile.
Missing optional components should appear as degraded features in
dwm-diagnostics, not as session-fatal failures.
For startx, a minimal .xinitrc can be:
#!/bin/sh
xset s off
xset -dpms
xsetroot -cursor_name left_ptr
exec dbus-run-session dwm
If the login path already creates a user D-Bus session, use exec dwm
instead of wrapping it with dbus-run-session.
After installation, verify the profile with:
dwm-diagnostics
dwm-terminal --print-command
dwm-diagnostics must report zero required failures before treating the
minimal profile as ready. Optional degraded features can remain unresolved.
The default binding opens Alacritty directly. A plain dwm-terminal also opens
the selected emulator directly unless DWM_HERDR=1 explicitly enables Herdr.
Commands such as dwm-terminal -e sh -c 'command' always bypass Herdr.
Dependencies and Package Profiles
lyona supports Arch Linux only. Every package it installs comes from one map,
scripts/dwm-packages.sh, so the installer, the install ISO, CI and this page
cannot disagree about a name. tests/test-arch-packages.sh fails if a package in
the groups below is missing from this page.
List any group yourself:
source scripts/dwm-packages.sh
dwm_packages arch required
Group names that are not listed print nothing.
Installer profiles
install.sh --profile (or DWM_INSTALL_PROFILE) takes three values, described in
Installation:
| Profile | What it installs |
|---|---|
core | required, plus Alacritty. |
recommended | core, plus the recommended group. |
full (the default) | recommended, plus the optional and gaming groups. |
The groups are made of smaller groups:
| Group | Made of |
|---|---|
required | build + x11 + runtime-required |
recommended | desktop + browser + media + system-management + screenshot-optional + theme + theme-gtk + fonts + shell |
optional | theme-optional + desktop-optional + system-management-optional |
full | required + recommended + optional + gaming |
The optional and gaming additions in full are conveniences. Picom is part of
the recommended desktop, since the overview’s window previews need it. Still, dwm
depends on none of these: the desktop starts without Picom, a wallpaper, a file
manager or a preferred terminal, and without Picom the overview shows icon-and-title
cards.
Groups
Each group below lists its packages exactly as the map prints them.
build
Compilers and the X11 development libraries that build dwm.
gcc make pkgconf base-devel libx11 libxft libxinerama libxrender imlib2 libxcb xcb-util freetype2 fontconfig
x11
The Xorg server, xinit, and the X tools the session and Settings call (xrandr, xrdb, xset, xinput, setxkbmap), plus xsettingsd, which broadcasts theme, cursor and DPI to running toolkits.
xorg-server xorg-xinit xorg-xrandr xorg-xrdb xorg-xset xorg-xsetroot xorg-xinput xorg-setxkbmap xsettingsd
runtime-required
What a running session needs: D-Bus, xdotool and xprop (the Quickshell state bridge), clipboard access, git, and the usual process and archive tools.
dbus curl git procps-ng psmisc unzip util-linux xclip xdotool xorg-xprop xdg-utils
desktop
The managed shell and the desktop around it: Quickshell, Picom, Feh, Dex, the polkit agent, audio (PipeWire, WirePlumber, pavucontrol), brightness, notifications, Bluetooth, power, Flatpak, the GTK desktop portal, AppImages, the login keyring, the signature check of lyona’s own updates, the Thunar file manager and NetworkManager.
quickshell picom python feh dex mate-polkit alsa-utils brightnessctl inotify-tools jq libpulse pipewire pavucontrol pipewire-pulse wireplumber libnotify light-locker xf86-input-libinput bluez bluez-utils blueman playerctl upower power-profiles-daemon flatpak xdg-desktop-portal-gtk pciutils gum cosign xorg-xmessage fuse2 squashfs-tools gnome-keyring pacman-contrib thunar gvfs gvfs-smb tumbler thunar-archive-plugin file-roller xdg-user-dirs networkmanager wireless-regdb iw
Thunar with SMB browsing, archives and thumbnails (the file-manager group) is what Super+E opens. BlueZ (bluez) is what the panel’s and Settings’ Bluetooth read; the installer enables and starts bluetooth.service when the unit is installed and not masked, and the image installer enables it on the new system. NetworkManager (the network group) is what the panel’s network status and Wi-Fi read; the installer enables it only when no other network manager (systemd-networkd, iwd, ConnMan, dhcpcd, netctl) is in use, and it starts at the next boot. Without it the panel says “NetworkManager not installed” or “NetworkManager not running”. The group also installs wireless-regdb, the kernel’s Wi-Fi regulatory database: without it Wi-Fi stays on the world domain, where 5 GHz connects slowly or not at all. iw, which it needs, also shows the Wi-Fi country (iw reg get).
fuse2 and squashfs-tools (the appimage group) are for AppImages: fuse2 runs the classic ones, which need libfuse.so.2 (the newer static-runtime ones run with Flatpak’s fuse3), and lyona-appimage reads an AppImage’s launcher entry and icon with unsquashfs, without running it.
cosign checks the Sigstore signature of each lyona release before lyona-update installs it. Without it, an update to a signed release is refused.
xorg-xmessage shows the one message the shell cannot: when a shell key finds the shell down and cannot start it again, since the shell is the notification server (#338).
gnome-keyring (the keyring group) stores secrets for browsers, NetworkManager and other applications. It includes pam_gnome_keyring.so, which Arch’s LightDM PAM stack already loads, so a password login unlocks the keyring; there is no separate PAM package. Under startx the keyring is unlocked on first use instead. dwm-diagnostics and System Health flag it when it is missing.
pacman-contrib (the update-indicator group) provides checkupdates, which the panel’s update icon counts pending package updates with. It never takes pacman’s lock.
browser
A web browser, for SUPER+B and the links other programs open. On a fresh account, seed-default-apps.sh makes it the default for web links and HTML pages only. Firefox also claims image, audio and video types, but those stay with sxiv and Celluloid. The installer skips it when your default https handler (xdg-mime query default x-scheme-handler/https) is another browser that’s already installed.
firefox
media
Celluloid, mpv and sxiv, which scripts/seed-default-apps.sh makes the defaults for audio, video and images on a fresh account.
celluloid mpv sxiv desktop-file-utils
system-management
What Settings > System reads: PackageKit and its Python bindings, AccountsService and CUPS.
python python-gobject packagekit accountsservice cups
screenshot-optional
maim, used by the screenshot hotkeys. The installer skips it, and says so, if it is not in the enabled repositories.
maim
theme
Icon themes and dconf.
dconf adwaita-icon-theme papirus-icon-theme
theme-gtk
The Arch GTK theme packages the installer installs when available; lyona also generates a GTK theme from every palette of its own.
adw-gtk-theme deepin-gtk-theme
fonts
Noto fonts and emoji, and MesloLGS Nerd Font, the terminal, bar and shell font
(the font-meslo profile).
noto-fonts-emoji noto-fonts ttf-meslo-nerd
shell
The shell add-ons the mybash configuration uses: Starship, zoxide, fzf, Fastfetch and friends.
starship zoxide fzf fastfetch bat tree trash-cli bash-completion
desktop-optional
rsync and autorandr. Every package is in the official repositories. The file manager and NetworkManager are in desktop.
rsync autorandr
theme-optional
qt6ct. With it installed, applying a theme points it at the palette lyona generates so Qt applications follow it. qt5ct, which the installer used to try when qt6ct was missing, is no longer installed; one you installed yourself is still pointed at the palette (docs/src/theming.md).
qt6ct
system-management-optional
The printer configuration tool and arch-audit.
system-config-printer arch-audit
gaming
Steam, Gamescope, GameMode and MangoHud, including the 32-bit builds. Needs the multilib repository.
steam gamescope gamemode lib32-gamemode mangohud lib32-mangohud
terminal
Alacritty and Kitty.
alacritty kitty
terminal-primary
Alacritty, the default terminal.
alacritty
lightdm
The LightDM display manager and its greeter.
lightdm lightdm-slick-greeter
iso
What the live install medium itself runs, on top of archiso’s releng
profile: the whole package list of the install image. The desktop is not on
it, as the new system downloads every package it installs.
plymouthdraws the boot splash;gumdraws the wizard, andjqwrites its credentials file;curlchecks the network, looks up the timezone and sets up the CachyOS repositories;opensslhashes the password, andpciutils(lspci) finds the GPU;reflectorranks the package mirrors in your country.
plymouth gum jq curl openssl pciutils reflector
qml-development
QML tooling for developing the shell: qt6-declarative (qmllint, qmltestrunner).
qt6-declarative
qml-validation
What CI needs to validate the QML: Quickshell and qt6-declarative.
quickshell qt6-declarative
Not installed by any profile
Continuous-integration groups (ci-smoke, ci-tools, ci-full) exist for the
project’s own test jobs and are not part of an install.
Repositories and the AUR
Every package above is in the official Arch repositories. Lyona limits the AUR to
where no official package can do the job (docs/AUR-PACKAGES.md, enforced by
make check-aur-policy). Today that is four places:
- the
yayhelperinstall.shinstalls for you; - Topgrade, built from the AUR’s pinned, reviewed
topgrade-binPKGBUILD, as Topgrade is only in the AUR; - on the live medium, an older NVIDIA card’s legacy driver, built from a pinned AUR PKGBUILD when the CachyOS repository cannot supply it;
- Settings -> System -> Update packages, which runs your own
yay -Syuwhenyayis installed.
Steam and its libraries need the multilib repository, which the installer enables only after
separate approval.
Getting Started
lyona is an Arch Linux-only X11 desktop. These instructions assume a supported Arch installation completed through the Arch install medium or
install.sh.
After installing, the first thing to know: Super = the Windows key.
Press Super + / at any time to open the interactive keybind viewer.
Essential Actions
| Action | Keys |
|---|---|
| Open Alacritty terminal | Super + X |
| App launcher (Quickshell) | Super + R |
| Close window | Super + Q |
| Power menu | Super + Ctrl + Q |
| Control Center | Super + F1 |
| Keybind viewer | Super + / |
Switching Tags (Workspaces)
Tags 1-9 act as workspaces. Use Super + a number from 1 through 9 to switch.
Super + 0 shows windows from all nine tags at once; 0 is not a tenth tag.
| Action | Keys |
|---|---|
| Switch to tag | Super + 1–9 |
| Move window to tag | Super + Shift + 1–9 |
| Show all tags | Super + 0 |
Layouts
Three layouts are available — switch between them instantly.
| Layout | Keys |
|---|---|
| Tiling (master + stack) | Super + T |
| Floating | Super + F |
| Monocle (one window at a time) | the Control Center; no default key |
The Control Center (Super + F1) has a Window layout row with all three:
the current layout is highlighted, and each tag keeps its own.
For one window rather than the whole layout: Super + M makes the focused
window fullscreen, and Super + Shift + M floats it, or tiles it again.
The window overview
Super + O shows every open window, on every tag and monitor, as a card with
a preview. The previews come from Picom, the compositor lyona starts at login;
without it the cards show each window’s icon and title instead. Type to narrow
the cards by title or class; Up, Down, Home and
End move the selection; Enter or a click goes to that window, on its tag;
Ctrl + W or a card’s close button asks the window to close, as Super +
Q would; Escape closes the overview. With more than one monitor, each card
says which monitor its window is on.
See Keybindings for the full reference.
Keybindings
Press Super + / inside dwm to open a live Quickshell keybind viewer.
MODKEY = Super (Windows key) in the shipped config.h.
Bindings are defined in ~/.config/lyona/hotkeys.toml and reload instantly on save — no recompile needed.
Launchers
| Keys | Action |
|---|---|
Super + R | App launcher (Quickshell) |
Super + O | Window overview: every window on every tag (Getting Started) |
Super + X | Alacritty terminal |
Super + E | File manager |
Super + B | Browser |
Super + / | Keybind viewer |
Super + F1 | Control Center |
Super + Alt + F1 | Control Center (the same, for keyboards where Super + F1 is taken) |
Super + Shift + W | A random wallpaper from ~/Pictures/backgrounds |
Super + Shift + R | Restart Quickshell |
Screenshots
| Keys | Action |
|---|---|
Super + P | Screenshot active monitor (cursor omitted) |
Super + Shift + P | Screenshot selection → file |
Super + Ctrl + P | Screenshot selection → clipboard |
All dwm-screenshot capture modes omit the mouse cursor.
maim region captures start selection immediately without a monitor chooser.
The active-monitor shortcut uses the monitor under the pointer. Clipboard
captures are PNG selections owned by xclip, while captures saved to disk use
JPEG. The lightweight capture flow intentionally has no annotation toolbar.
Applications and Web Apps
| Keys | Action |
|---|---|
Super + A | ChatGPT |
Super + Shift + A | Gemini |
Super + Shift + X | X/Twitter — new post |
Super + W | Looking Glass client, full screen, for a virtual machine with a passed-through GPU. No lyona profile installs looking-glass-client; without it, the key says so in a notification |
Super + Ctrl + R | Restart Proton and Steam |
Super + A opens an installed ChatGPT desktop application when one is
available and falls back to the ChatGPT web app otherwise. The application
launcher hides the ChatGPT web entry while a native desktop entry is installed.
Window Management
| Keys | Action |
|---|---|
Super + J | Focus next window |
Super + K | Focus previous window |
Super + Shift + J | Move window down in stack |
Super + Shift + K | Move window up in stack |
Super + Return | Move window to the main area |
Super + Q | Close window |
Super + I | One more window in the main area |
Super + D | One fewer window in the main area |
Super + H | Narrower main area |
Super + L | Wider main area |
Super + Shift + H | Taller window in the stack |
Super + Shift + L | Shorter window in the stack |
Super + Shift + O | Even out the stack heights |
Layouts
| Keys | Action |
|---|---|
Super + T | Tiling layout |
Super + F | Floating layout |
Super + M | Fullscreen the focused window (not a layout) |
Super + Space | Toggle floating for window |
Super + Shift + M | Toggle floating for window |
Super + Shift + Y | Fullscreen inside the window (the window keeps its size) |
Super + Shift + B | Toggle bar visibility |
The monocle layout (one window at a time, the bar visible) has no default key: choose it in the Control Center’s Window layout row.
Floating a tiled window with Super + Space (or Super + Shift + M)
pops it out of its tile at 85 percent of the tile’s
size, centered on it and kept inside the work area, so the change is visible.
A window whose minimum size is larger than the work area keeps that size,
starting at the work area’s top-left corner and extending past it. Toggle
again to return it to the tile. Super + F applies the same shrink to
each visible tiled window when it switches to the floating layout, including
from monocle, and Super + T retiles them. Choosing the floating layout
again leaves the sizes alone, and windows already floated individually keep
their size and position. Fixed-size windows are never resized. Mouse dragging
and resizing keep the geometry they start from.
Tags (Workspaces)
| Keys | Action |
|---|---|
Super + 1–9 | Switch to tag |
Super + Ctrl + 1–9 | Also show tag alongside current |
Super + Shift + 1–9 | Move window to tag |
Super + Ctrl + Shift + 1–9 | Also show window on that tag |
Super + 0 | Show windows from all nine tags; 0 is not a tag |
Super + Tab | Previous tag |
Multi-Monitor
| Keys | Action |
|---|---|
Super + , | Focus left monitor |
Super + . | Focus right monitor |
Super + Shift + , | Send window to left monitor |
Super + Shift + . | Send window to right monitor |
Media Keys
| Keys | Action |
|---|---|
XF86AudioRaiseVolume | Volume up |
XF86AudioLowerVolume | Volume down |
XF86AudioMute | Mute toggle |
XF86MonBrightnessUp | Brightness up |
XF86MonBrightnessDown | Brightness down |
Session & Power
| Keys | Action |
|---|---|
Super + Ctrl + Q | Power menu |
Super + Shift + Q | Log out: opens the power menu at its confirmation |
Super + Ctrl + Shift + Q | Quit dwm at once, without asking; for when the shell is not running |
Super + Ctrl + Shift + R | Reboot: opens the power menu at its confirmation |
Super + Ctrl + Shift + S | Suspend |
Mouse
| Action | Function |
|---|---|
Super + Left drag | Move window |
Super + Right drag | Resize window |
| Click a tag in the panel | Switch to that tag |
Customizing Keybinds
Edit ~/.config/lyona/hotkeys.toml — changes take effect on save, no recompile required. The repository’s config/hotkeys.toml is only the default a new account starts from.
[vars]
terminal = "alacritty"
keys = [
{ mod="SUPER SHIFT", key="f", desc="Firefox", func="spawn", exec=["firefox"] },
]
See the comments in hotkeys.toml for a full list of func values and modifier syntax.
The browser binding uses dwm-default-apps open. Configure it with
Settings -> Defaults or with dwm-default-apps browsers and
dwm-default-apps set-browser <desktop-id>.
The terminal variable defaults to Alacritty. Settings -> Defaults can select a
validated installed terminal without changing the Super+X key record. To
use the optional Herdr workspace, install it explicitly, change the binding to
dwm-terminal, and set DWM_HERDR=1 in the session environment.
Configuration
lyona keeps user configuration under
${XDG_CONFIG_HOME:-$HOME/.config}/lyona/. Customise lyona with these files.
They are read at runtime, live-reload on save, belong to you alone, and survive
every update and rollback unchanged. No recompile is needed.
| File | Purpose |
|---|---|
hotkeys.toml | All keybindings, including the tag keys |
themes.toml | Colors, themes, border size |
window-rules.toml | Per-app window rules: tag, floating, terminal swallowing, always on top, monitor |
power.conf | Control Center screen blanking and auto-lock choices |
dwm tells you about a file it could not load as written with a “dwm: bad config” notification, which names the first problem:
- Part of the file is wrong (an unknown key name, a missing comma or
}, a binding with nothing to run): dwm loads the rest, and the notification counts what it skipped, for example “1 problem, the rest loaded - unknown key ‘Retrun’”. - The file cannot be used (it is empty, nothing in it can be bound, or it is cut off inside an array, as a half-saved edit is): at login dwm falls back to the shipped default for that file; when you save it while dwm is running, it keeps the configuration it already had until the file is fixed. The notification says why, for example “invalid config (line 14: an array is never closed) - kept the previous config”.
The shipped defaults are read-only, in /usr/local/share/lyona/config/ (in
PREFIX/share/lyona/config/ for another install location). They are replaced on every update, so
change your own copy in ~/.config/lyona/, never these.
Window rules
window-rules.toml holds one rule per line, and every matching rule applies, in
order. Find a window’s class, instance and title with
xprop | grep -E "WM_CLASS|WM_NAME".
rules = [
{ class="Gimp", isfloating=1 },
{ class="firefox", tags=2 },
{ class="kitty", isterminal=1 },
]
Fields: class, instance, title (omit to match anything), tags (1-9; 0 or
omitted follows the current tag), isfloating, isterminal, alwaysontop,
noswallow (1/true or 0/false), and monitor (-1 for any). A rule needs at
least one of class, instance or title; one with none would match every window,
so dwm skips it and says so in its log.
config.h (compile-time options)
A few options are compiled into dwm and have no TOML equivalent yet: the bar font,
the tag names, the layouts, the default master size and count, the refresh rate, the
window icon size, the floating-toggle shrink and whether the bar is shown. These live
in config.h, your copy of config.def.h in the checkout, which make creates if it
does not exist.
$EDITOR config.h
./scripts/dev-sync-install.sh
dev-sync-install.sh rebuilds dwm, updates the installed commands, shared code,
shipped defaults and managed Quickshell configuration when needed, verifies parity,
and reports whether the dwm session must be restarted. When a session restart is already required, it activates
Quickshell there so the tray host starts before tray clients. Use
./scripts/dev-sync-install.sh --check for a non-mutating audit.
How updates treat config.h. lyona-update (and the Settings update pane)
builds each release with your own
${XDG_CONFIG_HOME:-$HOME/.config}/lyona/config.h, and falls back to a checkout’s
config.h when you run ./scripts/lyona-update from one. With neither, a release
builds from its config.def.h. make install-user (run by install.sh) copies a
customised checkout config.h there once, and never overwrites one that is already
there; it does not copy an unchanged default, which would only go stale.
When a release adds a compile-time option, merge it into your copy from the
release’s config.def.h; if the build fails, lyona-update names the config.h it
used and leaves the live install untouched. dwm is installed once for the whole
machine, so the person who runs the update decides these options for everyone. Keep
personal choices in the TOML files above, which are per user and always survive an
update.
| Setting | Description |
|---|---|
fonts[] | Font family and size used in the bar |
tags[] | Tag names |
layouts[] | Available layouts (switch with the keys, or the Control Center’s layout row) |
mfact, nmaster | Default master area size and count |
refresh_rate | Match your monitor (default 60; set 120 for high-refresh) |
FLOATSHRINKPCT | How far a window shrinks when toggled to floating (default 85%) |
ICONSIZE, SHOWWINICON | Window icon size, and whether it is shown |
MODKEY | The modifier the tag keys in hotkeys.toml use: Mod4Mask = Super, Mod1Mask = Alt |
hotkeys.toml — Live Keybinds
Add or change bindings without recompiling. Save the file and they apply instantly.
[vars]
terminal = "alacritty"
webapp = "webapp-launch"
keys = [
{ mod="SUPER", key="x", desc="Terminal", func="spawn", exec=["$terminal"] },
{ mod="SUPER SHIFT", key="f", desc="Firefox", func="spawn", exec=["firefox"] },
]
The default binding launches Alacritty directly. The dwm-terminal helper is
available to delegated tools that need a terminal selection fallback; it also
prefers Alacritty and opens the emulator directly by default. Explicit
arguments such as dwm-terminal -e command retain their direct execution
contract.
Thunar’s seeded Open Terminal Here action launches Alacritty directly in
the selected directory, matching the normal Super + X default. Existing
Thunar custom actions are preserved during installation and upgrades.
Set DWM_TERMINAL to choose another emulator for dwm-terminal. Herdr is an
optional layer: install it explicitly, set DWM_HERDR=1, and run
dwm-terminal. Set DWM_HERDR_COMMAND to select a different Herdr binary.
Default applications use freedesktop settings. Run dwm-default-apps browsers
to list browser desktop files, dwm-default-apps set-browser firefox.desktop
to set the default browser, or dwm-default-apps set-mime <mime> <desktop-id>
for other file types.
Display profiles are optional files under
${XDG_CONFIG_HOME:-$HOME/.config}/lyona/display-profiles. Use
dwm-display-profile template to print the format, dwm-display-profile list
to show profiles, and dwm-display-profile apply <name> to run the profile
through xrandr.
For persistent Xorg configuration, run dwm-display-setup. The interactive
wizard detects connected outputs and their exact advertised timings, then asks
for resolution, refresh rate, rotation, absolute position, and the primary
display. It checks whether the active Xorg driver exposes compatible TearFree
support or the NVIDIA Full Composition Pipeline and enables only the compatible
default. The proposed layout is applied as a live preview and automatically
restored unless it is confirmed. Advanced calls may pass
--force-full-composition-pipeline off to disable the NVIDIA default; forcing
it on with an incompatible kernel or Xorg driver is rejected.
Accepted layouts are installed as the isolated managed fragment
/etc/X11/xorg.conf.d/90-lyona-display.conf; existing Xorg files are not
replaced. Each change creates a versioned backup. Use
dwm-display-setup rollback to restore the newest backup, or
dwm-display-setup status to inspect the managed file and current layout.
Advanced users can pass an existing display-profile file to
dwm-display-setup generate, preview, or install.
For noninteractive session changes, dwm-display-setup capture prints the
current complete RandR profile, dwm-display-setup validate <profile> checks a
profile with xrandr --dryrun, and dwm-display-setup apply <profile> changes
the current X11 layout after validation.
The Settings Displays page uses the same profile grammar and validation through
dwm-settings-display. Named profiles remain user-owned under the XDG path.
Installing one persistently requires explicit confirmation and authorization;
only the root-owned helper under ${PREFIX}/libexec/lyona/ may update the
managed Xorg fragment. Legacy profiles that omit complete position or rotation
state remain usable with dwm-display-profile, but Settings will not preview or
install them until they are resaved as a complete layout.
Per-device input values kept in Settings are stored in
${XDG_CONFIG_HOME:-$HOME/.config}/lyona/input-settings.conf. The
event-driven input provider uses a hardware serial or path when available,
re-resolves that identity before every change, and skips a disconnected device
rather than applying its settings to another XInput ID. Session startup runs
dwm-settings-input apply-saved and starts an event-driven, debounced hotplug
replay so returning devices regain saved values. Repeating the apply is safe.
The replay watcher is scoped to the owning dwm process and exits at logout,
including when dwm was launched through startx.
Power settings are managed from Control Center -> Power. Out of the box
the screen turns off after 10 minutes idle and the desktop
locks: lyona sets light-locker to lock 5 seconds after the screen blanks and on
suspend, and starts it. Changing anything there writes power.conf, which is
then authoritative and persists screen DPMS state, display-off timing, and
automatic idle and suspend locking. Startup reapplies it (or the defaults)
before background session services are launched. Manual locking remains
available when automatic locking is disabled. The screen locker runs only
while automatic locking is enabled or for the duration of an explicit manual
lock, so DPMS display-off events remain independent from locking. External
loginctl lock-session requests are forwarded to dwm-lock by an
event-driven session listener. Until power.conf exists, lyona never stops or
disables a locker it did not start.
Modifier Syntax
Use space-separated modifiers: "SUPER", "SUPER SHIFT", "SUPER CTRL", "SUPER CTRL SHIFT".
Available Functions
func | Parameters | Description |
|---|---|---|
spawn | exec=[...] or cmd="..." | Run a program |
killclient | — | Close focused window |
zoom | — | Promote/demote master |
focusstack | i=1 or i=-1 | Focus next/prev window |
movestack | i=1 or i=-1 | Reorder in stack |
incnmaster | i=1 or i=-1 | Change master count |
setmfact | f=0.05 or f=-0.05 | Resize master area |
setcfact | f=0.25 / f=-0.25 / f=0.00 | Resize window slot |
setlayout | layout_idx=0/1/2 | 0=tile, 1=float, 2=monocle |
togglefloating | — | Float/tile window |
fullscreen | — | True fullscreen |
togglefakefullscreen | — | Fullscreen with bar |
togglebar | — | Show/hide bar |
focusmon | i=1 or i=-1 | Focus monitor |
tagmon | i=1 or i=-1 | Send window to monitor |
view | ui=-1 = all tags | Switch tag |
quit | — | Exit dwm |
Keys Typed Before a Window Opens
A binding that opens a window can hold the keys typed straight after it until that window appears, so they do not go to the window you were in:
{ mod="SUPER", key="r", desc="App launcher", func="spawn",
exec=["lyona-shell", "launcher", "toggle"], hold_keys="dwm launcher" },
hold_keys is text a window’s title, class or instance contains. dwm grabs
the binding’s key synchronously, so from the moment it goes down the X server
queues the keys typed after it, however busy the machine is; once a matching window maps and has the focus, dwm lets them go and
they reach it in the order typed, dwm’s own hotkeys included (Super+R again
closes the launcher, Escape dismisses it). The hold lasts at most one second:
if no matching window appears by then, the keys go where they would have gone
without it, late. A window that is already open is not waited for (the
binding usually closes it), and when another program has the keyboard
grabbed, nothing is held. The default Super+R binding has it; the installer’s
hotkeys migration adds it to a Super+R line still exactly as shipped.
Tag Bindings
Tag bindings auto-generate all four variants (switch, toggle-view, move, toggle-tag):
tag_keys = [
{ key="1", tag=0 },
{ key="2", tag=1 },
]
Notes on XDG Autostart
Recommend using Flatpak to install programs on startup:
flatpak install flathub io.github.flattool.Ignition
or you can create your own .desktop file in ~/.config/autostart/
set-refresh.desktop Example:
[Desktop Entry]
Type=Application
Exec=xrandr --output HDMI-0 --primary --mode 1920x1080 --pos 0x0 --rotate normal --rate 120 --output DP-0 --off --output DP-1 --off --output DP-2 --off --output DP-3 --off --output DP-4 --off --output DP-5 --off
Hidden=false
X-GNOME-Autostart-enabled=true
Name=Set Refresh
Theming
Themes are defined in ~/.config/lyona/themes.toml. Change the active theme and save
to update dwm, Quickshell, terminal, GTK, and Qt styling. No restart needed.
[active]
theme = "tokyonight" # ← change this line to switch themes
The managed transaction helper is the safe command-line interface for theme changes:
dwm-settings-theme preview preview-1 15 dracula
dwm-settings-theme keep preview-1 # confirm before the timeout
dwm-settings-theme revert preview-1 # or restore immediately
dwm-settings-theme abandon preview-1 # accept a conflicting external edit
dwm-settings-theme apply gruvbox
dwm-settings-theme reset # restore the managed default selection
An unconfirmed preview restores the exact previous themes.toml bytes and
mode automatically. Apply and reset preserve comments, custom theme sections,
and unrelated appearance settings. If an operation is interrupted after its
atomic write, inspect and restore it with:
dwm-settings-theme recovery-status
dwm-settings-theme recover
Recovery refuses to overwrite an externally changed theme file.
Available Themes
Dark
| Theme | Description |
|---|---|
nord | Arctic, cool blue palette |
dracula | Purple-tinted dark theme |
gruvbox | Warm retro earth tones |
catppuccin | Mocha variant — soft pastels |
tokyonight | Deep blue-grey night theme (default) |
onedark | Atom One Dark inspired |
solarized | Dark variant of Solarized |
rosepine | Muted rose/pine tones |
everforest | Muted green forest palette |
monochrome | Black and white minimal |
Light
| Theme | Description |
|---|---|
catppuccin-latte | Catppuccin light variant |
gruvbox-light | Warm light tones |
solarized-light | Classic Solarized light |
rosepine-dawn | Rose Pine dawn variant |
tokyonight-day | Tokyo Night day variant |
Border Size
[appearance]
borderpx = 1 # 0 = no border, 1 = thin (default), 2-3 = thicker
What Each Theme Controls
Each [theme.name] section sets colors for all components:
| Key | Applies To |
|---|---|
normfgcolor / normbgcolor / normbordercolor | Unfocused bar and windows |
selfgcolor / selbgcolor / selbordercolor | Focused window and active tag |
term_bg / term_fg / term_cursor | Terminal background, text, cursor |
term_color0–term_color15 | Full 16-color terminal palette |
dark_mode | GTK dark preference and Capitaine cursor variant (true / false) |
gtk_theme | Optional installed GTK theme name for GTK apps such as Thunar |
Quickshell derives its opaque surfaces, text, borders, accent, success, warning, and danger colors from the active theme’s existing dwm and terminal color keys.
Creating a Custom Theme
Add a new section to themes.toml:
[theme.mytheme]
normfgcolor = "#cdd6f4"
normbgcolor = "#1e1e2e"
normbordercolor = "#313244"
selfgcolor = "#cdd6f4"
selbgcolor = "#89b4fa"
selbordercolor = "#89b4fa"
term_bg = "#1e1e2e"
term_fg = "#cdd6f4"
term_cursor = "#f5e0dc"
# ... term_color0-15 ...
dark_mode = true
gtk_theme = "Lyona-mytheme"
Then set theme = "mytheme" under [active] and save.
gtk_theme may name any installed GTK theme. Leaving it out is usually the
right choice: make install generates a Lyona-<name> GTK theme from every
palette in this file, and that generated theme is what a palette falls back to.
Regenerate one by hand with:
lyona-gtk-theme generate mytheme ~/.config/lyona/themes.toml ~/.themes/Lyona-mytheme
Applications built on libadwaita ignore custom GTK themes by design and stay in their own light or dark palette regardless of this setting.
The same generated directory carries a GTK 2 theme (gtk-2.0/gtkrc) and a Qt
colour scheme (qt/colors.conf). With qt6ct or qt5ct installed, applying a
theme points the tool at that scheme and turns its custom palette on, creating
~/.config/qt6ct/qt6ct.conf (or the qt5ct one) if it does not exist yet, so
Qt applications follow the palette. Without either tool, Qt uses the GTK theme.
If you would rather pick your own Qt scheme, choose another platform theme under
Settings > Appearance, or set qt in personalization.conf.
Applying Themes via Control Center
Open the Control Center with Super + F1, open Appearance, and pick a theme from the list. The theme switches immediately.
Wallpapers
Place images in ~/Pictures/backgrounds/. Open Settings → Appearance to
select an image, choose its fit, preview it for 30 seconds, apply it, or reset
to the random session default. Use Super + Shift + W or
dwm-settings-wallpaper randomize for a one-off random wallpaper in the
current session, or persist a specific image and fit from a terminal:
dwm-settings-wallpaper apply "$HOME/Pictures/backgrounds/mywall.jpg" fill
Supported fit modes are center, fill, max, scale, and tile. Preview a
choice for 30 seconds before keeping it:
token="wallpaper-$$"
dwm-settings-wallpaper preview "$token" 30 \
"$HOME/Pictures/backgrounds/mywall.jpg" max
dwm-settings-wallpaper keep "$token"
Use dwm-settings-wallpaper reset to return to the session’s random-fill
default. If a saved image is removed, login remains usable and falls back to
that default until another image is selected or the setting is reset.
Fonts and Text Size
Open Settings -> Appearance to select an installed Fontconfig family and a managed shell text scale from 80, 90, 100, 110, 125, or 150 percent. The icon font remains the shipped Meslo Nerd Font even when ordinary interface text uses another family, so changing fonts cannot remove panel or menu glyphs.
Preview changes for 30 seconds before keeping them, or apply and reset from a terminal:
token="font-$$"
dwm-settings-font preview "$token" 30 "Noto Sans" 1.25
dwm-settings-font keep "$token"
dwm-settings-font apply "Noto Sans" 1.10
dwm-settings-font reset
The setting owns only font.conf under the lyona XDG configuration
directory. A malformed file falls back to the existing Meslo family at 100
percent without preventing shell startup. GTK and Qt application font policy
is intentionally deferred to the separate toolkit-control slice.
Boot Menu
The GRUB boot menu uses the CyberRe theme, selected by the installer on
machines that boot with GRUB. It is not part of the palette system above –
GRUB reads its own theme long before the session starts, so it does not follow
the dark/light theme you pick in Settings.
lyona-grub-theme status # detected bootloader and selected theme
lyona-grub-theme list # installed themes
lyona-grub-theme apply # select CyberRe (or apply <name>)
lyona-grub-theme remove # back to the default GRUB appearance and entries
Applying or removing a theme edits /etc/default/grub and regenerates
/boot/grub/grub.cfg, so it needs root and backs the file up first. Applying
also hides the (EFI BootNext) firmware entries GRUB 2.16 adds, through a
drop-in file that removing deletes. See
Install for exactly which keys it changes.
Machines that boot with systemd-boot have no GRUB menu to theme, and the commands above report that and do nothing. Installs made from the lyona image boot with GRUB, with this theme.
Picom opacity and backend
Open Settings > Appearance > Compositor to change foreground (active) and background (inactive) window opacity. Sliders save when released; keyboard edits save after a short pause. Values stay the same when switching themes. Custom Picom rules can override these defaults for individual windows.
The same section has a Window corner radius slider, from 0 to 32 pixels, that
rounds the corners of every window (dwm draws square borders, so rounding comes from
Picom’s corner-radius option). At 0 the setting is removed from the configuration.
Picom leaves fullscreen windows square by default, and a per-window corner-radius in
a Picom rule overrides the slider. Picom’s manual says rounded corners do not combine
well with transparent-clipping, so leave that off if you use them. It needs a running
compositor to show; with Picom stopped the value applies the next time it starts.
Let full-screen windows bypass the compositor is off by default. On, Picom’s
unredir-if-possible lets a full-screen window, such as a game, draw without the
compositor, which is faster. While a window is full screen that way, the overview
cannot preview it, and on some GPUs the screen flickers as it switches. Off removes
the setting from the configuration.
The controls read the active Picom configuration: your own ~/.config/picom.conf
or ~/.config/picom/picom.conf when you have one, otherwise lyona’s default
(/usr/local/share/lyona/xdg/picom/picom.conf in a standard install). lyona’s default
is lean so that old hardware can run it: no shadows, fading, blur or animations,
and every window opaque. It is read-only; Create user configuration copies it
to ~/.config/picom.conf, after which your copy is used and lyona’s updates never
touch it. The controls observe external edits. Comments, unrelated settings,
and included files are preserved; the ten most recent edits retain recovery
backups. Invalid or read-only configurations show an explanation rather than
disappearing controls. Edits made while Picom is stopped take effect the next time
it starts. Valid configurations using syntax the editor cannot rewrite, such as
nested includes, still support startup, restart, and reload through Picom itself.
Automatic chooses GLX for an accelerated Intel/AMD renderer and XRender for NVIDIA, software rendering, or unknown hardware. Failed automatic GLX startup retries XRender once. An existing explicit backend is preserved; choose Automatic to remove it. XRender, GLX, and experimental EGL remain selectable. The active renderer matters, not an unused or passthrough GPU installed in the machine.
PICOM_BACKEND remains a session override. Unset it before selecting a different
backend in Settings. DWM_PICOM_CONFIG=/absolute/path/picom.conf can select a
custom configuration; an existing Picom --config argument is also respected.
Command-line opacity and --corner-radius overrides must be removed before editing them in
Settings.
dwm-settings-picom status
dwm-settings-picom restart
Restart and toggle affect only your compositor on the current display. Failed configuration activation restores the prior files and attempts to recover the previous compositor; the error identifies the backup and session log.
Control Center
The Control Center is a single-card anchored Quickshell menu for launching applications, panel settings, system health, quick actions, appearance settings, power management, and keybind discovery.
Open: Super + F1, or run dwm-controlcenter from a
terminal.
The popup opens from the panel logo. Applications, Power, Settings, System Health, Keybinds, and System Info are available directly from the main menu. Bar Widgets, Quick Actions, Appearance, and Power Settings replace the menu contents in the same card and provide a Back control. Press Esc or click outside the card to close it from any page.
The main menu also has a Window layout row of three buttons, Tile, Floating and Monocle, for people who do not know the layout keybindings. The button for the current layout is highlighted and follows the keyboard, so pressing Super + T or Super + F moves the highlight. Layouts are per tag, and the row acts on the tag and monitor that currently have focus. The buttons are disabled when dwm does not report its layout (an older dwm build).
The Utilities section opens the unified Settings application directly, where
each section shows the current state and changes what it can. It can also be
opened with dwm-settings open.
The Utilities section also shows the installed lyona version, and — only when a newer release is available on the configured channel — an Update available row naming it. Both open Settings -> System. There is no update action in Control Center itself: applying an update is a multi-minute privileged operation that restarts Quickshell, and does not belong behind a one-click row next to the volume slider. See Settings and Updating and Rollback.
Network Popover
The panel network indicator opens a Quickshell network popover. It shows active NetworkManager connections, scans visible Wi-Fi networks, and connects to open or WPA personal networks directly. Successful Wi-Fi connections are saved as NetworkManager profiles, so they reconnect normally in later sessions.
Hidden SSIDs and enterprise Wi-Fi are handled through the optional
nm-connection-editor fallback when it is installed.
Bluetooth Popover
The panel Bluetooth indicator opens a compact device manager. It can power the
adapter on or off, scan for devices, pair and trust a new device, connect a
paired device, and disconnect a connected device through bluetoothctl.
Panel Widgets
The Bar Widgets page can show or hide the workspace, volume, Bluetooth,
network, power, calendar and weather widgets. Those choices are stored in the
project-owned ~/.config/lyona/panel-widgets.conf state and apply to every
monitor and future Quickshell session. Settings Appearance exposes the same
shared controls and can restore the defaults: everything on except the weather.
Calendar
Click the panel clock to open a month calendar.
- Keys: the arrows move a day or a week, Page Up and Page Down a month, and Home returns to today.
- Closing: Escape or a click outside closes it.
- Off: with the Calendar switch off, the clock does nothing when clicked.
- IPC:
quickshell ipc --path ~/.config/quickshell/shell.qml call calendar toggleopens it from a hotkey too.
Weather
The weather is off until you turn its Bar Widgets switch on and set a location in Settings, Appearance, Weather.
- What is sent: the shell then asks Open-Meteo for the current temperature, at most every 30 minutes, and only while the widget is on. No account or key is needed. The location you typed is sent to Open-Meteo and nothing else is; your position is never guessed from your IP address.
- Units: they follow your locale (Fahrenheit in the US and a few other regions) unless you choose Celsius or Fahrenheit there.
- When it fails: the panel shows “Unavailable” and tries again later.
- The helper: the panel uses
lyona-weather, which keeps its settings in~/.config/lyona/weather.confand its cache in~/.cache/lyona/weather/, both private to you.
The redesigned panel retains the active-window title, status segments, and system tray, and shows all nine dwm tags (workspaces). Hovering icon-only panel controls displays a text tooltip.
The panel, popovers, and control-center cards use fully opaque colors. Their
palette follows the active theme in themes.toml and updates when that file is
changed.
Modules
System Health
System Health opens as a separate dashboard filling the current monitor below
the panel, which stays visible. It starts two read-only scans: session checks run immediately, and a
privileged scan completes current-boot journal, kernel, system-service, and
drive checks. It always asks: the running polkit agent requests graphical
authorization for the root-owned ${PREFIX}/libexec/lyona/dwm-system-health-root,
under its own action (com.lyona.system-health.manage, “Authentication is
required to read system logs and repair system services”). That helper accepts
only the privileged scan and the listed service repairs. Cancelling the prompt
leaves a partial report and marks its coverage as incomplete.
The dashboard groups checks into:
- Boot and kernel errors from
journalctl, withdmesgas a fallback - Failed user and system services, one service per row
- Memory, pressure, load, swap, filesystem space, and inode use
- Local routing, resolver, and NetworkManager state
- X11, D-Bus, dwm, Quickshell, Picom, audio, and managed configuration
- Required commands, libraries, terminals, and package-database consistency
- Available battery, thermal, and SMART drive-health data
Use Issues Only to hide passing checks. Expand any card to see bounded evidence; the dashboard counts the complete matching log set even when only a sample is displayed. It does not contact an external service to test Internet connectivity and does not scan previous boots.
Boot-journal and kernel-error cards with matching entries include Copy and
Export. Copy sends the card’s readable bounded evidence to the X11
clipboard with xclip. Export saves the same content in the user’s home
directory as a private timestamped file, such as
boot2026-07-09-143000.txt or kernel-errors2026-07-09-143000.txt. Existing
files are never overwritten.
Repair buttons always require confirmation. Each failed service row offers
Start, Stop, Restart, Disable, and Enable. User units are managed with
systemctl --user; system units request administrator authorization through
polkit. An action is accepted only while that exact service remains failed.
The dashboard can also restart known desktop/audio components, launch the
interactive dependency installer, restart NetworkManager or Bluetooth, and
repair the detected time-synchronization provider.
Installing the health helper in a root-owned system path remains recommended:
make
sudo make install-system
A checkout’s copy of a helper is never elevated, and a cached sudo session
is never used: without the root-owned installed helper, the privileged scan and
the system repairs are unavailable and the dashboard says so.
Quick Actions
| Action | Description |
|---|---|
| Restart Picom | Restart the compositor through dwm-settings-picom, which picks the backend for this GPU |
| Restart Quickshell | Reload the managed Quickshell shell |
| Reload Wallpaper | A random wallpaper from ~/Pictures/backgrounds/ |
| Restart NetworkManager | The System Health repair: polkit asks for authorization, then NetworkManager restarts |
| Dependency Check | Opens check-deps.sh in a terminal |
| Self-Heal | Runs the script named in ~/.config/lyona/self-heal.path (or dwm-self-heal on PATH) in a terminal; shown only when one is set up |
| Install Missing Deps | In a terminal: install.sh from a checkout, or the required and desktop packages through pacman from an install |
| Wallpaper Folder | Open ~/Pictures/backgrounds/ in the file manager |
| GTK Settings | Launch nwg-look for GTK theming; shown only when nwg-look is installed |
While an action runs, the status line names it (“Running Restart Picom…”), then says “done”, “opened in a terminal” for the ones that work in a terminal, or why it failed.
Appearance
The Appearance page lists every theme in ~/.config/lyona/themes.toml, the
active one marked. Choose one to apply it at once. The wallpaper and GTK
actions are in Quick Actions above.
Power Settings
The Power Settings card retains the existing persisted screen-DPMS and auto-lock controls. Each feature can be enabled or disabled and assigned a 5-minute, 10-minute, 15-minute, 30-minute, or 1-hour timeout.
Both are on by default. After 10 minutes idle the screen turns off, and the
desktop locks 5 seconds later; moving the mouse in those 5 seconds cancels without
a password. Turning either off, or picking another timeout, is saved in
~/.config/lyona/power.conf and wins over the default. A choice you saved before
this default changed is kept. The lock uses light-locker, which locks through
LightDM (Lyona’s display manager). In a startx session the screen still turns off,
but the automatic lock needs LightDM.
Below them, the Power Settings card lists the batteries of wireless mice, keyboards, headsets and other peripherals that report one, each with its level (“40%”, or a word such as “Low” for a device that reports only that) and whether it is charging. With none, nothing extra is shown. A peripheral that drops below 15% sends one notification, not repeated until it has been charged.
The full Settings Power page also shows battery, external-power, profile, suspend, and lid capabilities, and a Devices section with the same peripheral batteries. Its Lock, Log Out, Suspend, Reboot, and Shutdown buttons use the same shared root QML action model and confirmation policy as the panel Power menu. Denied or failed actions remain attributed to the surface that requested them.
Defaults and Startup Applications
Settings -> Defaults manages browser, terminal, file-manager, and selected MIME handlers through versioned XDG records. Restore Previous is offered only while the recovery image still matches the state written by the last action.
File-type choices include installed handlers such as sxiv and Feh even when
their desktop entries use NoDisplay=true to stay out of launcher menus.
Disabled entries and handlers whose executables are missing remain excluded, and
the browser, file-manager and terminal roles still hide menu-hidden entries.
The same page lists effective XDG autostart entries and their vendor or user origin. Enable, disable, and reset create or update user overrides for the next login; vendor desktop files are never edited. Changes to the locker, compositor, or polkit agent require explicit confirmation.
Keybind Viewer
Displays all bindings from hotkeys.toml in a Quickshell list. Same
as pressing Super + /.
Running from Terminal
dwm-controlcenter
The script is a compatibility wrapper around the Quickshell IPC target. For a
key binding, prefer lyona-shell controlcenter toggle (or open), which the
default bindings use and which follows the IPC when it changes:
quickshell ipc --path "${XDG_CONFIG_HOME:-$HOME/.config}/quickshell/shell.qml" call controlcenter toggle
Open or refresh System Health directly through its IPC target:
quickshell ipc --path "${XDG_CONFIG_HOME:-$HOME/.config}/quickshell/shell.qml" call systemhealth open
quickshell ipc --path "${XDG_CONFIG_HOME:-$HOME/.config}/quickshell/shell.qml" call systemhealth refresh
The diagnostic helper can also produce its structured snapshot in a terminal:
dwm-system-health scan-user
Settings
The unified Settings application is one place to see and change the desktop: each section shows the current state, changes what it can, and says when a feature is restricted or unavailable on this machine.
Open Control Center with Super+F1, then select Settings from the main
menu. You can also run:
dwm-settings open
The Displays section discovers connected outputs and their advertised modes,
lets you edit resolution, refresh rate, position, rotation, primary state, and
output enablement, and manages named layouts. Choose Apply changes to test
the complete layout for 15 seconds, then Keep changes to accept it or
Revert to restore the captured layout. Timeout or closing Settings also
restores the prior layout; if it cannot be restored, the preview stays, a
notification says so, and Settings > Displays offers Keep current or Discard
when reopened. Settings fills the screen below the panel and follows it when
the screen is rotated, so the preview’s buttons stay on screen. If a preview is interrupted, for example because
the X session crashed mid-change, Settings drops it the next time it checks,
without applying anything, and the layout then in use stays. When the prior
layout cannot be restored automatically (its watchdog stopped, or it names a
display that is no longer connected), the prompt says why and offers Keep
current, which also uses the layout at the next login, and Discard,
which leaves the screens as they are for this session only; Revert stays
available when retrying can work. Saved layouts can be reused later; Use at next
login installs the selected layout for future X11 sessions after a separate
confirmation and administrator authorization.
The machine-oriented dwm-settings-display helper exposes discover and
watch, complete-layout save and preview, named preview-profile, timed
keep, revert, discard, and preview-status, plus authorized install-profile and
rollback-system actions. Named layouts live under the lyona XDG config
directory. Legacy incomplete layouts remain available to
dwm-display-profile, but Settings requires them to be resaved as complete
layouts before preview or persistent installation.
The Displays section also sets display scaling. Enter an Xft DPI between 72 and
384, or use the 100%, 125%, 150%, 175%, and 200% presets. Applying writes
Xft.dpi to dpi.Xresources in the lyona XDG config directory and merges
it into the running X resource database; autostart reapplies it at every login.
The pane reports whether the active scale is saved, session-only, or the X
server default, and shows the primary output’s measured DPI as a suggestion.
Reset removes the saved value and clears Xft.dpi from the running database
without disturbing other X resources. Scaling is not a timed preview: only
applications started after the change pick up the new value, so restart dwm and
the shell to rescale them too. The helper actions are dpi-set, dpi-reset,
and the startup-only dpi-apply-saved.
The Input section shows each XInput device by a stable hardware identity and offers only properties its driver exposes. Pointer acceleration, natural scrolling, tap-to-click, keyboard layout, and modifier options are supported when available. Changes use a timed preview with Keep and Revert. Reset is a separate direct action that restores and persists the driver’s default. Kept values are reapplied idempotently at session startup when the device exposes a stable udev or physical sysfs identity. Devices without one remain session-configurable and report that persistence is unavailable. Unsupported per-device properties remain visible with an explanation.
Type to search section names and descriptions. Use Up and Down to move through
the filtered sections, Enter to select one, or Escape to close Settings. A
search for “shortcut”, “hotkey” or “keybind” shows Keyboard shortcuts, which
opens the keybind viewer (Super+/). The
Refresh button runs a new bounded capability snapshot; Settings does not add an
idle polling timer.
Command-line IPC actions are also available:
dwm-settings open
dwm-settings refresh
dwm-settings status
dwm-settings close
Existing window-rules.toml files are preserved during upgrades. If your file
predates Settings, add this entry inside its rules array:
{ title="dwm settings", isfloating=1, alwaysontop=1 },
Saving the file applies the rule through dwm’s normal hot reload. A customized rule with the same title can be retained instead.
The same applies to the update terminal Settings -> System can open: to float
it in an older file, add { class="lyona-update-float", isfloating=1 }, (see
Updating and Rollback).
The Use at next login display action writes only the managed
90-lyona-display.conf fragment after a separate confirmation and polkit
authorization. The installed helper accepts validated display records only,
backs up the previous managed next-login fragment, and offers Restore login
backup. It does not capture the live XRandR layout. Later phases add
connectivity, audio, power, defaults, personalization, and system-management
operations.
System
The System section shows the installed lyona version, its commit and source (release tarball, ISO, or developer checkout), and whether the system record, user record, and running binary agree. If they disagree the card turns red and names which of the three differs — that is the one signal a damaged install gives you, so it is impossible to miss.
At the bottom, Needs attention lists only what is not working, such as a missing helper (“Reinstall lyona to restore system updates”). Parts that work, and administration lyona leaves to dedicated tools by design, are not listed.
Check for updates compares the installed version against the configured
channel (stable or preview) and reports one of:
- current: the installed release matches the channel;
- behind: a newer release is available;
- ahead: a development checkout newer than the published release;
- downgrade offered: the channel’s release is older than the installed one.
Nothing is installed unless you ask for that version: the button says Go
back to VERSION, the confirmation says it is older than what is installed,
and the password prompt is the separate “install an OLDER lyona release”
one, which needs the release’s signature (
lyona-update apply --version VERSION --allow-downgradefrom a terminal). To return to what was installed before an update, roll back to its backup (below) instead; - unknown: there is no install record to compare, or nothing has been
published on the channel yet (lyona’s releases so far are pre-releases, on
preview); - unavailable: the install record exists but cannot be trusted;
- offline: the update server could not be reached.
An unreachable server is never treated as an error, and the installed version stays visible either way. When a newer release is available, Update now asks you to confirm the exact target version, then downloads and SHA-256-verifies the release tarball, builds it, backs up the live install, and installs it through one confirmed privileged step. Progress is shown phase by phase (downloading, verifying, building, installing, verifying, restarting) rather than a bare spinner, because the whole operation restarts Quickshell partway through and can take several minutes. Declining the privileged step, or a build failure, costs nothing but time: the live install is untouched. A system install that stops part-way says so, and points at the backup to roll back to. Whatever failed, Settings -> System shows the reason, not just the step it failed in.
Switch between the stable and preview channels at any time; preview
carries a visible warning that pre-release builds are not release-qualified.
Every backup taken before an update is listed with its version and date, each
with its own Roll back action.
See Updating and Rollback for the full walkthrough, including how to roll back from a bare TTY if a session will not start — Settings has no way to help with that case, since there is no UI to click when the desktop itself will not come up.
Timezone, locale and network time
Load choices reads the reported timezone or locale catalog before you can select anything — a value must come from that exact list, not free text. Filter with the search box, select one, then Review change… reads a fresh preview against the system’s current state before showing a confirmation card. Apply change cannot be undone once sent; Cancel only dismisses the preview itself without changing anything. System locale changes apply to new sessions — Settings never logs you out to apply one.
Automatic network time shows whether NTP is enabled and whether the clock was synchronized as of the last read, with Review enable…/ Review disable… buttons that go through the same preview-then-confirm flow.
A live change to any of these — from this session or another — invalidates a preview or confirmation prepared against the state it read, with a message asking you to review a fresh one rather than silently applying stale data.
Accounts, printers and software sources
Below the update controls, System also lists Accounts, Password, Printers, and Software sources. Each launches a separate, already-trusted administration tool — Settings shows a confirmation card first (“Open tool?”) because closing Settings afterward does not close the tool or undo anything it does, and a successful launch is not proof the tool’s own work finished. Cancel discards the prepared launch without starting anything.
Printers opens system-config-printer. Password opens passwd in
your configured terminal — Settings never reads or stores your password
itself. Accounts and Software sources are unavailable on Arch: no
account-management GUI or interactive repository editor is packaged for it.
Edit /etc/pacman.conf directly for repository changes; see
Configuration for where lyona’s own managed files
live. A disabled button always states why, rather than leaving it
unexplained.
Below the launch buttons, System also lists the accounts and software sources the system currently reports, read-only.
Updating and Rollback
lyona updates itself in place from release tarballs, either through
Settings -> System or from a terminal with lyona-update. Both paths use the
same helper, so anything you can do from Settings you can also do from a
terminal — including the one thing Settings cannot help with: recovering a
machine whose desktop will not start.
Checking for updates
lyona-update check
Reports the installed version, the version available on your configured
channel, and one of current, behind, ahead, downgrade-offered,
unknown, or offline. offline is a normal outcome, not an error: if the
update server cannot be reached, check still reports the installed version
and exits successfully. unknown with “Nothing has been published on the
CHANNEL channel yet” means the server answered but has no release there; see
Channels. Nothing is written to disk by check.
check_on_login=true (the default) runs one check shortly after Quickshell
starts, jittered so a machine with several users logging in around the same
time does not all hit the update server at once. It never runs more than once
per session, and a behind result only shows on the panel’s update icon and in
the Control Center — it never applies anything on its own.
The panel’s update icon
When updates are available, the panel shows an update icon with a count, left of the Bluetooth icon. The count is the system packages and Flatpak apps waiting to be updated, plus one when a new lyona release is out. Hover it for the details; click it to open Settings -> System, where updates are run. The panel itself installs nothing.
-
Packages are counted with
checkupdates(frompacman-contrib). It syncs a private copy of the package databases and never takes pacman’s lock, so counting cannot interfere with a runningpacman. Packages from the AUR are not counted. -
Flatpak apps are counted with
flatpak remote-ls --updates, for the system and the user installation each. If one cannot be checked, Settings says which. -
When it checks:
- a few minutes after you log in;
- every 6 hours (choose 1, 3, 6, 12 or 24 in Settings -> System);
- when NetworkManager reports that you are connected again;
- when you press Check for updates in Settings -> System.
One check runs at a time. After a successful check, a reconnect within 10 minutes does not check again. The lyona release is re-checked this way only while
check_on_loginistrue. -
When it shows: only while something can be updated, and not while an update is running (the progress icon shows then). Turn on “Show the panel icon when everything is up to date” in Settings -> System to keep it.
-
Its settings are in
~/.config/lyona/update-indicator.conf, private to you, written bylyona-update-indicator. Runlyona-update-indicator checkto see what the panel would count.
Updating in a terminal
Settings -> System -> System packages and Flatpak runs an update in your own terminal, where you see the full plan and output and answer the tool’s own confirmation. Nothing is confirmed for you. This sits beside the PackageKit preview further down the page (System updates); use whichever you prefer. While a PackageKit update runs, Update packages is unavailable, so the two never contend for the package database. lyona’s own releases have their own section, lyona, above.
-
Update packages runs
yay -Syuwhenyayis installed, so packages built from the AUR (such as the legacy NVIDIA drivers) update too, andsudo pacman -Syuotherwise. -
Update Flatpak apps runs
flatpak update --system, thenflatpak update --user. If one fails, the other still runs, and the result says which did not update. The system installation asks for authorization through Flatpak’s own prompt. -
The result comes from the command, not from the window. Settings shows “Updated”, “Not updated” with the exit status (declining the plan counts), or that the terminal closed before the update finished. The window stays open after the update until you press Enter. The panel count is read again when it closes.
-
Floating: the terminal tiles. Turn on Float the update terminal to float it. That uses the window class
lyona-update-float, which a new install’swindow-rules.tomlfloats. An existing file is never edited for you; if yours predates this, Settings shows the line to add inside itsrulesarray:{ class="lyona-update-float", isfloating=1 },Saving the file applies it through dwm’s hot reload. Terminals other than Alacritty, kitty, st and xterm cannot be given the class, and always tile.
Topgrade
A recommended or full install also has Topgrade.
Run topgrade in a terminal to update everything it finds in one go:
- system packages, through
yayorpacman; - Flatpak apps;
- cargo and rustup, when you have installed them;
- firmware;
- and more.
It is a separate path from Settings -> System:
- Settings previews package updates through PackageKit, or runs them in a terminal, and keeps the panel’s update count current.
- Topgrade goes further than packages, with its own prompts. It does not
update lyona itself out of the box; use
lyona-updateor Settings for that, or add it to Topgrade yourself (below).
The installed Topgrade is the AUR’s topgrade-bin package, so pacman -Syu
does not upgrade it. Topgrade updates it itself, through yay, each time it
runs, as it does every other AUR package. To reinstall it, run
install-topgrade --force.
Adding lyona to Topgrade
Topgrade runs your own commands as steps of its run, from the [commands]
section of its configuration file. lyona doesn’t add one for you, because the
file is yours. To have topgrade update lyona too:
-
Open Topgrade’s configuration. This creates it, at
~/.config/topgrade.toml, the first time:topgrade --edit-config -
Find the
[commands]section (it is there, commented out), and add a line under it:[commands] "lyona" = 'if [ "$(lyona-update check --json | jq -r .state)" = behind ]; then lyona-update apply; fi'Use single quotes around the command, as above: it holds double quotes of its own.
-
Run
topgrade. Its summary at the end lists lyona as a step of its own.
What the command does. lyona-update apply installs the newest release
every time it runs, even one you already have. So the command first asks
lyona-update check (see Checking for updates) and
applies only when your install is behind:
check says | The step |
|---|---|
behind | runs lyona-update apply: the same update as in a terminal, with its backup and checks |
current | does nothing |
offline | does nothing; the next run tries again |
ahead, downgrade-offered or unknown | does nothing; nothing older is ever installed from Topgrade |
What to expect while it runs:
- Confirmation:
applyasks before it installs, in Topgrade’s terminal. To skip that question, changelyona-update applytolyona-update apply --yes. - Authorization: installing the system files needs root. In a desktop
session that is a polkit prompt; otherwise
sudoasks for your password. - Your channel: it follows the channel you chose (see Channels).
On
preview, Topgrade installs pre-releases too. - A failed update shows as a failed step in Topgrade’s summary, and leaves your install as it was, as described in Applying an update.
Your shell: Topgrade runs the command with your login shell. The line above works in bash and zsh. With fish, use this instead:
"lyona" = 'if test (lyona-update check --json | jq -r .state) = behind; lyona-update apply; end'
To run only this step, use topgrade --only custom_commands. This runs
every command in your [commands] section. To stop Topgrade updating
lyona, delete the line.
Applying an update
lyona-update apply --version 2026.10.0-beta.6
Nine steps, in this exact order, so an interruption at any point is always recoverable:
- Download the release tarball to
$XDG_STATE_HOME/lyona/updates/. - Verify its SHA-256 against the published release digest, and, for a release
from
2026.10.0-beta.2on, its signature withcosign, before unpacking it. An earlier release has no signature: it is installed on its digest alone, through the “NOT verified” prompt (below). - Unpack it, and copy your
config.hinto the build:~/.config/lyona/config.h, or a checkout’sconfig.hwhen run from one (see Configuration). - Build it, unprivileged, so a compile failure costs you nothing but time.
- Back up the live install.
- Install the system files through one confirmed privileged step
(
lyona-update-root, authenticated through polkit), then install the user-level files. The privileged step does not trust the unprivileged build: it makes its own root-owned copy of the tarball (read with your permissions), checks the digest and the signature again on that copy, against lyona’s release workflow (fixed in the helper, not taken from the caller), then unpacks and rebuilds only that copy before backing up the system files and installing. The one program that includes yourconfig.h,dwm, is built there as lyona’s own system user,lyona-build(throughsetpriv), never as root and not as the sharednobody: aconfig.hcan include only files everyone can read, and the password prompt says aconfig.his compiled in. The step needssetpriv(util-linux) and thelyona-buildaccount, which the install creates (systemd-sysusers, from/usr/lib/sysusers.d/lyona-update.conf); nothing else runs as it, and the build refuses to start while anything does.
What the checks prove. The SHA-256 digest comes from the release page (or a
short-lived cache in ~/.cache/lyona/), so a match proves the download is
intact. The signature proves it is genuine: from 2026.10.0-beta.2 on, each
release is signed by lyona’s own release workflow on GitHub,
and lyona-update refuses one whose signature is missing or does not verify.
It needs cosign, which the install provides, and the network, for Sigstore’s
trust root. The privileged step checks the signature again itself, so its
usual prompt (“Authentication is required to install a lyona system update”)
only ever installs a signed release that is not older than the one installed. A
release from before signing, or an
offline file you vouch for with --sha256, is installed on its digest alone,
says so, and asks through a different prompt: “…install a lyona update whose
signature was NOT verified”. Approve either only for an update you started, and
that one only for a file you checked yourself.
7. Verify every installed file matches what was staged.
8. Rewrite the provenance record (/etc/lyona-release,
$XDG_STATE_HOME/lyona/install.state) — last, and only after step 7
succeeds, so an interrupted update never claims success.
9. Restart Quickshell when it is safe to; report if dwm itself also needs a
session restart.
Declining the privileged-step confirmation, or a build failure, leaves the
live install completely untouched and exits non-zero. Should the system install
itself stop part-way (a full disk, say), the update says so, names the backup
it took first, and tells you to run lyona-update rollback, which restores the
release installed before. Whatever the failure, its reason is what the progress
popup, the notification and Settings -> System show, and the log has the rest.
Before it builds, an apply checks the packages the new release needs, from the
release’s own package list. If one it requires is missing, it stops, changes
nothing, and prints the command to install it, for example
sudo pacman -S --needed xdotool. Run that, then update again; Settings shows the
same message. A missing desktop package (Picom, light-locker, …) is only a
warning: the update goes ahead and the features that use it stay unavailable.
It prints the command to install it too, and so do the notification and
Settings -> System once the update is in. An update never installs packages, so
a release that adds one (as wireless-regdb, iw and xorg-xmessage were
added after 2026.10.0-beta.6) leaves it to that command on a system installed
before it:
sudo pacman -S --needed wireless-regdb iw xorg-xmessage
Watching an update
An apply takes a few minutes and restarts Quickshell part way through, so the progress is shown outside Settings and survives that restart:
- A progress popup appears under the panel while an update runs, showing the current step (downloading, verifying, building, installing, restarting). Hide tucks it away without stopping anything.
- A panel indicator appears next to the battery while an update runs and stays after it ends until you dismiss it; a successful update dismisses itself after 20 seconds, a failed one never does. Click it to bring the popup back. When the shell restarts mid-update, both reappear on their own, still in progress or showing how it ended. A shell that starts up more than ten minutes after an update ended does not show it, and neither does one left “in progress” for over an hour by a crash.
- A notification reports how an update or rollback ended. A failure is critical and names the log; declining the confirmation prompt is not treated as a failure and sends nothing.
- Cancelling the password prompt cancels the update (or rollback): nothing
is changed, and the popup and Settings -> System say “Update cancelled”,
with no notification. Dismissing the dialog cancels from a terminal too.
Started from a terminal,
lyona-updateasks for your password withsudoonly when polkit could not authorize at all: no agent to ask, or not allowed. - Settings -> System shows how the last update or rollback ended, its reason when it failed or was cancelled, for a day after it.
- A successful update removes what it downloaded and built under
~/.local/state/lyona/updates; a failed one leaves it there, to look into. Rollback uses the backups, not these files. - View log in the popup, or View update log under Settings -> System,
shows the last 64 KiB of
$XDG_STATE_HOME/lyona/update.log. Each apply or rollback starts a fresh log holding its full output (build output included), readable only by you; a dry run leaves the previous log alone.
The whole apply asks you to authenticate once: the installation of system files is a single privileged step, and a step that ran and failed is never retried through a second prompt.
Useful flags:
-
--allow-downgrade— required to install a version older than what is installed. An older release is installed only with its signature checked (never with--sha256alone), and through its own prompt, “Authentication is required to install an OLDER lyona release”, not the usual one; the progress names both versions before it. To return to what was installed before an update, uselyona-update rollbackinstead: it needs no download and keeps your settings as they were. Settings offers the same as Go back to when the channel’s release is older than the installed one. -
--dry-run— builds and reports exactly what would be written, without installing anything. -
--file PATH— install an already-downloaded tarball; still requires--version, and still verifies the checksum and the signature, which it downloads. Give the signature you downloaded with the tarball with--bundle FILE(the release’slyona-<version>.sigstore.json); it is needed for a version that is not the newest on your channel. Checking a signature still needs the network, for Sigstore’s trust root.--sha256 HASHgives the checksum yourself:HASHis the 64-character hexadecimal value on the tarball’s line in the release’slyona-<version>-SHA256SUMS(the first field). With--bundletoo, both are checked. Given alone, for a machine with no network, the signature is not checked: you vouch for the file, and the install asks through the “NOT verified” prompt. A release older than the installed one is never installed this way: it needs its signature.lyona-update apply --file ~/lyona-2026.10.0.tar.gz --version 2026.10.0 \ --sha256 HASH -
--from-checkout DIR— removed. The privileged step installs only releases it has verified itself. To install a local development checkout, runsudo make install-system && make install-userin it, orscripts/dev-sync-install.sh, where you type the command that runs as root. -
--yes— skip the interactive confirmation prompt (Settings always passes this, since it shows its own confirmation first).
Channels
lyona-update set-channel stable # or: preview
stable tracks GitHub’s Latest release. preview tracks the newest
published release including pre-releases, which are not release-qualified —
see Releasing
for what that means in practice. The channel is stored in
~/.config/lyona/update.conf, seeded on first use and never overwritten
except by set-channel itself. Settings -> System sets it too, under
Channel.
While lyona is in beta, every release is a pre-release, so the stable
channel has nothing to offer yet. A pre-release install (a version such as
2026.10.0-beta.1) is seeded on preview for that reason; one already on
stable gets unknown and “Nothing has been published on the stable channel
yet”, with the command to switch:
lyona-update set-channel preview
offline, by contrast, means the release server could not be reached at all.
Rolling back
lyona-update rollback --list
lyona-update rollback # the newest backup
lyona-update rollback --backup 20260828T153709Z-1472673
Every apply backs up the live install first, before writing anything, so
rollback always has something to restore to. A backup has two halves under the
same id: your own files (the managed Quickshell config, and in backups taken
before an earlier release moved it, the Lyona data directory) in
~/.local/state/lyona/live-update-backups/<id>/, and the system
files, which the privileged helper copies as root, just before installing, into
/var/lib/lyona/backups/<id>/, readable only by root. A rollback restores the
system files from that root-only copy and never from anything in your home
directory, so nothing another program running as you could have changed is ever
installed as root. The helper keeps the newest 5 system backups. The system
half holds the commands, the privileged helpers, PREFIX/lib/lyona and
PREFIX/share/lyona whole, the polkit actions, the cursor and GTK themes, the
man page, the session file and /etc/lyona-release; a rollback puts them all
back, and restores your install record
(~/.local/state/lyona/install.state) with them, so a regression in the shared
code is undone too (#324). The backup also lists the managed files the update
is about to add, such as a command new in that release, and a rollback
removes them, so an older release is not left with a newer release’s helpers
(#456). Your own files
are restored whole: the backed-up Quickshell config, and the data directory when
the backup holds one, replace the current ones, so nothing a newer version added
is left behind. An older backup’s data directory still holds that version’s
session scripts and defaults, which the restored version needs; the next update
removes them again.
It refuses to restore a backup whose checksums do not match, or one taken against
a different install environment (prefix, config, or data directory) than the one
it would be restored into — it will not guess. A backup taken before system
backups moved to /var/lib/lyona/backups has no system half, and rollback
refuses it rather than restore only your own files.
Rolling back from a TTY when the desktop will not start
This is the case that matters most, and it is why rollback is built the
way it is. If an update leaves you without a working session, you are at a
text console, not a desktop — so rollback does not depend on Quickshell,
D-Bus, or a running polkit agent. It authenticates with sudo directly when
no graphical polkit agent is reachable.
-
Log in at the TTY (Ctrl+Alt+F2 through F6 if X is stuck on the active console).
-
List what is available to restore:
lyona-update rollback --list -
Restore the newest backup (or name one from the list):
lyona-update rollback -
When it finishes, start the session again:
startxor log in normally if you use a display manager.
If rollback itself reports a checksum or environment mismatch, do not
force past it — that check exists specifically to stop a restore from making
things worse. Open an issue with the exact message instead.
How lyona Works
lyona uses a maintained fork of dwm, a compact window manager for X11. A window manager controls where application windows appear, how they are arranged, and which window receives input. Unlike a full desktop environment, upstream dwm focuses on this core job and is configured primarily in source code.
The dwm community traditionally distributes optional features as source-code “patches.” lyona already integrates and maintains a curated set of those ideas alongside its own runtime configuration, Quickshell desktop layer, Settings experience, and system helpers. Users do not need to find or apply patches themselves.
This page documents the major technical additions to the window-manager core and how they support the complete desktop experience.
Window Management Patches
Pertag
Each tag independently remembers its layout, master count, and master/stack sizing. Switching tags restores the previous layout for that tag.
Cfact
Assign per-window size weights within the stack area. Windows are no longer forced to equal height.
| Keys | Action |
|---|---|
Super + Shift + H | Grow this window’s slot |
Super + Shift + L | Shrink this window’s slot |
Super + Shift + O | Reset to equal sizing |
Movestack
Reorder windows within the stack without using the mouse.
| Keys | Action |
|---|---|
Super + Shift + J | Move window down |
Super + Shift + K | Move window up |
Window Swallowing
When a GUI application is launched from a terminal, it replaces the terminal in the layout. Closing the app brings the terminal back.
Controlled via window rules in config.h:
{ "Alacritty", NULL, NULL, 0, 0, 1, 0, -1 }, /* isterminal = 1 */
Fullscreen (3-State)
Three fullscreen modes available:
| Mode | Keys | Description |
|---|---|---|
| True fullscreen | Super + M | The focused window only: hides the bar, takes the full screen |
| Fake fullscreen | Super + Shift + Y | Looks fullscreen, bar still usable |
| Monocle layout | none (the Control Center’s Window layout row) | A layout, for the tag: one window at a time, bar visible |
Bar & EWMH
Quickshell Integration
The managed Quickshell layer reads dwm workspace and active-window state through
EWMH-compatible helpers so the panel stays synchronized with X11 state.
The Control Center includes a Power page for screen DPMS and automatic locking
settings backed by ${XDG_CONFIG_HOME:-$HOME/.config}/lyona/power.conf.
EWMH Compliance
Implements _NET_WM_STATE, _NET_CURRENT_DESKTOP, _NET_NUMBER_OF_DESKTOPS, and related atoms so external tools and taskbars work correctly.
Window Icons
Title bar icons via _NET_WM_ICON. Applications that set this atom display their icon in the bar.
Systray
A built-in system tray is compiled in and can be configured in config.h.
Visual
Noborder
When only one window is visible on a tag, its border is automatically removed for a cleaner look. Borders return when a second window appears.
Cursor Warp
When focus moves to a different window or monitor (via keyboard), the mouse cursor warps to the center of the newly focused window.
Live Configuration
TOML Hotkeys (hotkeys.toml)
Keybindings are parsed from ~/.config/lyona/hotkeys.toml at runtime. Edit and save — bindings update without recompiling or restarting dwm.
TOML Themes (themes.toml)
Colors for dwm, terminal, GTK, and Qt are sourced from ~/.config/lyona/themes.toml.
Save the file to apply a new theme instantly across supported apps.
Scripts & Utilities
| Script | Description |
|---|---|
dwm-controlcenter | Quickshell control center (Super+F1) |
lyona-shell | Opens a part of the shell: launcher toggle, overview toggle, controlcenter open|toggle|openKeybinds, power toggle, power confirm logout|reboot. The default keybinds call it; use it in your own hotkeys.toml rather than Quickshell’s IPC, which can change between releases |
dwm-keybinds | Opens the keybind viewer (Super+/) |
dwm-quickshell-launcher | Indexes desktop entries and launches ChatGPT with a native-first web fallback |
dwm-screenshot | Cursor-free maim wrapper (screen, full, gui, clip modes) |
dwm-settings-theme | Previews, applies, resets, and recovers theme selection transactionally |
theme-apply.sh | Converges the active theme from user or managed themes.toml across supported apps |
webapp-create | Creates a web app shortcut |
webapp-launch | Launches a URL as a standalone web app window |
autostart.sh | Runs programs on dwm start |
check-deps.sh | Checks all required dependencies |
disable-powersaving | Disables DPMS and screen blanking |
Multi-Monitor
Xinerama support keeps tags independent per monitor. Windows can be moved
between monitors with Super + Shift + ,/..
Troubleshooting
Run the dependency checker first — it covers most common issues:
dwm-diagnostics
Or use the Control Center → System Health.
An AppImage does not open or start
Opening a new AppImage asks first (Add and run, Add only, Cancel). If nothing seems to happen, look for that question in the top-right corner; closing it cancels.
Opening an AppImage uses lyona-appimage. If it says the file is not an
AppImage it can read, the file is unsupported or unreadable: not a type-2 x86
AppImage (very old type-1 ones are not supported), or damaged or truncated, for
example by an interrupted download. Run it from a terminal to see why it
stopped:
lyona-appimage open ~/Downloads/Some.AppImage
lyona-appimage list
An AppImage that fails right after it starts is reported (“did not start”), and
one that is in the launcher but does not start usually needs libfuse.so.2:
install fuse2 (sudo pacman -S fuse2; the recommended desktop includes it).
A file whose name has a control character or a backslash is refused: rename it
first. Remove one with lyona-appimage remove NAME. Prefer Gear
Lever? Run install.sh with --with-gearlever, or install-gearlever.
Gear Lever does not open
Gear Lever requires Flatpak’s document portal. If launching it prints a
bwrap: Can't find source path /run/user/.../doc/by-app/... error, the portal
process has outlived its FUSE mount. Repair the current user session with:
systemctl --user restart xdg-document-portal.service
flatpak run it.mijorus.gearlever
The recommended and full installers include Flatpak and the GTK portal; Gear
Lever, from Flathub for the user, only with --with-gearlever. To repair only the
application setup from an installed lyona checkout, run:
install-gearlever
It refuses a flathub remote that has signature verification disabled, is
disabled, or points at an unofficial URL, and says which. Fix or remove that
remote (flatpak remote-modify, flatpak remote-delete --user flathub) and run
it again; dwm-flatpak-setup --user checks the remote on its own.
dwm Won’t Start
Black screen / returns immediately to login:
- Run
dwm-diagnosticsand resolve any required X11/session failures. - Preview required packages with
./install.sh --dry-run --profile core. - Check
~/.xinitrcexists and ends by starting dwm, as the shipped one does:dbus-run-session -- sh -c 'exec dwm' - Run
startxfrom a TTY to see error output in the terminal
dwm: cannot open display:
- You must launch dwm from a TTY, not an existing X session
- With a display manager, choose the lyona session; its file is
/usr/share/xsessions/dwm.desktop
No Status Bar / Quickshell Missing
- Install the recommended desktop layer:
./install.sh --profile recommended - Verify the managed config exists:
ls ~/.config/quickshell/shell.qml - Restart it with Super + Shift + R, or
dwm-quickshell-controlcenter action restart-quickshell. Any shell key (Super + R, the power keys) starts the shell when it is not running, then does what it was pressed for; when it is running but still starting, as early in a login, the key waits for it instead (#394). If the shell cannot start or never answers, a message names the key to try again (Super + Shift + R by default); the message for a power key also names the key that quits the session. Started by hand instead, a second Quickshell does not get the hotkeys - Check fonts:
fc-list | grep -i meslo - A bar of your own, instead of the lyona panel, must reserve space at the top
or bottom of the screen: a dock window with a strut (
_NET_WM_STRUT_PARTIAL; in Quickshell, aPanelWindowwith a non-zeroexclusiveZone). dwm takes only such a dock as the bar. One that reserves nothing is shown as a plain dock, and windows are not kept clear of it (#322).
Terminal Won’t Open (Super+X)
- Run
alacrittyfrom an existing shell to inspect its error directly - Install Alacritty with
sudo pacman -S alacritty - Confirm the fixed terminal in
~/.config/lyona/hotkeys.toml:[vars] terminal = "alacritty"
Herdr is an optional terminal workspace, not a graphical terminal emulator.
Install it explicitly and use DWM_HERDR=1 dwm-terminal to run it inside
Alacritty. The default Super+X binding remains plain Alacritty.
Browser Won’t Open (Super+B)
- Run
dwm-default-apps statusto inspect the current default browser - Run
dwm-default-apps browsersto list installed browser desktop files - Set one with
dwm-default-apps set-browser firefox.desktop - Open Settings -> Defaults to inspect provider details, candidates, and the Restore Previous action
- Ensure
xdg-utilsis installed soxdg-settings,xdg-mime, andxdg-openare available
Startup Application Change Failed
- Open Settings -> Defaults and inspect the entry origin, effective state, and detail. Malformed or conditional vendor entries are intentionally not rewritten.
- Changes apply at the next login; Settings does not start or stop the application in the current session.
- A stale-revision error means the entry changed after it was displayed. Use Refresh and retry.
- Reset to vendor removes only the managed user override. Existing vendor desktop files are never edited.
Themes Not Applying
- Confirm
themes.tomlis at~/.config/lyona/themes.toml - Check the
[active]section has a valid theme name - Manually trigger:
kill -USR1 $(pidof dwm) - Run
theme-apply.shdirectly to see any errors
Keybinds Not Working
- Check
~/.config/lyona/hotkeys.tomlfor mistakes. A “dwm: bad config” notification names the first problem. When only some bindings are wrong (an unknown key or function, a tag outside 0-8, a missing comma), dwm loads the rest and says how many it skipped. A file dwm cannot use at all (empty, or cut off inside its array): at login dwm falls back to the shipped defaults, and when you save it while running it keeps the keys you already had. dwm lists every entry it skips on its standard error: the terminal you ranstartxfrom, or your display manager’s session log (for LightDM,~/.xsession-errors). - Verify the key name is correct (use
xevto find X11 key names). - If neither your file nor the shipped default can be loaded, only two keys work: Super+x opens a terminal and Super+Shift+q quits dwm.
Multi-Monitor Issues
- Tags not syncing across monitors: run
dwm-diagnostics - Cursor doesn’t follow focus: verify cursor warp is enabled in
config.h(cursorwarp = 1) - Persistent resolution or positioning: run
dwm-display-setup detect, thendwm-display-setup. The wizard previews changes before writing Xorg config. - Bad persistent layout: run
dwm-display-setup rollback, then log out and back in. From a TTY, remove/etc/X11/xorg.conf.d/90-lyona-display.confif Xorg cannot start. - TearFree is enabled only when the active Xorg driver exposes a compatible option or RandR property. Unsupported drivers are left unchanged.
- NVIDIA Full Composition Pipeline is enabled in generated persistence only
when the relevant output uses the NVIDIA kernel driver and an NVIDIA Xorg
provider is available, including supported hybrid configurations. Run
dwm-display-setup capabilitiesto inspect the detected fallback before saving a layout. - Display layout profiles: run
dwm-display-profile diranddwm-display-profile templateto create optionalxrandrprofiles - Settings > Displays keeps asking “Keep these display settings?”: choose
Discard to forget the preview and keep the current layout for this
session, or Keep current to keep it at the next login too. From a
terminal,
dwm-settings-display preview-statusshows the preview’s token, anddwm-settings-display discard TOKENremoves it without applying anything.
NVIDIA / Suspend Issues
- Black screen on wake: run
scripts/nvidia-suspend-test.shto diagnose - DPMS/screensaver issues: use Control Center -> Power, or run
scripts/disable-powersavingto disable blanking and DPMS for the current session
Wi-Fi is slow to connect or 5 GHz fails
Check the kernel log first:
journalctl -b -k | grep -E 'regulatory|timed out'
failed to load regulatory.db: the regulatory database is missing, so Wi-Fi stays on the world domain, where 5 GHz is passive only. Install it withsudo pacman -S wireless-regdb(lyona installs it since #365), then reboot.- No Wi-Fi country:
iw reg getshowscountry 00. The image installer sets the country from your timezone in/etc/modprobe.d/lyona-regdom.conf. To set or change it yourself, uncomment your country’s line in/etc/conf.d/wireless-regdom(for exampleWIRELESS_REGDOM="DE") and reboot; that setting wins over the installer’s. - Some chips stay unreliable on 5 GHz even with a country set, such as the
Broadcom BCM43224 (
brcmsmac) in older MacBooks. Keep such a connection on 2.4 GHz:nmcli con mod "<connection name>" 802-11-wireless.band bg. - On those Broadcom chips the log also shows
b43failing to probe the card (probe with driver b43 failed with error -524). That is harmless:brcmsmacdrives the card. lyona does not blacklistb43.
A Bluetooth device’s battery is not shown
Settings > Power and the Control Center list the batteries UPower reports. Most
wireless mice and keyboards on a USB receiver (for example Logitech’s) report
theirs through the kernel. Some Bluetooth devices report a battery only when
BlueZ’s experimental battery provider is on, which lyona does not change for
you. To turn it on, set Experimental = true under [General] in
/etc/bluetooth/main.conf, then sudo systemctl restart bluetooth. Check what
UPower sees with upower --dump.
Picom / Compositor
Picom is part of the lyona desktop: the window overview’s previews need it. dwm and the panel work without it; the overview then shows icon-and-title cards.
Picom does not start
At login, a notification says “Picom could not start” (with the path of its log, and a pointer to the XRender backend in Settings > Appearance > Compositor, which works on most GPUs) or “Picom is not installed”. It is shown once. To see why:
dwm-settings-picom status
dwm-settings-picom start
start prints the reason and the log path. Common causes: an old or broken GPU
driver, or a virtual machine without 3D acceleration. Choose XRender in
Settings > Appearance > Compositor: it needs no GPU acceleration. If it is not
installed: sudo pacman -S picom. Start Picom with dwm-settings-picom start, not
picom alone: lyona’s default configuration leaves the backend for the helper to
choose, and Picom 13 does not start without one.
Stopping Picom
Control Center > Restart Picom restarts it. To stop it while troubleshooting,
run dwm-settings-picom stop: window previews are off until it starts again, and
it starts again at the next login.
The shell’s menus work without Picom too. Each one is then only as big as the menu, and a click outside it still closes it. Unlike with Picom, that click also reaches the window you clicked.
Artifacts
Restart picom via the Control Center (Quick Actions → Restart Picom) or:
dwm-settings-picom restart
If artifacts persist, choose XRender or GLX in Settings > Appearance >
Compositor. EGL is experimental. Automatic selection uses the active renderer
and retries XRender if automatic GLX startup fails. Existing configuration choices
and PICOM_BACKEND=glx or PICOM_BACKEND=egl session overrides remain respected.
Run dwm-settings-picom status to see the configuration path and effective
backend. The controls remain available while Picom is stopped. Configuration
errors and concurrent edits are reported without silently replacing your choices;
activation errors identify a recovery backup and session log.
An update fails to build with “Permission denied”
lyona-update builds dwm, the one program that includes your config.h, as
an unprivileged user (lyona’s own lyona-build), never as root. A config.h that includes a
file only you or root can read fails there with Permission denied, and
nothing is installed; the reason is in the update log (Settings -> System,
View update log). Make the included file readable by everyone, or keep
what it holds in config.h itself. The runtime TOML files are the supported
way to customise (docs/src/configuration.md).
Still Stuck?
- Open an issue: github.com/technicks89/Lyona/issues
- Run the full check:
bash scripts/check-deps.sh