# How Omarchy Install Scripts and Finalize Scripts Function

> Understand how Omarchy install scripts and finalize scripts function across three key phases: system installation, per-user finalization, and first-run graphical setup. Streamline your OS configuration.

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

---

**Omarchy’s installation pipeline splits system configuration into three distinct phases: root-side installation executed by `omarchy-apply-system` within the ISO chroot, per-user finalization managed by `omarchy-provision-user` with idempotency markers in `~/.local/state/omarchy/done/`, and first-run graphical setup triggered by `omarchy-provision-first-run` after the initial login.**

The `omacom/omarchy` repository implements a modular, idempotent installation architecture that cleanly separates system-wide defaults from per-user configuration. Understanding how **Omarchy install scripts** and their finalize counterparts function is essential for customizing the distribution or debugging provisioning failures. The pipeline leverages specific orchestration scripts and marker files to ensure operations run exactly once or safely on repeat invocations.

## Root-Side Installation Phase

The root-side installation runs during ISO construction inside a chroot environment. The entry point `omarchy-apply-system` sources four top-level aggregator scripts located under the `install/` directory:

```bash
run_logged "$OMARCHY_INSTALL/config/all.sh"      # System-wide configuration

run_logged "$OMARCHY_INSTALL/hardware/all.sh"      # Hardware-specific fixes

run_logged "$OMARCHY_INSTALL/login/all.sh"       # SDDM theme and session setup

run_logged "$OMARCHY_INSTALL/post-install/all.sh" # Post-installation tasks

```

Each leaf script resides in directories like `install/config/`, `install/hardware/`, `install/login/`, or `install/post-install/`. These scripts are **sourced** (not executed) via the `run_logged` helper defined in [`install/helpers/logging.sh`](https://github.com/omacom/omarchy/blob/main/install/helpers/logging.sh), which records all output to `/var/log/omarchy-install.log`.

Because these scripts run as root within the ISO chroot, they perform privileged operations such as copying files to `/usr/share/omarchy`, modifying `/etc` configuration, enabling system services, loading kernel modules, and setting up udev rules or firewall policies. These steps execute once per ISO build without per-script idempotency guards, relying instead on the immutable nature of the build process.

## Per-User Finalization (`omarchy-provision-user`)

After the system boots and the user logs in, `bin/omarchy-provision-user` handles runtime configuration that requires the target user’s home directory and environment. This script follows a strict idempotency protocol to prevent redundant operations on subsequent runs.

### Idempotency Checks and Environment Setup

The finalizer first checks for an existing marker using `omarchy-done check finalize-user`. If the marker file `~/.local/state/omarchy/done/finalize-user` exists and the `--force` flag is not supplied, the script exits immediately. When proceeding, it sets critical environment variables including `OMARCHY_PATH`, `OMARCHY_INSTALL`, and updates `PATH` to ensure child scripts locate Omarchy resources correctly.

### Skill Symlinks and XDG Configuration

A unique feature of the finalizer is its **dev-aware skill symlink creation**. For every skill directory under `$OMARCHY_PATH/default/agents/skills/*/`, the script creates symlinks into the user’s home directory at locations like `~/.agents/skills` and `~/.claude/skills`. This operation repeats on every run to support development checkouts where skills may change frequently.

The script then updates XDG user directories and populates `~/.config/gtk-3.0/bookmarks` to ensure consistent file manager behavior across sessions.

### Executing User Leaf Scripts

The finalizer sources [`install/user/all.sh`](https://github.com/omacom/omarchy/blob/main/install/user/all.sh) (located in the repository root), which aggregates all per-user configuration leaf scripts such as [`install/user/theme.sh`](https://github.com/omacom/omarchy/blob/main/install/user/theme.sh) and [`install/user/mise.sh`](https://github.com/omacom/omarchy/blob/main/install/user/mise.sh). After sourcing these, the script refreshes application launchers, sets the default browser, and configures MIME handlers.

If invoked with the `--first-install` flag (used during ISO creation), the script touches all migration scripts under `install/migrations/` to mark them as already applied for the brand-new user account. Finally, it creates the idempotency marker using `omarchy-done mark finalize-user`.

## First-Run Graphical Setup (`omarchy-provision-first-run`)

After the first interactive graphical login, `omarchy-provision-first-run` executes actions requiring a live user systemd instance. This phase runs only once, guarded by the marker `~/.local/state/omarchy/done/first-run-user`.

This script performs the following operations:

- Invokes `omarchy-provision-user` if it hasn't completed yet.
- Enables user-level systemd units including `bt-agent.service` and `omarchy-sleep-lock.service`.
- Applies GNOME and GTK settings via `dconf` that require an active graphical session.
- Performs speaker tuning and displays a welcome toast notification.
- Handles initial Wi-Fi configuration prompts.

## Idempotency Management with `omarchy-done`

The `bin/omarchy-done` utility provides three primitives used throughout the installation pipeline:

- `omarchy-done check <name>` — Returns success (exit code 0) if the marker file exists.
- `omarchy-done mark <name>` — Creates the marker file in `~/.local/state/omarchy/done/`.
- `omarchy-done ensure <name>` — Checks for the marker, creates it if missing, and returns success.

The finalizer uses `check` and `mark` to control the `finalize-user` state, while the first-run script uses `ensure` for the `first-run-user` marker. This design allows administrators to force re-provisioning by removing marker files or using the `--force` flag.

## Adding New Leaf Scripts to Omarchy

Extending the installation pipeline requires adding leaf scripts to the appropriate aggregator.

**For system-side changes:**

1. Create a new script at [`install/config/my-feature.sh`](https://github.com/omacom/omarchy/blob/main/install/config/my-feature.sh).
2. Add the following line to [`install/config/all.sh`](https://github.com/omacom/omarchy/blob/main/install/config/all.sh):
   ```bash
   run_logged "$OMARCHY_INSTALL/config/my-feature.sh"
   ```

**For per-user changes:**

1. Create a new script at [`install/user/my-feature.sh`](https://github.com/omacom/omarchy/blob/main/install/user/my-feature.sh).
2. Source it within [`install/user/all.sh`](https://github.com/omacom/omarchy/blob/main/install/user/all.sh):
   ```bash
   source "$OMARCHY_INSTALL/user/my-feature.sh"
   ```

Both approaches automatically inherit logging via `run_logged` and environment variable injection.

## Common Operations and Examples

Run the per-user finalizer manually (normally invoked automatically):

```bash
omarchy provision user

```

Force re-run after adding a new leaf script:

```bash
omarchy provision user --force

```

Execute first-run steps manually (rarely needed):

```bash
omarchy provision first-run

```

Example leaf script structure for user customization:

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

# File: install/user/example.sh

source "$OMARCHY_INSTALL/helpers/logging.sh"

run_logged "Installing example configuration"
mkdir -p ~/.config/example
echo "option = true" > ~/.config/example/settings.conf

```

## Summary

- **Root-side installation** runs via `omarchy-apply-system` in the ISO chroot, sourcing `install/{config,hardware,login,post-install}/all.sh` to configure system defaults.
- **Per-user finalization** executes through `bin/omarchy-provision-user`, creating skill symlinks, updating XDG directories, and sourcing [`install/user/all.sh`](https://github.com/omacom/omarchy/blob/main/install/user/all.sh) while respecting the `finalize-user` idempotency marker.
- **First-run setup** triggers on initial graphical login via `omarchy-provision-first-run`, enabling user systemd units and applying desktop settings, protected by the `first-run-user` marker.
- **Idempotency** is enforced by `bin/omarchy-done`, which manages marker files under `~/.local/state/omarchy/done/` to prevent duplicate operations.
- **Logs** for root-side operations write to `/var/log/omarchy-install.log` via the `run_logged` helper in [`install/helpers/logging.sh`](https://github.com/omacom/omarchy/blob/main/install/helpers/logging.sh).

## Frequently Asked Questions

### What is the difference between `omarchy-apply-system` and `omarchy-provision-user`?

`omarchy-apply-system` runs during ISO creation inside a chroot environment as root, configuring system-wide settings in `/etc` and `/usr/share`. `omarchy-provision-user` runs after installation as the target user, managing home directory configuration, skill symlinks, and user-specific settings with full idempotency protection.

### How does Omarchy ensure finalize scripts do not run multiple times?

The system uses marker files managed by `bin/omarchy-done`. `omarchy-provision-user` checks for `~/.local/state/omarchy/done/finalize-user` before executing and creates this marker upon completion. Subsequent runs exit immediately unless the `--force` flag is provided or the marker file is manually removed.

### Where are Omarchy installation logs stored?

Root-side installation steps log to `/var/log/omarchy-install.log` through the `run_logged` function defined in [`install/helpers/logging.sh`](https://github.com/omacom/omarchy/blob/main/install/helpers/logging.sh). Per-user finalization also uses `run_logged` (or a fallback implementation) to record operations, though output typically appears in the terminal during interactive use.

### How do I add a custom step to the per-user finalizer?

Create a new shell script in `install/user/` (for example, [`install/user/custom.sh`](https://github.com/omacom/omarchy/blob/main/install/user/custom.sh)) and source it from [`install/user/all.sh`](https://github.com/omacom/omarchy/blob/main/install/user/all.sh). The finalizer will automatically execute your script with proper logging and environment variables, provided the `finalize-user` marker is cleared or `--force` is used on the next run.