# Idempotency Guarantees for Omarchy Migrations: How Safe Execution Works

> Discover Omarchy migrations' idempotency guarantees: safe execution via marker files, early-exit checks, atomic changes, and failure-safe queue processing. Learn how Omarchy ensures reliable data migrations.

- Repository: [Omacom/omarchy](https://github.com/omacom/omarchy)
- Tags: internals
- Published: 2026-09-06

---

**Omarchy migrations are strictly idempotent through per-user marker files, mandatory early-exit checks in each script, atomic state changes, and failure-safe queue processing that halts on error without leaving partial state.**

Every migration in the `omacom/omarchy` repository follows a formal contract designed to make system changes safe to run repeatedly. Whether you're managing a single machine or deploying across multiple user accounts, understanding these guarantees helps you write custom migrations and debug update failures with confidence.

## The Six Core Idempotency Guarantees

Omarchy's migration system enforces six specific behavioral guarantees. Each one addresses a different category of risk in configuration management.

| Guarantee | Enforcement Mechanism |
|-----------|----------------------|
| **Only run once per user** | Marker file at `~/.local/state/omarchy/migrations/<timestamp>.sh` |
| **Safe to re-execute** | Scripts self-check for markers and exit 0 if already applied |
| **Atomic state changes** | Work only proceeds after verifying state doesn't already exist |
| **Failure halts the queue** | Non-zero exit prevents marker creation; runner stops processing |
| **No background side-effects** | Synchronous execution in user session only |
| **Per-user isolation** | Marker files live in `$HOME`, giving fresh migration sets per account |

These rules are documented in [`agents/skills/migrations.md`](https://github.com/omacom/omarchy/blob/main/agents/skills/migrations.md) and implemented consistently across all scripts in the `migrations/` directory.

## How the Marker File System Works

The foundation of Omarchy's idempotency is the **per-user marker file**. The `omarchy-migrate` runner checks for this file before executing any migration script.

In [`migrations/1785095882.sh`](https://github.com/omacom/omarchy/blob/main/migrations/1785095882.sh) and every other migration, you'll find this pattern:

```bash
#!/usr/bin/env bash
set -euo pipefail

MIGRATION_NAME="${BASH_SOURCE[0]##*/}"
MARKER="$HOME/.local/state/omarchy/migrations/$MIGRATION_NAME"

# Early exit if already applied

if [[ -e "$MARKER" ]]; then
  echo "Migration $MIGRATION_NAME already applied; skipping."
  exit 0
fi

# Idempotent work: only act if needed

if ! systemctl --user is-enabled my-service.service >/dev/null 2>&1; then
  systemctl --user enable my-service.service
fi

# Success: create the marker

mkdir -p "$(dirname "$MARKER")"
touch "$MARKER"

```

This structure ensures three critical behaviors:

1. **First run**: Detects missing marker, performs work, creates marker on success
2. **Second run**: Finds marker, exits immediately with status 0 (no error, no work)
3. **Failed run**: Exits non-zero without creating marker, remains pending for retry

## Atomic State Changes and Safe Scripting

Every migration must verify preconditions before acting. The example above uses `systemctl --user is-enabled` to check state before calling `enable`. This pattern—**check, then act, then mark**—prevents duplicate operations.

The `set -euo pipefail` directive at the top of each script provides additional safety:

- `-e`: Exit immediately on any command failure
- `-u`: Treat unset variables as errors
- `-o pipefail`: Propagate pipeline failures (not just last exit code)

Combined with early-exit logic, these options ensure that partial failures don't leave the system in an inconsistent state.

## Failure Handling and Queue Integrity

The migration runner enforces **strict queue ordering**. If any migration fails:

- The script exits with non-zero status
- No marker file is created
- The runner stops processing subsequent migrations
- The system remains in a consistent "pending" state

According to [`docs/update-process.md`](https://github.com/omacom/omarchy/blob/main/docs/update-process.md), migrations trigger only at login or during explicit `omarchy-migrate` runs—not on every package update. This controlled execution window reduces exposure to partial failure scenarios.

## Per-User Isolation and Multi-Account Safety

Marker files reside in `~/.local/state/omarchy/migrations/`, not system directories. This design provides:

- **Fresh migration sets** for new users
- **No cross-user contamination** of migration state
- **Portable user data** that travels with home directory backups

Checking migration state from another script follows the same pattern:

```bash
if [[ -e "$HOME/.local/state/omarchy/migrations/1785095882.sh" ]]; then
  echo "Migration already applied"
else
  echo "Migration pending – run omarchy-migrate"
fi

```

## Running and Inspecting Migrations

Users can interact with the migration system directly:

```bash

# List pending migrations for current user

omarchy-migrate --pending

# Apply all pending migrations

omarchy-migrate

```

These commands respect the same idempotency guarantees. Running `omarchy-migrate` multiple times is always safe—already-applied migrations skip automatically.

## Key Source Files

| File | Purpose |
|------|---------|
| `migrations/*.sh` | Individual migration scripts implementing the idempotency pattern |
| [`agents/skills/migrations.md`](https://github.com/omacom/omarchy/blob/main/agents/skills/migrations.md) | Authoring guide defining the idempotency contract |
| [`docs/update-process.md`](https://github.com/omacom/omarchy/blob/main/docs/update-process.md) | Update flow documentation including migration triggers |
| `~/.local/state/omarchy/migrations/` | Runtime marker directory (per-user state) |

## Summary

- **Marker files** in `~/.local/state/omarchy/migrations/` track per-user completion state
- **Self-checking scripts** exit early if work is already applied, making re-runs safe
- **Atomic patterns** require verify-before-act logic for all state changes
- **Queue halting** prevents cascading failures by stopping on first error
- **Synchronous execution** in user sessions eliminates background process risks
- **User isolation** ensures migrations run exactly once per account

## Frequently Asked Questions

### What happens if I manually delete a marker file?

Deleting a marker file causes the migration to appear pending again. On next `omarchy-migrate` run, the script will re-execute. Because all proper migrations use check-then-act patterns, this is safe—duplicate work is skipped based on actual system state, not just the marker.

### Can system-wide migrations affect multiple users?

No. As implemented in `omacom/omarchy`, migrations are strictly per-user. Each user's marker directory is independent. System-wide changes would need to be handled through package installation or a separate administrative mechanism outside the migration framework.

### How do I check which migrations have run on my account?

List the contents of your marker directory:

```bash
ls -la ~/.local/state/omarchy/migrations/

```

Each `.sh` file corresponds to a completed migration. Compare against `migrations/` in the repository or use `omarchy-migrate --pending` to see what's outstanding.

### What should I do if a migration fails repeatedly?

First, examine the script in `migrations/` to understand what it's trying to accomplish. Check for conflicting manual changes you may have made. The migration will remain pending (no marker created) until it exits successfully. You can run `omarchy-migrate` with shell debugging enabled by modifying the script temporarily or checking `~/.local/state/omarchy/logs/` if available in your version.