omarchy-update-user-notify.path watched /usr/share/omarchy/migrations, but pacman writes that directory during every update, including the blessed omarchy update, which runs omarchy-migrate a step later. The watcher fired a critical notification for the migrations the update was already applying in the visible terminal. A watcher cannot tell that apart from a bypassed pacman -Syu, so the only trigger that never collides with a running update is a once-per-login check. The service that already ran at graphical-session.target is now the whole mechanism, renamed after the command it runs. That is also all the second-user case needs: markers are per-user, so anyone who did not run the update finds them missing at their next login. Login timing means the toast can be sent before the shell has claimed org.freedesktop.Notifications, so the notifier waits for a live server first. The wait is omarchy-first-run's, lifted into omarchy-notification-wait rather than duplicated. The package keeps omarchy-update-user-notify.service as a symlink onto the new unit. Existing users hold an absolute wants symlink to the old path, and the migration that repoints it only runs for users who run an update, which is the opposite of who the notifier is for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4.0 KiB
Omarchy migrations
Omarchy migrations are one-time repair scripts for existing installs. They are used when a package update needs to change state that pacman cannot safely own by itself.
Migration model
Migrations live in:
migrations/*.sh
They run as the current Omarchy user through omarchy-migrate, normally during
omarchy update. A migration may touch user/session state (~/.config,
~/.local, user systemd, browser/editor prefs, DBus/session state), and may also
perform machine-wide repairs when needed.
Completion state is per-user:
~/.local/state/omarchy/migrations/<migration filename>
That means every user gets a chance to run every migration. Migrations run as the user; privileged operations should invoke the appropriate helper or privilege prompt themselves. Migrations must be idempotent: if one user already applied a machine-wide repair, the same migration running for another user should detect that and no-op.
When migrations run
During omarchy update
omarchy update is the normal update path. It runs package updates, then:
omarchy-migrate
omarchy-hook post-update
omarchy-migrate waits for any active pacman transaction to finish, then runs
all pending migrations for the current user in the visible update terminal.
At login
Every graphical login starts omarchy-migrate-notify.service, which checks:
omarchy-migrate --pending
If that user has pending migrations, it shows a notification that opens a terminal for:
omarchy-migrate
The notifier never runs migrations silently in the background.
This is what covers users who did not run the update themselves: someone who
bypassed the pacman guard with sudo env OMARCHY_ALLOW_DIRECT_PACMAN=1 pacman -Syu, and any second user on the machine, whose migration markers are per-user
and therefore still missing after another user updated.
Login is the only trigger on purpose. Watching the packaged migration directory
also fires during a normal omarchy update, which prompts for migrations that
omarchy-migrate is about to run in the visible update terminal.
Manually
Users can safely run:
omarchy-migrate
at any time. Already-completed migrations are skipped.
Inspecting pending migrations
Use:
omarchy-migrate --pending
Exit behavior:
0— one or more migrations are pending- non-zero — no migrations are pending
Output is one pending migration per line:
1781158082.sh
Creating a migration
Use the helper:
omarchy-dev-add-migration --no-edit
This creates:
migrations/<unix timestamp>.sh
New migration format:
- File permissions must be
0644(-rw-r--r--). Migration runners execute them withbash -euo pipefail, not through executable bits. - No shebang line.
- Start with an
echodescribing what the migration does. - Use
$OMARCHY_PATHto reference the Omarchy directory. - Be idempotent. Check existing state before changing it.
- Use helper commands such as
omarchy-cmd-present,omarchy-cmd-missing,omarchy-pkg-add,omarchy-pkg-drop,omarchy-pkg-present, andomarchy-pkg-missingwhen appropriate.
Example:
echo "Relink Neovim theme to Omarchy current state"
theme_link="$HOME/.config/nvim/lua/plugins/theme.lua"
current_relative_target="../../../../.local/state/omarchy/current/theme/neovim.lua"
[[ -L $theme_link ]] || exit 0
ln -sfn "$current_relative_target" "$theme_link"
Testing migrations
Run a migration against a temporary home when possible:
HOME=$(mktemp -d) bash -euo pipefail migrations/<timestamp>.sh
To rerun a migration locally, remove its marker and run the migrator:
rm ~/.local/state/omarchy/migrations/<migration>.sh
omarchy-migrate
Omarchy 4.0 is upgraded through bin/omarchy-upgrade-to-quattro, not through the
normal migration runner. Do not add compatibility migrations for old installer
layouts; put pre-4 package-layout transition work in the upgrade command instead.