# Omarchy User Provisioning Workflow: Creating Users and Finalizing Setup

> Discover the Omarchy user provisioning workflow for automated user creation and system personalization. Learn the three phases: deferred first-boot, runtime finalization, and graphical setup. Automate your setup process.

- Repository: [37signals/omarchy](https://github.com/basecamp/omarchy)
- Tags: how-to-guide
- Published: 2026-08-19

---

**The Omarchy user provisioning workflow is a three-phase process—deferred first-boot creation, runtime per-user finalization, and first-run graphical setup—that automates account creation and system personalization while maintaining idempotency through state markers.**

Omarchy, the opinionated workstation setup from 37signals (Basecamp), handles user creation differently than traditional Linux distributions. Instead of creating users during the ISO installation, Omarchy uses a deferred provisioning model that separates system installation from account setup, allowing for unattended installs and consistent runtime finalization. This workflow ensures that every user receives the same development environment configuration regardless of when their account was created.

## The Three-Phase Provisioning Architecture

The provisioning system is split between **root-side** (first-boot) and **runtime** (per-user) operations, ensuring that system-level configuration happens before user-level customization.

### Phase 1: Deferred First-Boot Provisioning

When installing with the `--defer-provisioning` flag, Omarchy leaves a marker file at `/var/lib/omarchy/provisioning/pending` rather than creating a user during the ISO installation. On the next boot, the systemd unit `omarchy-provision-owner.service` (running on **tty1**) executes **`bin/omarchy-provision-owner`** to complete setup.

This script presents an installer-style console form that collects user details and performs system-level actions:

- Creates the system account via `useradd` or modifies existing users with `usermod`
- Records chosen groups and configures **sudo** access
- Writes the password using `chpasswd`
- Installs authorized SSH keys
- Configures hostname and timezone
- Invokes **`omarchy-provision-user`** with the `--first-install` context

The implementation in `bin/omarchy-provision-owner` uses functions defined in [`install/provisioning/setup-form.sh`](https://github.com/basecamp/omarchy/blob/main/install/provisioning/setup-form.sh) to handle the interactive prompts and validation.

### Phase 2: Runtime Per-User Finalization

After the user exists, **`bin/omarchy-provision-user`** runs **as the target user** (it aborts if invoked as root). This script creates an idempotency marker at `~/.local/state/omarchy/done/finalize-user` to prevent duplicate runs.

Key finalization tasks include:

- **Skill symlinking**: Creates symlinks from `~/.agents/skills/*` to `$OMARCHY_PATH/default/agents/skills/*` for development tool integration
- **XDG configuration**: Updates user directories and GTK bookmarks
- **Default applications**: Sets the default web browser and mailto handlers
- **Per-user hooks**: Sources [`install/user/all.sh`](https://github.com/basecamp/omarchy/blob/main/install/user/all.sh) for additional customization that requires `$HOME` context

When invoked with `--first-install`, the script marks all shipped migrations as already applied, ensuring that chroot installations don't trigger unnecessary updates on first boot.

### Phase 3: First-Run Graphical Setup

When the user logs into the graphical session for the first time, **`bin/omarchy-provision-first-run`** executes automatically via [`default/hypr/autostart.lua`](https://github.com/basecamp/omarchy/blob/main/default/hypr/autostart.lua). This wrapper ensures the user finalization marker exists (re-running `omarchy-provision-user` if necessary) before executing desktop-specific tasks:

- Installs post-update hooks (`install-voxtype.hook`, `setup-fingerprint.hook`, `setup-agent.hook`)
- Enables per-user systemd units (`omarchy-migrate-notify.service`, `omarchy-sleep-lock.service`)
- Applies GNOME/GTK theme settings and speaker tuning
- Displays the welcome notification

Completion is recorded in `~/.local/state/omarchy/done/first-run-user`, making this phase fully idempotent.

## Key Provisioning Scripts and Their Roles

Understanding the specific entry points helps when debugging or customizing the workflow:

- **`bin/omarchy-provision-owner`**: Root-only script for initial account creation. Handles the transition from "no users" to "owner account exists" and is responsible for the `create_user` function that writes to `/var/lib/omarchy/provisioning/setup-user`.

- **`bin/omarchy-provision-user`**: User-context finalizer that handles `skill` symlink creation and sources [`install/user/all.sh`](https://github.com/basecamp/omarchy/blob/main/install/user/all.sh). This script contains the `finalize_user` function and respects the `--force` flag to bypass the `omarchy-done` checks.

- **`bin/omarchy-provision-first-run`**: Graphical session initializer that bridges the gap between console provisioning and desktop readiness. It executes scripts in `install/user/first-run/` including [`enable-user-units.sh`](https://github.com/basecamp/omarchy/blob/main/enable-user-units.sh).

## How the Components Fit Together

The complete workflow executes in this order:

1. **ISO Installation**: When `omarchy-apply-system --defer-provisioning` runs, it skips user creation and writes the pending marker to `/var/lib/omarchy/provisioning/pending`.

2. **First Boot**: The `omarchy-provision-owner.service` detects the pending file and launches the owner provisioning script on tty1, presenting the `user_form` and executing `create_user` with the development-aware group configuration.

3. **User Finalization**: Immediately after creation, the owner script calls `omarchy-provision-user --force --first-install`, which creates skill symlinks and runs [`install/user/all.sh`](https://github.com/basecamp/omarchy/blob/main/install/user/all.sh).

4. **Desktop Initialization**: Upon first graphical login, `omarchy-provision-first-run` executes, enabling user systemd units and applying desktop-specific settings via `run_first_run_step`.

## Working with the Provisioning Commands

These commands are useful for manual intervention or debugging the Omarchy user provisioning workflow:

```bash

# Trigger first-boot provisioning manually (normally runs automatically on tty1)

sudo systemctl start omarchy-provision-owner.service

# Finalize an existing user (run as the target user, not root)

omarchy provision user

# Or manually with flags:

omarchy-provision-user --force --first-install

# Re-run first-run setup after fixing a broken initial session

omarchy-provision-first-run --force

```

The `create_user` function in `bin/omarchy-provision-owner` handles both new and existing accounts:

```bash
create_user() {
  echo "$username" >"$PROVISIONING_DIR/setup-user"
  if getent passwd "$username" >/dev/null; then
    usermod -aG "$(user_groups)" ${full_name:+-c "$full_name"} "$username"
  else
    useradd -m -G "$(user_groups)" -s /bin/bash ${full_name:+-c "$full_name"} "$username"
  fi
  printf '%s:%s\n' "$username" "$password" | chpasswd
  printf '%s:%s\n' root "$password" | chpasswd
}

```

Skill symlinking in `bin/omarchy-provision-user` supports multiple AI agent namespaces:

```bash
mkdir -p ~/.agents/skills ~/.claude/skills ~/.codex/skills ~/.pi/agent/skills
for skill in "$OMARCHY_PATH"/default/agents/skills/*/; do
  skill=${skill%/}
  name=${skill##*/}
  ln -sfn "$skill" ~/.agents/skills/"$name"
  # ... symlinks for other namespaces

done

```

## Idempotency and State Markers

Every phase of the Omarchy user provisioning workflow uses state markers to ensure safety and repeatability:

- **Owner provisioning**: Records the username in `/var/lib/omarchy/provisioning/setup-user`
- **User finalization**: Creates `~/.local/state/omarchy/done/finalize-user`
- **First-run completion**: Creates `~/.local/state/omarchy/done/first-run-user`

The `omarchy-done` utility manages these markers, checking for existence before executing phase-specific logic. Each script supports `--force` to bypass these checks when re-provisioning is necessary.

## Summary

- Omarchy uses **deferred provisioning** to separate system installation from user creation, writing a pending marker rather than creating accounts during the ISO phase.
- **`bin/omarchy-provision-owner`** handles root-side account creation on first boot, including group assignment, password setting, and SSH key installation.
- **`bin/omarchy-provision-user`** performs runtime finalization as the target user, creating skill symlinks and sourcing [`install/user/all.sh`](https://github.com/basecamp/omarchy/blob/main/install/user/all.sh).
- **`bin/omarchy-provision-first-run`** completes the workflow during the first graphical login, enabling user systemd units and applying desktop settings.
- All phases are **idempotent** via state markers in `~/.local/state/omarchy/done/` and support `--force` for manual re-runs.

## Frequently Asked Questions

### How do I re-run the user provisioning if it fails?

Use the `--force` flag with the specific script that failed. For the finalization phase, run `omarchy-provision-user --force` as the target user (not root). For the first-run phase, use `omarchy-provision-first-run --force`. Avoid forcing the owner provisioning unless you intend to create a new primary account, as it will overwrite the existing setup-user marker.

### Can I use Omarchy with pre-existing user accounts?

Yes. The `create_user` function in `bin/omarchy-provision-owner` checks for existing accounts with `getent passwd` and uses `usermod` instead of `useradd` if the user already exists. However, you must still run `omarchy-provision-user` to complete the runtime finalization phase and create the necessary skill symlinks and XDG configuration.

### Where does Omarchy store the provisioning state?

State markers are stored in three locations: `/var/lib/omarchy/provisioning/` for system-wide owner provisioning data, `~/.local/state/omarchy/done/` for per-user completion markers, and `/etc/omarchy/` for configuration persistence. The `finalize-user` and `first-run-user` markers specifically prevent duplicate execution of the runtime and graphical phases.

### What happens during deferred provisioning installs?

When the installer runs with `--defer-provisioning`, it skips all user creation logic and writes `/var/lib/omarchy/provisioning/pending`. The system then boots to a minimal state without a regular user account. On first boot, `omarchy-provision-owner.service` detects the pending file and launches the interactive setup form on tty1, gathering username, password, groups, and SSH keys before creating the account and finalizing the system.