migrations
Read this before creating or changing migrations under `migrations/`.
Claude Code
$ npx -y skills add omacom/omarchy --agent claude-code
Cursor
Cursor also loads subagents from .claude/agents, so copy this file there to use it in Cursor.
Agent definition
migrations.mdOmarchy migrations
Read this before creating or changing migrations under `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` after `graphical-session.target`. The notifier checks:
omarchy-migrate --pending
It stays silent while `omarchy update` holds its lock, since that update applies the pending migrations itself.
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
with `bash -euo pipefail`, not through executable bits.
- No shebang line.
- Start with an `echo` describing what the migration does.
- Use `$OMARCHY_PATH` to reference the Omarchy directory.
- Be idempotent. Check existing state before changing it.
- Migrations are strictly ordered and synchronous. A migration that cannot finish must exit non-zero, remain pending, and stop the queue; never mark later migrations complete against state an earlier migration has not established.
- Use helper commands such as `omarchy-cmd-present`, `omarchy-cmd-missing`,
`omarchy-pkg-add`, `omarchy-pkg-drop`, `omarchy-pkg-present`, and `omarchy-pkg-missing` when appropriate.
- Never restart the Omarchy shell. `omarchy update` restarts it unconditionally
after migrations run, and the login-time shell already runs current code and hot-reloads `shell.json` edits.
- Raw `pacman`, `command -v`, and direct config edits are acceptable when
needed for one-off repair work.
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
Don't add a test for a migration under `test/`. It runs once per machine and is frozen once it ships, so the test stops guarding anything. If a migration needs logic worth testing, put that logic in a `bin/` command the migration calls and test the command. Tests of `omarchy-migrate`, the login notifier, and `omarchy-upgrade-to-quattro` stay.
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.
Clearing a privileged file that a retired installer left on disk is the exception, and belongs in a migration whether or not that installer was part of a package layout transition. The upgrade command only runs on a machine still making the 3 to 4 crossing, so anything put there never reaches an install that crossed already, and it never runs at all for an installer that was retired on its own — while the file the installer wrote is still sitting on those machines. The upgrade command finishes by running `omarchy-migrate` (`run_post_upgrade_migrations`), so one migration reaches every population; a copy in the upgrade command would only be a second copy of the same predicate to keep correct. Such a migration must name the defect it clears and match what the old installer actually produced before deleting it. Leave safe administrato
Read more
Omarchy migrations
Read this before creating or changing migrations under `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` after `graphical-session.target`. The notifier checks:
omarchy-migrate --pending
It stays silent while `omarchy update` holds its lock, since that update applies the pending migrations itself.
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
with `bash -euo pipefail`, not through executable bits.
- No shebang line.
- Start with an `echo` describing what the migration does.
- Use `$OMARCHY_PATH` to reference the Omarchy directory.
- Be idempotent. Check existing state before changing it.
- Migrations are strictly ordered and synchronous. A migration that cannot finish must exit non-zero, remain pending, and stop the queue; never mark later migrations complete against state an earlier migration has not established.
- Use helper commands such as `omarchy-cmd-present`, `omarchy-cmd-missing`,
`omarchy-pkg-add`, `omarchy-pkg-drop`, `omarchy-pkg-present`, and `omarchy-pkg-missing` when appropriate.
- Never restart the Omarchy shell. `omarchy update` restarts it unconditionally
after migrations run, and the login-time shell already runs current code and hot-reloads `shell.json` edits.
- Raw `pacman`, `command -v`, and direct config edits are acceptable when
needed for one-off repair work.
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
Don't add a test for a migration under `test/`. It runs once per machine and is frozen once it ships, so the test stops guarding anything. If a migration needs logic worth testing, put that logic in a `bin/` command the migration calls and test the command. Tests of `omarchy-migrate`, the login notifier, and `omarchy-upgrade-to-quattro` stay.
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.
Clearing a privileged file that a retired installer left on disk is the exception, and belongs in a migration whether or not that installer was part of a package layout transition. The upgrade command only runs on a machine still making the 3 to 4 crossing, so anything put there never reaches an install that crossed already, and it never runs at all for an installer that was retired on its own — while the file the installer wrote is still sitting on those machines. The upgrade command finishes by running `omarchy-migrate` (`run_post_upgrade_migrations`), so one migration reaches every population; a copy in the upgrade command would only be a second copy of the same predicate to keep correct. Such a migration must name the defect it clears and match what the old installer actually produced before deleting it. Leave safe administrato
Omarchy is a beautiful, fun & agentic Linux distribution by DHH. Read more at omarchy.org.
Other agents on omarchy.
More agents from other plugins.
architect
AgentMUST BE USED when starting new projects or planning major changes. This agent specializes exclusively in system architecture…
api-reference
Agent**⚠️ DEVELOPER REFERENCE ONLY** — This file documents the raw GraphQL API schema for development and maintenance purposes (adding…
architect
AgentProduce design + contracts (OpenAPI/AsyncAPI/JSON Schema) + ADRs for a greenfield feature. Wraps /plan. Use when the spec exists…
Questions about migrations.
- Which coding agents can use migrations?
- migrations installs in Claude Code and Cursor: each loads subagents from .claude/agents, so copy the file there. Flowy's auto-invocation runs in Claude Code only.

