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 tahoeThis 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 sshpassWithout 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 tahoeUse a custom config
Point to your YAML file:
lume create my-vm --os macos --ipsw latest --unattended ./my-config.ymlDebug mode
Save screenshots showing what the automation sees:
lume create my-vm --os macos --ipsw latest --unattended tahoe --debugScreenshots go to /tmp/unattended-<uuid> by default, or specify --debug-dir /path/to/folder.
How it works
- VM boots and reaches the Setup Assistant
- Lume waits
boot_waitseconds for the UI to stabilize - Commands execute sequentially: click text, type strings, press keys
- OCR finds text on screen; VNC sends input
- 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: lumeCommands
Wait for text (OCR)
- "<wait 'Continue'>" # Wait up to 120s (default)
- "<wait 'Loading...', timeout=300>" # Custom timeoutClick 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 coordinatesWhen 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 workExample: 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: 10Health 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 retriesThe 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 settingsScreen coordinates — Default resolution is 1920x1440. Center is roughly <click_at 960,720>.
Troubleshooting
| Problem | Solution |
|---|---|
| Commands run too early | Increase boot_wait, add <delay> |
| Text not found | Check spelling/case, increase timeout, use coordinates |
| Wrong element clicked | Use index to select correct occurrence |
| Hotkeys ignored | Click desktop first to focus |
| Tab skips elements | Enable 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
| Field | Type | Default | Description |
|---|---|---|---|
boot_wait | integer | 60 | Seconds to wait before starting |
boot_commands | array | required | List of commands |
health_check | object | optional | Verification config |
Health check fields
| Field | Type | Default | Description |
|---|---|---|---|
type | string | required | ssh |
user | string | — | SSH username |
password | string | — | SSH password |
timeout | integer | 30 | Seconds per attempt |
retries | integer | 3 | Number of attempts |
retry_delay | integer | 5 | Seconds between retries |
Was this page helpful?