Omarchy User Provisioning Workflow: Creating Users and Finalizing Setup
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
useraddor modifies existing users withusermod - Records chosen groups and configures sudo access
- Writes the password using
chpasswd - Installs authorized SSH keys
- Configures hostname and timezone
- Invokes
omarchy-provision-userwith the--first-installcontext
The implementation in bin/omarchy-provision-owner uses functions defined in 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.shfor additional customization that requires$HOMEcontext
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. 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 thecreate_userfunction that writes to/var/lib/omarchy/provisioning/setup-user. -
bin/omarchy-provision-user: User-context finalizer that handlesskillsymlink creation and sourcesinstall/user/all.sh. This script contains thefinalize_userfunction and respects the--forceflag to bypass theomarchy-donechecks. -
bin/omarchy-provision-first-run: Graphical session initializer that bridges the gap between console provisioning and desktop readiness. It executes scripts ininstall/user/first-run/includingenable-user-units.sh.
How the Components Fit Together
The complete workflow executes in this order:
-
ISO Installation: When
omarchy-apply-system --defer-provisioningruns, it skips user creation and writes the pending marker to/var/lib/omarchy/provisioning/pending. -
First Boot: The
omarchy-provision-owner.servicedetects the pending file and launches the owner provisioning script on tty1, presenting theuser_formand executingcreate_userwith the development-aware group configuration. -
User Finalization: Immediately after creation, the owner script calls
omarchy-provision-user --force --first-install, which creates skill symlinks and runsinstall/user/all.sh. -
Desktop Initialization: Upon first graphical login,
omarchy-provision-first-runexecutes, enabling user systemd units and applying desktop-specific settings viarun_first_run_step.
Working with the Provisioning Commands
These commands are useful for manual intervention or debugging the Omarchy user provisioning workflow:
# 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:
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:
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-ownerhandles root-side account creation on first boot, including group assignment, password setting, and SSH key installation.bin/omarchy-provision-userperforms runtime finalization as the target user, creating skill symlinks and sourcinginstall/user/all.sh.bin/omarchy-provision-first-runcompletes 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--forcefor 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →