Post-setup sign-in surfaces and removing the App Store
Companion to setup_assistant_pane_gating.md: what the Apple ID / iCloud
sign-in surfaces look like after Setup finishes on a guest that never signed
in, what it takes to suppress them, and how the App Store — a staged system
app — is actually removed. Measured 2026-10-06 on ipad-mini-01 (iPadOS
26.6.2, setup completed, never signed in, bundle 2.6.0-local.92448989) plus
static analysis of the iPhone17,3 27.0 (24A435) images; panetest-iphone
(ios 27.0 + cloudOS 26.4) is the fresh-machine testbed for the open items.
TL;DR
- A finished, never-signed-in guest shows one sign-in surface today: the
"Apple Account / Sign in to access iCloud data, the App Store…" card at the top of
Settings. No Settings badge, no sign-in notification — the follow-up
machinery is running (
followupd,appleidsetupd,akd) but has posted nothing visible. - Suppression ladder: (1) do nothing and re-check after the Setup pane patch
lands; (2) disable
followupd+appleidsetupd(two plist writes, kills the naggers at the source); (3) DSC-patchFLFollowUpController postFollowUpItem*to return NO (kills every follow-up system-wide). The Settings card itself only disappears by patching Settings.app — an inert row; recommended against. - Removable system apps can be deleted durably. Their running copies live
on the data volume (
/private/var/containers/Bundle/Application/<uuid>/).apps.uninstall'sLSApplicationWorkspacefallback refuses them, so the removal is:apps.unregisterthe bundle (LS) →files.removethe whole container (not just the.app) →system.respring. Removing only the.appis not durable — iOS re-materializes the app from the container'sSerializedPlaceholder.ipaon the next boot (this is why the App Store the prior pass "removed" was back after a reboot). Measured end-to-end onpanetest-iphone(2026-10-06): News removed, survived a full reboot while a file-only-removed App Store came back; then Home, TV, News, FaceTime, iTunes Store, Messages, Camera and App Store all removed and survived avm stop/vm startcycle (app count 258 → 250).
What "sign-in" surfaces exist after Setup
Measured on ipad-mini-01 (screenshot 2026-10-06 00:24, Settings root) and,
after a full fresh Setup walk, on panetest-iphone (iOS 27.0, 2026-10-06 —
the Apple ID pane was skipped by hand via Set Up Later, then setup.skip
ended the control run):
So the fresh, never-signed-in guest does acquire a follow-up (badge + "Finish Setting Up" row) even though nothing nags on the older guest. The ladder below covers both.
Daemons running on that guest: followupd (203), appleidsetupd (180),
akd (177), appstored (183), itunesstored (207), storekitd (184).
The follow-up machinery (static, 27.0)
CoreFollowUp.framework in the shared cache carries FLFollowUpController,
the client every poster uses. Method IMPs (unslid, 27.0 cache):
plus the HSA2 (iCloud Keychain sign-in) notification family
(_postHSA2LoginNotification:, _postHSA2PasswordChangeForAppleID: …).
com.apple.followupd.plist is the server; com.apple.appleidsetupd.plist
drives the "finish setting up your Apple ID" flows (AppleIDSetupDaemon,
AppleIDSetupUIService.app, ProximityAppleIDSetup).
Suppression ladder
- Do nothing (measure first). Depends on how the guest got here: a
fresh setup with a hand-skipped Apple ID pane leaves the badge and the
"Finish Setting Up" row (
panetest-iphone); the older finished guest shows neither. The pane patch insetup_assistant_pane_gating.mdskips the pane atcontrollerNeedsToRun— nobody presses "Set Up Later" — and may therefore leave no follow-up at all. Verify after that patch lands. - Disable
appleidsetupd, clear the item store, keepfollowupd— the measured recipe (see below). Do it withservices.disable(persists in the data-volume launchd override DB,/var/db/com.apple.xpc.launchd/), not by editing the sealed-volume plists. Disablingappleidsetupdstops the Apple ID follow-up from being re-posted; removing/var/mobile/Library/CoreFollowUp/items.db(+-wal/-shm) drops the pending item; leavingfollowupdenabled lets it reconcile the Settings icon badge to 0 on the next boot. Disablingfollowupdas well is the trap: it removes the Settings row but orphans the icon badge (the badge was already pushed to SpringBoard and survives a respring with nothing left to zero it). - DSC patch.
postFollowUpItem:error:andpostFollowUpItem:completion:→ return NO (same leaf-rewrite shape as the pane patch). Suppresses every follow-up item system-wide — including software-update and storage badges; on a research guest that is usually acceptable, but it is broader than the ask. - The Settings card would need a Settings.app patch (Swift UI, brittle, and the row is inert). Recommended against; not part of this work.
Measured (panetest-iphone, 2026-10-06)
The fresh guest showed the red "1" on the Settings icon and a "Finish
Setting Up Your iPhone" row at Settings root — confirmed to be the CoreFollowUp
item created by the hand-skipped Apple ID during setup, stored in
/var/mobile/Library/CoreFollowUp/items.db (SQLite).
So the respring clears the row but only a boot (followupd's boot-time badge
reconciliation) clears the icon badge. appleidsetupd stays disabled so the
Apple ID follow-up is not re-posted; followupd stays enabled so it can zero the
badge. The "Apple Account — Sign in…" card itself remains (ladder step 4,
left intact by recommendation).
Removing removable system apps (durably)
Measured live on panetest-iphone (iPhone17,3 iOS 27.0, 2026-10-06). These
are the user-facing removable system apps — the ones with a placeholder in
/System/Library/AppPlaceholders (52 of them: App Store, Home, TV, News,
FaceTime, iTunes Store (MobileStore), Messages (MobileSMS), Camera, …).
Each is installed on first boot into its own container on the data volume
(/private/var/containers/Bundle/Application/<uuid>/), which is writable and
not sealed, with staged_system_apps emptied afterward.
The re-stage trap (why the earlier App Store removal came back)
The container holds more than the .app:
Removing only the .app subdir (the earlier recipe) and resprininging
hides the icon for that session, but LaunchServices still has the app
registered, so on the next boot installd "repairs" the registered-but-missing
bundle by re-expanding SerializedPlaceholder.ipa — the icon returns (as it did
for the App Store this pass found still present after a reboot, with a stale
apps.list record at the old path). /System/Library/AppPlaceholders/<App>.app
on the sealed root volume is the master source these placeholders seed from.
The durable recipe
Three RPCs per app (plus an optional backup):
apps.unregister {path, force:true} is IcliKit's path-based LS unregister (the
icli_unregister_app the earlier note wanted — it is exposed). Doing it
before removing the files is what stops installd from re-materializing the app:
with no registration there is nothing to repair, and with the container (and its
SerializedPlaceholder.ipa) gone there is nothing to repair it from.
Revert: files.copy the backup container back, then apps.register the .app
inside it (or system.uicache), then respring. A full restore also brings the
app back from the image.
What was measured
Store daemons (appstored, itunesstored, appstorecomponentsd) keep running
after the App Store bundle is gone; disable them too (services.disable, as in
ota_software_update_block.md) for no store traffic. Keep storekitd — apps
the researcher installs may link StoreKit.
One verb: apps.remove_system
vphoned now folds the durable sequence into one call:
apps.remove_system {"bundle_ids":[…],"force":true} reads each app's current
container from the live app list, backs the whole container up to
/private/var/db/vphoned/removed-system-apps/<bundle_id>.container with a
manifest beside it, unregisters the app, removes the container and resprings
once. The backup directory is root-only (0700) and on the Data volume, like
the bundle containers, so the backup is an APFS clone that costs next to
nothing and the restore is a rename. The first version of the verb used
/private/var/mobile/Library/removed-system-apps, the hand recipe's
directory; /private/var/mobile is the User volume, so those backups were full
copies and their restore failed with EXDEV. Backups there are still listed
(legacy: true) and restored, by a copy that keeps owners, modes, extended
attributes and flags, after which the legacy copy is removed. It refuses apps outside /private/var/containers/Bundle/Application/<UUID>/
(Phone and the rest of /Applications). apps.restore_system moves a backup
back to its original UUID path and registers it, and apps.removed_system
lists the backups. icli's apps.register refuses Apple's apps since 0.7.17, so
the hand recipe's revert step above no longer works through it. See
Research/vphoned_http_api.md, "Removable system apps and APFS snapshots".
Open items
- Whether the pane patch (
setup_assistant_pane_gating.md), which skips the Apple ID pane without anyone pressing "Set Up Later", leaves the badge / "Finish Setting Up" row uncreated — the freshest data point says a hand-skipped pane does create it, so this is the interesting check once the patch builds. Whether disablingResolved (see "Measured" above): disablefollowupd/appleidsetupdclears the badge.appleidsetupd+ clearitems.db+ keepfollowupdenabled; the badge clears on the next boot.panetest-iphoneis left running. Applied this pass and verified durable across avm stop/vm startcycle: Home, TV, News, FaceTime, iTunes Store, Messages, Camera and App Store removed (backups under/private/var/mobile/Library/removed-system-apps/); OTA blocked (ota_software_update_block.md); the "Finish Setting Up" row/badge cleared. The only sign-in surface left is the inert Settings "Apple Account" card. The purplebuddy domain was restored (2026-10-06, after the pane A/B walks) from the completed-setup backup: all 29 keys back throughsettings.set,SetupDonekept,Passcode4Presentedcorrectly absent (Setup clears it at buddy-done), so the passcode pane behaves stock — re-entering Setup (deleteSetupDone) shows it again.
Note on creating panetest-iphone: the first attempt timed out — first boot
reached the vphoned boundary exactly at the create wrapper's 300 s window
(camera on vsock 1338 connected at the timeout edge; kernel console healthy,
no panic), and the wrapper tore the machine down. The retry succeeded within
the window. If 27.0 first boots on a given Mac routinely exceed it, the
firstBoot step's wait needs a look in Launchpad before fresh 27.0 machines
can be created there at all.
Reproducing the static bits
Same extraction flow as setup_assistant_pane_gating.md. The Preferences
binary is /Applications/Preferences.app/Preferences (Swift-first — only 78
ObjC classes dump; the root list is FLTopLevelViewModel sapp_groupsWithQueue:completion:); CoreFollowUp classes via
ipsw class-dump <dsc> /System/Library/PrivateFrameworks/CoreFollowUp.framework/CoreFollowUp --re -V.
2026-10-07: Games and Phone app entries
User requested hiding Games and Phone entry points. On panetest-iphone, unregistered com.apple.games and com.apple.mobilephone, then moved program files into /var/root/hidden-app-entries-20261007/ rather than deleting them. Games' entire bundle container (including placeholder metadata) was moved to Games.container; /Applications/MobilePhone.app was moved to MobilePhone.app. com.apple.GameTrampoline already carries SBAppTags=[hidden] and was left intact, as were Game Center widgets/services.
After full reboot, both target registrations remain absent (app count 250 → 248). Screenshots confirm no Games/Phone icon on either home page or in App Library; dock contains Safari and Music. Settings launches with foreground verified. Root is read-only again. The temporary remount job was unloaded, its plist removed and its log deleted.
Original data containers were retained and directory reads succeeded after reboot:
- Games:
/private/var/mobile/Containers/Data/Application/DBA101EC-66DF-4C79-906F-14C958771D2B - Phone:
/private/var/mobile/Containers/Data/Application/304C2592-BF11-440F-90B9-2D84CF4FF503
To restore on this guest, temporarily remount root writable, move Games.container back to /private/var/containers/Bundle/Application/90D1ADC8-1429-4D25-96C0-E270D6A3D688 and the saved MobilePhone.app back to /Applications/MobilePhone.app, register each .app path, then reboot. Both backup entries were verified present after reboot. This removes app launchability together with the icon; it does not stop underlying telephony daemons.
Evidence: /private/tmp/prefs-audit/hidden-apps-post-reboot.json, hidden-apps-environment.json, hidden-apps-device.json, hidden-app-backups-post-reboot.json, hidden-apps-home-current.jpg, hidden-apps-library.jpg (second home page), and hidden-apps-library-final.jpg (actual App Library). SpringBoard UI-tree requests cannot verify the foreground home scene on this build, so visible icon checks use screenshots rather than treating that API failure as a successful check.
2026-10-07: Find My entry removed
Unregistered com.apple.findmy, then moved its entire bundle container from /private/var/containers/Bundle/Application/6EB8CC54-634C-4191-9A18-8287D20C55A1 to /var/root/hidden-app-entries-20261007/FindMy.container. The data container /private/var/mobile/Containers/Data/Application/A3EA4863-9650-4135-B0C6-246E7BF253F9 and Find My auxiliary services were retained. Backup and data directory reads succeeded afterwards.
The first guest-initiated reboot left vphoned disconnected and the window black. Launchpad reported running, panicked=false; serial logs continued APFS activity and no panic record was found. Preserved that log as /private/tmp/prefs-audit/findmy-pre-recovery-console.log. Normal vm stop then vm start --wait with the original bundle restored vphoned in 10 seconds. This recovery does not establish the root cause of the earlier disconnect.
After that complete VM restart, Find My remained absent from registrations (248 → 247); Settings launch had foreground verified, and the second home page screenshot confirmed the Find My icon gone and the UI responsive. Evidence: findmy-post-recovery-apps.json, findmy-backup-verified.json, findmy-data-verified.json, findmy-final-screen.jpg in /private/tmp/prefs-audit. Restore by moving the saved full container back to its original UUID path, registering FindMy.app, then respring/reboot. No kernel patch or host security setting changed during this removal.
2026-10-07: Wallet app entry removed
Removed the Wallet main app (com.apple.Passbook) from panetest-iphone by unregistering its bundle and moving the complete program container, including placeholder metadata, from /private/var/containers/Bundle/Application/22E11AE9-A1A6-4533-8F4F-CBF82D1FF026 to /var/root/hidden-app-entries-20261007/Wallet.container. The data container /private/var/mobile/Containers/Data/Application/BFDA90DC-29FB-4885-8CB0-39A165724970 was retained. FinanceStub and Wallet UI/credential helper services were left intact. This app removal is separate from the already implemented Wallet & Apple Pay Settings-row patch.
The first immediate VM stop/start still showed a stale Wallet registration and icon. The original container directory did not exist, and a second unregister reported that the app was not registered, so the evidence does not establish that its program files were restored. After respring, the registration disappeared. A second complete VM stop/start then confirmed persistent absence (247 → 246 registered apps), and a fresh home-screen screenshot showed Settings occupying Wallet's former position. Root remained read-only; no writable remount was required for this data-volume operation.
The backup and retained data directory were read successfully. To restore, move Wallet.container back to its original UUID path, register the enclosed Passbook.app, and respring before checking a full restart. Host evidence is under /private/tmp/prefs-audit: wallet-final-apps.json, wallet-final-environment.json, wallet-final-screen.jpg, wallet-backup.json and wallet-data.json.