# How omarchy-migrate-notify.service Detects Pending Migrations in Omarchy

> Discover how omarchy-migrate-notify.service detects pending migrations by checking lock files and querying outstanding migrations with omarchy-migrate.

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

---

**`omarchy-migrate-notify.service`** runs a three-stage bash script that checks for a runtime lock file, queries `omarchy-migrate --pending` to list outstanding migrations, and counts the results to decide whether to alert the user via desktop notification or terminal output.

Omarchy uses systemd user services to keep users informed about system maintenance tasks. The `omarchy-migrate-notify.service` specifically handles migration notifications—ensuring users know when pending configuration or data migrations require attention. This service triggers automatically when a graphical user logs in, executing the helper script at `bin/omarchy-migrate-notify` to perform detection.

## The Three-Stage Detection Process

The `omarchy-migrate-notify` script follows a precise sequence to avoid false notifications and race conditions with active updates.

### Stage 1: Check for Concurrent Updates

Before any detection occurs, the script verifies no update is currently running. The `update_in_progress` function (lines 7-14 in `bin/omarchy-migrate-notify`) checks for the existence of `$XDG_RUNTIME_DIR/omarchy-update.lock`:

```bash

# From omarchy-migrate-notify

update_in_progress() {
  [[ -f "$XDG_RUNTIME_DIR/omarchy-update.lock" ]]
}

```

If this lock file exists, the script exits silently. This prevents duplicate or misleading notifications when an update process will handle migrations automatically.

### Stage 2: Query Pending Migrations

With no active update, the script executes the core detection command (line 20):

```bash
pending_migrations=$(omarchy-migrate --pending)

```

The `omarchy-migrate` binary with the `--pending` flag outputs one pending migration per line. This output is captured in the `pending_migrations` variable for evaluation.

### Stage 3: Count and Evaluate Results

Lines 21-22 strip empty lines and compute the count:

```bash
count=$(echo "$pending_migrations" | grep -v '^[[:space:]]*$' | wc -l)

```

The script then branches based on this count:

- **Zero pending migrations**: Exit without notification
- **One or more pending migrations**: Build and send a user-facing alert

## Notification Delivery Workflow

### Waiting for the Desktop Environment

Before displaying any notification, the script ensures the notification daemon is ready. Line 33 calls `omarchy-notification-wait` to synchronize with the desktop environment.

### Double-Checking the Update Lock

Lines 35-39 perform a final `update_in_progress` check. This second verification closes a race window where an update could have started between the initial check and notification readiness:

```bash
if update_in_progress; then
  exit 0
fi

```

This defensive pattern prevents alerting users about migrations that will be resolved momentarily.

### Fallback to Terminal Output

If desktop notification fails, lines 48-60 fall back to terminal output, printing the pending migrations directly:

```bash

# Simplified fallback logic

echo "Pending migrations:"
echo "$pending_migrations"

```

## Manual Testing and Verification

You can manually trigger the same detection logic the service uses:

```bash

# Run the full notification workflow

omarchy-migrate-notify

```

To inspect pending migrations directly without notification logic:

```bash

# Raw list of pending migrations (same source the helper queries)

omarchy-migrate --pending

```

Test the lock-file behavior by simulating an active update:

```bash

# Create the lock file that blocks notification

export XDG_RUNTIME_DIR=/tmp
touch /tmp/omarchy-update.lock

# This will exit silently due to the lock

omarchy-migrate-notify

```

## Key Source Files

Understanding the `omarchy-migrate-notify.service` detection mechanism requires familiarity with these components:

| File | Purpose |
|------|---------|
| `default/systemd/user/omarchy-migrate-notify.service` | Systemd user unit defining when and how the helper launches (ExecStart at line 17) |
| `bin/omarchy-migrate-notify` | Bash script implementing the three-stage detection and notification logic |
| `bin/omarchy-migrate` | Core migration tool providing the `--pending` query interface |
| [`docs/notifications.md`](https://github.com/omacom/omarchy/blob/main/docs/notifications.md) | User documentation for Omarchy's notification system |
| [`agents/skills/migrations.md`](https://github.com/omacom/omarchy/blob/main/agents/skills/migrations.md) | Architectural overview of migration handling |

## Summary

- **`omarchy-migrate-notify.service`** triggers at graphical login via systemd user service activation
- Detection relies on **`omarchy-migrate --pending`** output, counting non-empty lines to identify pending work
- **Dual lock checks** (before and after waiting for the notification daemon) eliminate race conditions with concurrent updates
- The **fallback to terminal output** ensures users receive critical migration information even when desktop notifications fail
- Implementation spans `bin/omarchy-migrate-notify` with critical logic at lines 7-14, 20-22, and 35-39

## Frequently Asked Questions

### How does omarchy-migrate-notify.service know when to run?

The service includes an `[Install]` section targeting `default.target` with a `WantedBy=graphical-session.target` dependency. This configuration causes systemd to start the service automatically when a graphical user session begins, ensuring users receive timely migration alerts after login.

### What happens if omarchy-migrate --pending returns no output?

When `omarchy-migrate --pending` produces empty output or only whitespace, the count operation yields zero and the script exits cleanly without any user notification. This silent success path avoids spamming users when no migrations are pending.

### Why does the script check the update lock twice?

The initial check prevents wasted work when an update is already running. The second check after `omarchy-notification-wait` addresses a race condition: an update could have started during the wait period. This double-guard pattern ensures users never receive stale notifications about migrations that will be handled automatically.

### Can I run the detection logic without triggering a notification?

Yes—direct invocation of `omarchy-migrate --pending` bypasses all notification logic and simply lists pending migrations to stdout. This is useful for scripting, automated health checks, or when you want to inspect system state without desktop interaction.