LumeGuideFundamentals

Unattended Setup

Automate macOS Setup Assistant with YAML configuration files

The macOS Setup Assistant takes 10+ minutes of clicking through screens. Unattended setup does it for you—using VNC and OCR to navigate the UI automatically.

lume create my-vm --os macos --ipsw latest --unattended tahoe

This creates a VM, installs macOS, and runs through the entire Setup Assistant. When it's done, you have a configured VM with user lume (password lume) and SSH enabled.

Unattended configs are macOS version-specific. The tahoe preset works with macOS Tahoe (15.x). Setup Assistant changes between versions, so configs may need updating for new releases.

Prerequisites

If your config includes an SSH health check (like the built-in presets do), you need sshpass installed:

brew install sshpass

Without it, the setup will complete but the health check will fail with sshpass: No such file or directory.

Quick start

Use the built-in preset

The tahoe preset handles macOS Tahoe's Setup Assistant:

# During VM creation
lume create my-vm --os macos --ipsw latest --unattended tahoe

# Or on an existing VM that's at the Setup Assistant
lume setup my-vm --unattended tahoe

Use a custom config

Point to your YAML file:

lume create my-vm --os macos --ipsw latest --unattended ./my-config.yml

Debug mode

Save screenshots showing what the automation sees:

lume create my-vm --os macos --ipsw latest --unattended tahoe --debug

Screenshots go to /tmp/unattended-<uuid> by default, or specify --debug-dir /path/to/folder.

How it works

  1. VM boots and reaches the Setup Assistant
  2. Lume waits boot_wait seconds for the UI to stabilize
  3. Commands execute sequentially: click text, type strings, press keys
  4. OCR finds text on screen; VNC sends input
  5. Optional health check verifies success (e.g., SSH connection)

Writing a config file

A config has three parts:

boot_wait: 30 # Seconds to wait after boot

boot_commands: # Sequence of automation commands
  - "<wait 'Continue'>"
  - "<click 'Continue'>"
  - "<type 'lume'>"
  - '<enter>'

health_check: # Optional verification
  type: ssh
  user: lume
  password: lume

Commands

Wait for text (OCR)

- "<wait 'Continue'>" # Wait up to 120s (default)
- "<wait 'Loading...', timeout=300>" # Custom timeout

Click text

- "<click 'Continue'>" # Click first occurrence
- "<click 'Agree', index=-1>" # Click last occurrence
- "<click 'Label', xoffset=50>" # Click 50px right of text
- '<click_at 960,540>' # Click exact coordinates

When text appears multiple times (like "Agree" in license text and button), use index:

  • index=0 — first (top)
  • index=-1 — last (bottom)

Type text

- "<type 'username'>"
- "<type 'my-password'>"

Press keys

- "<enter>"          # or <return>
- "<tab>"
- "<space>"
- "<esc>"
- "<backspace>"
- "<delete>"
- "<up>" "<down>" "<left>" "<right>"
- "<f1>" through "<f12>"

Hotkey combinations

- '<cmd+space>' # Spotlight
- '<cmd+c>' # Copy
- '<cmd+v>' # Paste
- '<cmd+q>' # Quit
- '<shift+cmd+3>' # Screenshot
- '<ctrl+alt+delete>'

Modifiers: cmd/command/super, shift, alt/option, ctrl/control

Delays

- '<delay 2>' # Wait 2 seconds
- '<delay 0.5>' # Decimals work

Example: Complete Setup Assistant

This walks through macOS Tahoe's Setup Assistant:

boot_wait: 30

boot_commands:
  # Dismiss greeting
  - '<delay 5>'
  - '<space>'
  - '<delay 2>'

  # Language
  - "<wait 'English', timeout=120>"
  - "<type 'English'>"
  - '<delay 1>'
  - '<enter>'
  - '<delay 2>'

  # Country
  - "<wait 'Country or Region'>"
  - '<click_at 960,900>'
  - "<type 'United States'>"
  - '<enter>'
  - "<click 'Continue'>"
  - '<delay 2>'

  # Transfer - select "Set up as new"
  - "<wait 'Transfer Your Data'>"
  - '<delay 20>'
  - '<tab><tab><tab>'
  - '<space>'
  - "<click 'Continue'>"

  # Accessibility
  - "<wait 'Accessibility'>"
  - "<click 'Not Now'>"

  # Account creation
  - "<wait 'Create a Mac Account'>"
  - '<tab><tab><tab><tab><tab><tab>'
  - "<type 'lume'>"
  - '<tab><tab>'
  - "<type 'lume'>"
  - '<tab>'
  - "<type 'lume'>"
  - '<tab><tab><space>'
  - "<click 'Continue'>"

  # Terms
  - "<wait 'Terms and Conditions'>"
  - "<click 'Agree', index=-1>"
  - "<wait 'I have read and agree'>"
  - "<click 'Agree', index=0>"

health_check:
  type: ssh
  user: lume
  password: lume
  timeout: 30
  retries: 5
  retry_delay: 10

Health checks

Verify setup succeeded by testing SSH connectivity:

health_check:
  type: ssh
  user: lume
  password: lume
  timeout: 30 # Seconds per attempt
  retries: 5 # Number of attempts
  retry_delay: 10 # Seconds between retries

The automation waits for the VM to become reachable via SSH before declaring success.

Tips

Timing issues — If commands run before the screen is ready, increase boot_wait or add <delay> commands. Use <wait 'text'> to sync with specific screens.

Text not found — OCR is case-sensitive. Check exact spelling. If text is unreliable, use <click_at X,Y> with coordinates.

Multiple occurrences — When "Agree" appears in both license text and the button, use <click 'Agree', index=-1> to click the button (usually last).

Keyboard navigation — macOS doesn't Tab through all elements by default. Enable full keyboard access:

- '<cmd+space>'
- "<type 'Keyboard'>"
- '<delay 2>'
- '<enter>'
# Then enable "Keyboard navigation" in settings

Screen coordinates — Default resolution is 1920x1440. Center is roughly <click_at 960,720>.

Troubleshooting

ProblemSolution
Commands run too earlyIncrease boot_wait, add <delay>
Text not foundCheck spelling/case, increase timeout, use coordinates
Wrong element clickedUse index to select correct occurrence
Hotkeys ignoredClick desktop first to focus
Tab skips elementsEnable keyboard navigation in System Settings

Limitations

  • OCR depends on resolution — Text detection accuracy varies with display settings
  • Version-specific — Setup Assistant changes between macOS releases
  • No conditionals — Commands run sequentially; can't branch based on screen state
  • Single display — Coordinates assume one display at native resolution

Reference

Config fields

FieldTypeDefaultDescription
boot_waitinteger60Seconds to wait before starting
boot_commandsarrayrequiredList of commands
health_checkobjectoptionalVerification config

Health check fields

FieldTypeDefaultDescription
typestringrequiredssh
userstringSSH username
passwordstringSSH password
timeoutinteger30Seconds per attempt
retriesinteger3Number of attempts
retry_delayinteger5Seconds between retries

Was this page helpful?