Skip Setup
A fresh Data seed starts the Setup app on first boot. The payload can mark Setup as done before the image is written, so the device boots to SpringBoard.
Command
./unixnu build payload \
--data-ramdisk data.dbr \
--skip-setup \
--trust-cache trustcache.img \
--unique-chip-id <hex>--skip-setup requires --data-ramdisk. The payload step reads [payload] skip_setup_tool from the board file and runs it on a copy of the seed.
[payload]
skip_setup_tool = "scripts/seed-data-skip-setup.py"The original seed stays unchanged. The payload uses the edited copy as Payloads/scratch-data.img.
What the tool changes
scripts/seed-data-skip-setup.py expands the packed APFS Data seed, attaches it read-write, merges preferences into /private/var/mobile/Library/Preferences, and packs the result again.
| Preference file | Values |
|---|---|
com.apple.purplebuddy | SetupDone = true, SetupFinishedAllSteps = true, SetupVersion = 11, daemonizeNeedsToRun = false |
com.apple.purplebuddy.notbackedup | Every mini-buddy flag is false: diagnostics, HSA2, keychain sync, Mesa, payment, standard, silent ICDP |
com.apple.managedconfiguration.notbackedup | LockdownActivationIndicatesCloudConfigurationAvailable = false |
com.apple.springboard | BKNoWatchdogs = true, FBLaunchWatchdogExceptions = { com.apple.purplebuddy: 100 }, MCForceShowCloudConfigurationUI = false |
com.apple.migration | LastSystemVersion = 21H461, DMUserDataDisposition = { SyntheticDidUpgrade = false, buildVersion = 21H461 } |
The tool also creates these directories under /private/var/containers:
Bundle
Data/System
Shared/SystemGroup
TempThe volume UUID stays the same. The APFS container magic is checked again after the edit.
Build version
The script sets:
BUILD, VERSION = '21H461', '17.7.11'Update both values when the board targets a different iOS build. LastSystemVersion and DMUserDataDisposition.buildVersion must match the IPSW.
Device tree
The ADT adds four /chosen properties with --ipad-identity:
| Property | Value |
|---|---|
certificate-production-status | 0 |
effective-production-status-ap | 0 |
certificate-security-mode | 1 |
effective-security-mode-sep | 1 |
These describe a development-fused, undemoted board. mobileactivationd reads them through MobileGestalt and takes its native activation path without an activation record.
Jobs
Setup depends on services that do not run on this platform. The board disables them with boot arguments:
sheng-disable-jobs=com.apple.identityservicesd,com.apple.locationd,com.apple.CommCenter,com.apple.iconservices.iconservicesagentcom.apple.CommCenter is the cellular service. The list is board specific. Keep the services the userland needs and remove the ones that block the first boot.
Output
The payload directory contains:
out/<board>/payload/data-skip-setup-<hash>.dbr
out/<board>/payload/payload.img
out/<board>/payload/payload.jsonpayload.json records:
| Field | Meaning |
|---|---|
data_ramdisk_sha256 | Hash of the edited seed |
skip_setup | true |
payload_sha256 | Payload image hash |
The edited seed is cached by the hash of the original. A different seed produces a new file.
Verify
- Build the payload with
--skip-setup. - Check
payload.jsonhas"skip_setup": true. - Boot the image.
- The log reaches SpringBoard instead of the Setup pages.
The reference implementation is scripts/seed-data-skip-setup.py in this repository. The sheng port recorded the first hardware boot with these changes in commit 5eba9f5 of blu-sharky/sheng-ipados.