How Omarchy Uses systemd User Services for Per-User Daemon Management
Omarchy runs all background components as systemd user services, shipping unit files to /usr/lib/systemd/user/ and enabling them via install/enable-services.sh during first-run setup.
Omarchy is Basecamp's experimental Linux desktop environment built atop systemd. Rather than relying on system-wide daemons or ad-hoc background processes, Omarchy leans entirely on systemd user services to manage its per-user daemons. This article examines the complete lifecycle—from installation through runtime control—based on the actual source implementation in the basecamp/omarchy repository.
Installation and Unit File Placement
Omarchy ships its user service definitions in default/systemd/user/ within the source tree. During package installation, these files land in /usr/lib/systemd/user/, the standard location for system-provided user units.
Key unit files include:
default/systemd/user/omarchy-sleep-lock.service– Locks the session before suspenddefault/systemd/user/omarchy-crash-watch.service– Watches for crashes and forwards them to the UIdefault/systemd/user/omarchy-fcitx5.service– Starts the Fcitx5 input method for the user sessiondefault/systemd/user/omarchy-tailscale-receive.service– Handles incoming Tailscale packets for per-user networking
All services use Type=simple and launch corresponding Omarchy helper binaries (e.g., omarchy-system-sleep-monitor). The Restart=always directive ensures automatic recovery where appropriate.
Enabling Services at First Run
The installer handles one-time service activation via install/enable-services.sh. This script issues systemctl --user enable --now for each shipped unit:
# From install/enable-services.sh
systemctl --user enable --now omarchy-sleep-lock.service
systemctl --user enable --now omarchy-crash-watch.service
# ... and so on for each unit
This creates symlinks under the user's $HOME/.config/systemd/user/, ensuring units survive reboots and start automatically on future logins.
You can replicate this manually:
# Enable all Omarchy user services
for u in /usr/lib/systemd/user/omarchy-*.service; do
systemctl --user enable --now "$(basename "$u")"
done
# Or disable a single service
systemctl --user disable --now omarchy-fcitx5.service
Enabling Lingering for Background Operation
Some Omarchy timers and services must fire without an active login session—backups, automated updates, and similar background tasks. The installer ensures this via loginctl enable-linger "$USER", which allows the user-level systemd manager (systemd --user) to persist after logout.
The migration script migrations/1785608166.sh contains the logic that creates the lingering flag if needed:
# Ensure timers keep running after logout
loginctl enable-linger "$USER"
Verify lingering status for your user:
loginctl show-user "$USER" --property=Linger
Environment Variables and Drop-In Configuration
Certain services require additional environment variables or runtime options. The same migration (migrations/1785608166.sh) creates a drop-in at 90-omarchy-session-environment.conf specifically for omarchy-sleep-lock.service:
# Created by migrations/1785608166.sh
[Service]
Environment=OMARCHY_PATH=/home/user/.local/share/omarchy
Environment=WAYLAND_DISPLAY=wayland-1
This propagates critical session variables (OMARCHY_PATH, WAYLAND_DISPLAY) into the service's execution environment without modifying the base unit file.
Runtime Control and Monitoring
Users and Omarchy components interact with services through standard systemctl --user commands:
# Check status of a service
systemctl --user status omarchy-sleep-lock.service
# Restart a service after configuration changes
systemctl --user restart omarchy-crash-watch.service
# List all loaded Omarchy units
systemctl --user list-unit-files | grep omarchy
# View live logs
journalctl --user -u omarchy-sleep-lock.service -f
Resource Management and OOM Protection
Omarchy services run within the user's app.slice, which enables fine-grained resource control. The migration migrations/1785424256.sh configures systemd-oomd to target only this slice—killing runaway applications without terminating the entire session.
This architecture provides:
- Process isolation – Each service operates in its own cgroup
- Clean failure domains – A crashing daemon doesn't cascade into session termination
- Predictable resource limits – Standard systemd slice controls apply
Summary
- Unit files ship in
default/systemd/user/and install to/usr/lib/systemd/user/ install/enable-services.shrunssystemctl --user enable --nowfor first-run activationloginctl enable-lingerallows background operation without active login- Drop-ins in
migrations/1785608166.shinject environment variables where needed - Runtime control uses standard
systemctl --usercommands - OOM protection via
app.slicetargeting, configured inmigrations/1785424256.sh
Frequently Asked Questions
Do I need root privileges to manage Omarchy user services?
No. All systemctl --user commands operate entirely within your user session without elevated privileges. Only the initial package installation (placing files in /usr/lib/systemd/user/) requires root. Enable, disable, start, stop, and status commands work as your regular user.
Why does Omarchy use user services instead of system services?
User services provide better session integration—they automatically inherit your environment, use your UID for file permissions, and terminate cleanly on logout (unless lingering is enabled). System services would require complex privilege dropping and environment reconstruction to achieve the same desktop integration.
How do I prevent an Omarchy service from starting automatically?
Use systemctl --user disable servicename.service to remove the startup symlink, or systemctl --user mask servicename.service to prevent manual starts as well. Masking creates a null symlink that blocks even implicit dependencies from starting the unit.
Can I modify a unit file without losing changes on update?
Yes. Create a drop-in override rather than editing the base unit:
systemctl --user edit omarchy-sleep-lock.service
This opens an editor for a drop-in file that persists across package updates, while the base unit remains managed by Omarchy's package.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →