- Distro: Artix Linux | Init: dinit | DM: ly
- Compositor: labwc | Desktop Shell: Noctalia v5 (native C++ binary)
- Audio: PipeWire + WirePlumber | Session: elogind + turnstile
| Category | Packages |
|---|---|
| Init/Session | dinit, turnstile, elogind |
| Compositor | labwc, wlroots |
| Audio | pipewire, wireplumber, pipewire-pulse |
| Portals | xdg-desktop-portal-wlr, xdg-desktop-portal-gtk |
| Screenshots | grim, slurp |
| Utilities | wlsunset |
| Desktop Shell | noctalia-git (v5 native binary), noctalia-qs (Quickshell library) |
| D-Bus | dbus |
| Bluetooth | bluez, bluez-utils, bluez-dinit |
| Keyring | gnome-keyring |
| Path | Purpose |
|---|---|
~/.config/dinit.d/ |
User services |
~/.config/labwc/rc.xml |
labwc config, keybinds |
~/.config/labwc/environment |
Session environment variables |
~/.config/noctalia/config.toml |
Noctalia v5 main config (user edits) |
~/.local/state/noctalia/settings.toml |
Noctalia v5 settings/app-managed overrides |
/etc/pam.d/ly, /etc/pam.d/ly-autologin |
PAM for turnstile |
/etc/dinit.d/elogind, /etc/dinit.d/turnstiled |
System seat management services |
User-defined env vars for dinit services: ~/.config/dinit.d/environment (use env-file parameter)
Session vars (XDG, cursor, keyboard, etc.): ~/.config/labwc/environment
User services started by dinit (via turnstile) do NOT inherit the full user environment. Use env-file parameter to pass variables.
All user-defined environment variables should ONLY be defined in ~/.config/dinit.d/environment.
Critical: DBUS_SESSION_BUS_ADDRESS is required for Flatpak apps to access D-Bus portals.
Important: Always set HOME=/home/user in dinit environment to ensure terminals start at home directory.
The wayland-ready service waits for the Wayland socket using inotifywait (with polling fallback).
~/.config/dinit.d/environment and ~/.config/labwc/environment must be kept in sync.
- Use
dinitctl(system) ordinitctl --user(user services) - User services:
~/.config/dinit.d/, socket:/run/user/1000/dinitctl - Service types:
process(foreground),scripted,bgprocess(PID file) - DO NOT
kill -HUPuser dinit — it loses track of processes - Enable
log-type = bufferin all services to allowdinitctl catlogfor debugging
Labwc is started by ly (display manager), not by dinit.
Service dependency order:
dbus → gnome-keyring, pipewire → wireplumber + pipewire-pulse
dbus + wayland-ready → voxtype
wayland-ready → noctalia → wlr-randr
Current services:
wayland-ready— waits for Wayland socket usinginotifywaitwith polling fallback (one-shot)noctalia— desktop shell (/usr/bin/noctalia, waits-for wayland-ready, smooth-recovery, restart=on-failure)wlr-randr— display configuration (waits-for wayland-ready, one-shot)gnome-keyring— password storage (depends-on dbus)voxtype— typing daemon (depends-on dbus, waits-for wayland-ready)dbus,pipewire,wireplumber,pipewire-pulse— system services
- Use absolute paths for binaries
- Use
env-fileto pass environment variables to user services (NOT inline in command) - Use
type = processfor long-running services,type = scriptedfor one-shot commands - Use
waits-for(notdepends-on) for one-shot dependencies like wayland-ready - Use
smooth-recovery = truefor services that should restart without stopping dependents - Use
restart = on-failureinstead ofrestart = trueto avoid restart loops on clean exits - Dinit has no native file/socket watching;
wayland-readyusesinotifywaitwith polling fallback - Enable services at boot by symlinking to
~/.config/dinit.d/boot.d/
If user dinit doesn't start (dinitctl --user list fails), manually start it:
# Create boot service if missing
echo -e "type = process\ncommand = sleep infinity" > ~/.config/dinit.d/boot
# Create placeholder for system dbus
echo -e "type = scripted\ncommand = true\nlog-type = buffer" > ~/.config/dinit.d/dbus
# Start user dinit
nohup dinit -u -d ~/.config/dinit.d -p /run/user/1000/dinitctl > /tmp/dinit.log 2>&1 &
sleep 2
# Start services
dinitctl --user start dbus wayland-ready noctalia gnome-keyring voxtype wlr-randrLabwc is started by ly (display manager), not by dinit. Services that need the Wayland socket use wayland-ready service:
#!/bin/sh
# ~/.config/dinit.d/wayland-ready.sh
# Handles: inotifywait missing (polling fallback), file created but not yet a socket, race conditions
[ -S "$XDG_RUNTIME_DIR/wayland-0" ] && exit 0
if [ ! -d "$XDG_RUNTIME_DIR" ]; then
mkdir -p "$XDG_RUNTIME_DIR" 2>/dev/null || exit 1
fi
if ! command -v inotifywait >/dev/null 2>&1; then
echo "WARNING: inotifywait not found, falling back to polling" >&2
for i in $(seq 1 60); do
[ -S "$XDG_RUNTIME_DIR/wayland-0" ] && exit 0
sleep 1
done
exit 1
fi
while true; do
inotifywait -q -t 60 -e CREATE "$XDG_RUNTIME_DIR" || exit 1
[ -S "$XDG_RUNTIME_DIR/wayland-0" ] && exit 0
doneServices use waits-for = wayland-ready to wait for socket creation. Avoid depends-on for one-shot services (use waits-for).
Add pam_turnstile.so to PAM session in /etc/pam.d/ly and /etc/pam.d/ly-autologin. Without it, user dinit won't start at boot.
In /etc/turnstile/turnstiled.conf, set manage_rundir = yes to create /run/user/1000 at login. Without this, user dinit fails with "unable to open wayland socket: Invalid argument". Restart turnstiled after changing:
sudo dinitctl restart turnstiledelogind socket is owned by root:seat. Add your user to the seat group:
sudo gpasswd -a user seatLog out and back in for group membership to take effect.
- Services: pipewire → wireplumber (depends-on), pipewire-pulse
- Control:
wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ - OSD: Noctalia v5 has built-in OSD. Use
noctalia msgIPC:- Volume up:
noctalia msg volume-up [step] - Volume down:
noctalia msg volume-down [step] - Toggle mute:
noctalia msg volume-mute - Mic mute:
noctalia msg mic-mute
- Volume up:
- Keybinds are in
~/.config/labwc/rc.xml
Noctalia v5 uses Unix socket IPC at $XDG_RUNTIME_DIR/noctalia-$WAYLAND_DISPLAY.sock. Usage: noctalia msg <command> [args]
| Command | Description |
|---|---|
volume-up [step] |
Increase volume (default 5%) |
volume-down [step] |
Decrease volume |
volume-mute |
Toggle speaker mute |
volume-set <value> |
Set volume (percent or normalized) |
mic-mute |
Toggle microphone mute |
mic-volume-up [step] |
Increase mic volume |
mic-volume-down [step] |
Decrease mic volume |
mic-volume-set <value> |
Set mic volume |
| Command | Description |
|---|---|
session lock |
Lock screen |
session suspend |
Suspend |
session lock-and-suspend |
Lock then suspend |
session logout |
Log out |
session reboot |
Reboot |
session shutdown |
Shutdown |
| Command | Description |
|---|---|
panel-toggle launcher |
Toggle app launcher |
panel-toggle session |
Toggle session menu |
panel-toggle control-center |
Toggle control center |
panel-toggle clipboard |
Toggle clipboard |
panel-open <id> |
Open a panel |
panel-close [id] |
Close active or named panel |
settings-open / settings-close / settings-toggle |
Settings window |
| Command | Description |
|---|---|
wallpaper-random [connector] |
Random wallpaper |
wallpaper-get [connector] |
Print current wallpaper path |
wallpaper-set [connector] <path> |
Set wallpaper (persisted) |
| Command | Description |
|---|---|
brightness-up [target] [step] |
Increase brightness |
brightness-down [target] [step] |
Decrease brightness |
nightlight-toggle |
Toggle night light |
nightlight-force-toggle |
Toggle forced night light |
caffeine-toggle |
Toggle idle inhibitor |
theme-mode-toggle |
Toggle dark/light mode |
screenshot-region |
Interactive region screenshot |
screenshot-fullscreen [pick|monitor|all] |
Fullscreen screenshot |
media <next|previous|toggle|stop> |
MPRIS media control |
dpms-on / dpms-off |
Monitor power |
config-reload |
Reload config |
status |
Print state as JSON |
wifi-toggle |
Toggle Wi-Fi |
bluetooth-toggle |
Toggle Bluetooth |
power-set <profile> / power-cycle |
Power profiles |
dock-show / dock-hide / dock-toggle |
Dock visibility |
window-switcher [close] |
Open/close window switcher |
grim -g "$(slurp)" ~/Pictures/screenshot-$(date +%Y%m%d-%H%M%S).pngNoctalia v5 also has built-in screenshot commands: noctalia msg screenshot-region and noctalia msg screenshot-fullscreen.
wlsunset -S 07:30 -s 18:30 -t 3500 -T 6500 &Noctalia v5 has built-in night light (gamma control): noctalia msg nightlight-toggle, configured in settings GUI or ~/.local/state/noctalia/settings.toml under [nightlight]. If using Noctalia's night light, don't run wlsunset (they conflict).
| Error | Fix |
|---|---|
| Wayland socket not created / labwc "unable to create backend" | Set WLR_RENDERER=pixman in ~/.config/labwc/environment to force software rendering. Labwc uses libseat (elogind/turnstile) and falls back to headless backend if DRM is unavailable, not creating a wayland socket. |
| Socket missing | pgrep turnstiled, check /run/elogind/ |
| Missing boot dir | sudo mkdir -p /usr/lib/dinit.d/user/boot.d |
| Service restarting quickly | dinitctl catlog <service> |
| Orphaned process | Kill manually, then dinitctl --user start <service> |
| Bluetooth pairing | Install bluez-utils for bluetoothctl, start service with dinitctl start bluetoothd |
| polkit failing | Unload bad service: dinitctl --user unload polkit; polkit runs via D-Bus activation (no dinit service needed) |
| wlr-randr "failed to connect to display" | These services waits-for wayland-ready; check dinitctl --user status wayland-ready |
| Noctalia won't start | Check dinitctl --user status noctalia and dinitctl --user catlog noctalia. Ensure /usr/bin/noctalia exists. |
| Flatpak "Settings portal not found" / "dbus-launch" error | Add DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus to ~/.config/dinit.d/environment |
| Nautilus not remembering network passwords | Ensure gnome-keyring dinit service is running: dinitctl --user start gnome-keyring |
| Terminal opens to wrong directory (e.g., ~/.config/dinit.d) | Add HOME=/home/user to ~/.config/dinit.d/environment, then restart user services |
| "unable to open wayland socket: Invalid argument" | Set manage_rundir = yes in /etc/turnstile/turnstiled.conf and restart turnstiled |
| Noctalia IPC command not working | Ensure noctalia is running: dinitctl --user status noctalia. Verify socket: ls $XDG_RUNTIME_DIR/noctalia-* |
xdg-user-dirs-update
dinitctl --user reload <service>dinitctl listshows user services when user dinit is running- Socket:
/run/user/1000/dinitctl - If it fails with "No such file or directory", user dinit isn't running — start it manually:
nohup dinit -u -d ~/.config/dinit.d -p /run/user/1000/dinitctl > /tmp/dinit.log 2>&1 & sleep 2
- Turnstile sets
DBUS_SESSION_BUS_ADDRESSbut does NOT start dbus-daemon —~/.config/dinit.d/dbusis still required
Set --ozone-platform=wayland in the desktop file so launching via menu/app launcher uses Wayland:
- Copy the system desktop file to local:
cp /var/lib/flatpak/exports/share/applications/<app>.desktop ~/.local/share/applications/ - Edit
~/.local/share/applications/<app>.desktop, adding--ozone-platform=waylandto allExec=lines - Run
update-desktop-database ~/.local/share/applications/ - Set as default:
xdg-settings set default-web-browser <app>.desktop
For Brave: <app> = com.brave.Browser.desktop
For Chromium: <app> = org.chromium.Chromium.desktop
noctalia msg wallpaper-set <path>
noctalia msg wallpaper-random [connector]Edit ~/.config/noctalia/config.toml (TOML format, not JSON):
[wallpaper]
directory = "/home/user/Pictures/Wallpapers"
# Per-monitor paths are stored in ~/.local/state/noctalia/settings.tomlApp-managed wallpaper state is in ~/.local/state/noctalia/settings.toml under [wallpaper.monitors.<connector>].
dinitctl --user stop wlr-randr && dinitctl --user stop noctalia && dinitctl --user start noctalia && dinitctl --user start wlr-randrUse ~/.config/dinit.d/ for user services (NOT ~/.config/labwc/autostart or ~/.config/autostart/).
- Service:
sudo dinitctl start bluetoothd(system) ordinitctl --user start bluetoothd - Status:
sudo dinitctl status bluetoothd - Pairing: Install
bluez-utilsforbluetoothctl, or useblueman(GUI) - Config:
/etc/bluetooth/main.conf
- Service:
sudo dinitctl start zramen(system) — runs as swap - Status:
zramctl - Devices:
/sys/block/zram*
- Use chrony instead of ntpd — it's faster, more accurate, and handles intermittent connections better.
- polkitd runs via D-Bus activation (no dinit service needed)
- Binary:
/usr/lib/polkit-1/polkitd - D-BUS service file:
/usr/share/dbus-1/system-services/org.freedesktop.PolicyKit1.service - If a bad polkit dinit service exists, unload it:
dinitctl --user unload polkit
Lock+suspend is handled via labwc keybind in rc.xml:
- Keybind
XF86PowerOff→/home/user/.local/bin/lock-suspend - Script uses Noctalia v5 IPC:
noctalia msg volume-mute noctalia msg session lock-and-suspend
- Also mutes audio before suspending
Noctalia v5 handles logout gracefully via noctalia msg session logout. Internally it tries:
labwc --exit(graceful compositor exit)labwc -ekill $LABWC_PID SIGTERMloginctl terminate-session $XDG_SESSION_IDsystemctl --user stop graphical-session.targetloginctl terminate-user $USER
No more pkill -9 labwc — v5 uses graceful shutdown.
dinitctl --user stop wlr-randr && dinitctl --user stop noctalia && dinitctl --user start noctalia && dinitctl --user start wlr-randrThe ly display manager can be slow due to PAM overhead and redundant service spawning in ~/.bash_profile.
/etc/pam.d/ly-autologin — Minimal config (no auth checks, no gnome-keyring):
#%PAM-1.0
auth required pam_permit.so
account required pam_permit.so
password required pam_permit.so
session required pam_unix.so
session optional pam_turnstile.so
/etc/pam.d/ly — Manual login (requires pam_turnstile.so for user dinit):
#%PAM-1.0
auth requisite pam_nologin.so
auth requisite pam_unix.so
account required pam_unix.so
session required pam_unix.so
password required pam_unix.so
session optional pam_turnstile.so
Important: Both /etc/pam.d/ly AND /etc/pam.d/ly-autologin must have pam_turnstile.so in session. Without it in ly, user dinit won't start.
Key rules:
session required pam_unix.sois REQUIRED inly-autologin— without it, turnstile can't set up the session and user dinit won't start (/run/user/1000/dinitctlmissing)pam_turnstile.somust beoptional, NOTrequired— if it fails for any reason,requiredcauses PAM to reject the session and ly loops endlessly- Remove
pam_gnome_keyring.sofrom both files — gnome-keyring is managed by dinit, not PAM ly-autologinshould usepam_permit.sofor auth/account/password (nosystem-authinclude which pulls inpam_faillock)
Remove redundant service spawning — dbus and audio are managed by dinit:
# ~/.bash_profile — keep it minimal
[[ -f ~/.bashrc ]] && . ~/.bashrcRemove these lines (they add delay on every login):
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus— set by dinitenv-file- Manual
dbus-daemon --session --fork— dbus is a dinit service pkill -9 pulseaudio— irrelevant with PipeWire via dinit
- Check
/var/log/ly.logfor repeatedattempting autologinloops - If autologin keeps retrying, verify
ly-autologinPAM usespam_permit.so(notinclude login) - Profile sourcing (
/etc/profile+/etc/profile.d/*.sh) is unavoidable but should be fast