# How to Manage Idempotency Markers in Omarchy: A Complete Guide with Code Examples

> Learn to manage idempotency markers in Omarchy with our complete guide. Ensure safe, repeatable script execution and prevent duplicate changes.

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

---

**Omarchy uses environment variables ending in `_MARKER` to track completion state, letting migrations and scripts run safely multiple times without causing duplicate changes.**

Idempotency markers are the backbone of Omarchy's state management system. They transform destructive shell scripts into safe, repeatable operations by recording whether a specific step has already executed. This article explains how these markers work, where they are defined, and how to implement them correctly in your own Omarchy contributions.

## What Are Idempotency Markers?

An **idempotency marker** is a simple file-based flag that indicates a particular operation has completed successfully. In Omarchy, marker paths are passed through environment variables following the pattern `OMARCHY_<NAME>_MARKER`. Scripts check for the marker's existence before performing work, and create it afterward using `touch`.

The convention is enforced across the codebase in `migrations/`, `test/shell.d/`, and runtime tools. Markers typically live in `$XDG_STATE_HOME/omarchy` to keep state separate from configuration.

## Where Markers Are Defined and Stored

Marker paths are **not hardcoded** in the scripts that use them. Instead, they are injected by the execution environment:

- **Migration harness**: Sets `OMARCHY_*_MARKER` variables before invoking migration scripts
- **Test framework**: Creates temporary marker files under `test_tmp/` and exports the path
- **Runtime tools**: Use `$XDG_STATE_HOME/omarchy` as the default marker directory

This external configuration lets the same script use different marker locations in testing versus production.

## Core Usage Pattern: Guard, Execute, Record

Every idempotent script in Omarchy follows a three-step pattern:

1. **Guard**: Exit early if the marker exists
2. **Execute**: Perform the actual work
3. **Record**: Create the marker to prevent re-execution

```bash
#!/usr/bin/env bash

# 1. Guard - skip if already done

[[ -f $OMARCHY_EXAMPLE_MIGRATION_MARKER ]] && exit 0

# 2. Execute - perform the migration

echo "Applying one-time configuration..."

# ... actual work here ...

# 3. Record - mark as complete

touch "$OMARCHY_EXAMPLE_MIGRATION_MARKER"

```

This pattern appears in [`migrations/1786137597.sh`](https://github.com/omacom/omarchy/blob/main/migrations/1786137597.sh), which contains an explicit comment noting that the original migration is idempotent by design.

## Real-World Example: T2 Hardware Repair Marker

The `OMARCHY_T2_REPAIR_MARKER` demonstrates production marker usage. In [`test/shell.d/t2-hardware-test.sh`](https://github.com/omacom/omarchy/blob/main/test/shell.d/t2-hardware-test.sh), the test suite validates that the T2 repair script respects idempotency:

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

. "$ROOT/bin/omarchy-test-helper"

# Test validates that OMARCHY_T2_REPAIR_MARKER prevents duplicate repairs

marker_path="$test_tmp/t2-repair-marker"
export OMARCHY_T2_REPAIR_MARKER="$marker_path"

# First run should succeed and create marker

run_t2_repair
[[ -f "$marker_path" ]] || fail "Marker was not created"

# Second run should exit cleanly without re-running repair

run_t2_repair && pass "Idempotency respected" || fail "Second run failed"

```

The test proves the marker system works: subsequent invocations find the existing file and exit immediately.

## Common Marker Variables in Omarchy

| Variable | Purpose | Typical Location |
|----------|---------|----------------|
| `OMARCHY_T2_REPAIR_MARKER` | T2 security chip hardware repair | `$XDG_STATE_HOME/omarchy/t2-repair` |
| `OMARCHY_RETIRED_INSTALLER_ARTIFACTS_MARKER` | Plymouth theme cleanup | `$XDG_STATE_HOME/omarchy/retired-artifacts` |
| `OMARCHY_UPDATE_LOCK_MARKER` | Prevents concurrent update runs | `$XDG_STATE_HOME/omarchy/update.lock` |

These variables are **set by the caller**, not the script. This separation of concerns enables flexible testing.

## Best Practices for Marker Management

### Always Use the Three-Step Pattern

Never omit the guard check. Even "harmless" operations create log noise and waste compute when repeated:

```bash

# Correct - exits early

[[ -f $OMARCHY_SOME_MARKER ]] && exit 0
do_work
touch "$OMARCHY_SOME_MARKER"

# Incorrect - reruns every time

do_work  # Missing guard!

touch "$OMARCHY_SOME_MARKER"

```

### Never Delete Production Markers

Markers represent completed state. Deleting them causes the operation to re-run on next invocation, potentially breaking idempotency:

```bash

# WRONG - destroys idempotency guarantee

rm -f "$OMARCHY_SOME_MARKER"

# CORRECT - let the marker persist

# (If you need re-run capability, use a different mechanism)

```

### Use Descriptive Naming

The middle portion of `OMARCHY_<NAME>_MARKER` should clearly describe the operation:

```bash

# Good - describes what was done

OMARCHY_PLYMOUTH_THEME_FIX_MARKER
OMARCHY_USER_DIRS_RECREATED_MARKER

# Avoid - vague or implementation-focused names

OMARCHY_STEP1_MARKER
OMARCHY_TEMP_FIX_MARKER

```

### Test Your Markers

Every marker-based script should have a corresponding test in `test/shell.d/`. The test framework in `bin/omarchy-test-helper` provides utilities for temporary marker management:

```bash
#!/usr/bin/env bash

# test/shell.d/my-migration-test.sh

. "$ROOT/bin/omarchy-test-helper"

marker="$test_tmp/my-migration-marker"
export OMARCHY_MY_MIGRATION_MARKER="$marker"

# Verify marker creation

run_my_migration
assert_file_exists "$marker"

# Verify idempotency

run_my_migration  # Should succeed without error

assert_command_succeeds "Second run failed"

```

## Advanced Pattern: Lock Markers for Mutual Exclusion

Markers can also **prevent concurrent execution**. The `OMARCHY_UPDATE_LOCK_MARKER` pattern differs slightly from completion markers:

```bash
#!/usr/bin/env bash

# Check for existing lock

if [[ -f $OMARCHY_UPDATE_LOCK_MARKER ]]; then
    echo "Update already in progress" >&2
    exit 1
fi

# Acquire lock (created, not checked)

touch "$OMARCHY_UPDATE_LOCK_MARKER"

# Ensure lock releases even on failure

cleanup() { rm -f "$OMARCHY_UPDATE_LOCK_MARKER"; }
trap cleanup EXIT

# ... perform update ...

```

Unlike completion markers, lock markers are **removed after use**. This pattern appears in update-lock tests across the test suite.

## Complete Migration Example

Here's a production-ready migration template based on patterns from [`migrations/1786137597.sh`](https://github.com/omacom/omarchy/blob/main/migrations/1786137597.sh):

```bash
#!/usr/bin/env bash

# migrations/1234567890-example.sh

# Idempotent migration: configures example service

set -euo pipefail

# Guard: already applied?

[[ -f $OMARCHY_EXAMPLE_SERVICE_CONFIGURED_MARKER ]] && exit 0

echo "Configuring example service..."

# Create configuration directory

mkdir -p "$HOME/.config/example"

# Write configuration only if missing (additional idempotency layer)

if [[ ! -f "$HOME/.config/example/config.toml" ]]; then
    cat > "$HOME/.config/example/config.toml" << 'EOF'
[service]
enabled = true
EOF
fi

# Record completion

touch "$OMARCHY_EXAMPLE_SERVICE_CONFIGURED_MARKER"
echo "Example service configured successfully"

```

This script uses **dual idempotency**: the marker prevents re-entry, and the file existence check prevents overwriting user modifications.

## Key Source Files Reference

| File | Description |
|------|-------------|
| [`migrations/1786137597.sh`](https://github.com/omacom/omarchy/blob/main/migrations/1786137597.sh) | Migration with explicit idempotency comment |
| [`test/shell.d/t2-hardware-test.sh`](https://github.com/omacom/omarchy/blob/main/test/shell.d/t2-hardware-test.sh) | Validates `OMARCHY_T2_REPAIR_MARKER` behavior |
| `bin/omarchy-test-helper` | Test utilities for marker management |

Consult these files when implementing new marker-based functionality.

## Summary

- **Idempotency markers** in Omarchy are file paths passed via `OMARCHY_*_MARKER` environment variables
- The **three-step pattern** (guard, execute, record) ensures scripts are safe to re-run
- Markers are **set by callers** (migration harness, test framework) not the scripts themselves
- **Never delete** completion markers; they represent durable state
- **Lock markers** are a variant for mutual exclusion and are cleaned up after use
- All marker-based code should have **corresponding tests** in `test/shell.d/`

## Frequently Asked Questions

### What happens if I delete an idempotency marker file?

The associated migration or script will run again on next invocation. This may cause duplicate configuration changes, re-apply one-time fixes, or trigger unnecessary restart prompts. Only remove markers during debugging or when intentionally forcing re-execution.

### Can I use multiple markers in a single script?

Yes. Complex migrations may use separate markers for distinct phases: `OMARCHY_PHASE1_MARKER`, `OMARCHY_PHASE2_MARKER`. This allows partial re-execution if a later phase fails. Check each marker independently and only create markers for successfully completed phases.

### How do I test a script that uses environment variables I don't control?

The `bin/omarchy-test-helper` library sets up isolated test environments. Create a temporary directory, construct your marker path there, and `export` it before running the script under test. The test framework automatically cleans up temporary files after each test.