Removing the boot-time notification banners from the macOS golden base
Every clone boots with three persistent alert-style banners in the top-right, over the screenshotted desktop:
| Banner | Real source | Notes |
|---|---|---|
| Data Access Blocked — "NucleicVMAgent tried to access your data from other apps and was blocked" | NucleicVMAgent lacks Full Disk Access; TCC blocks it and posts this |
The default computer-use path is host-side, so this is cosmetic unless you use the in-guest native/ax path — but the block fires every time the agent runs. |
| Multiple Extensions Added — "Xcode-beta added multiple extensions" | Background Task Management (com.apple.BTMNotificationAgent) |
BTM already records Xcode-beta as notified, so it will not re-post — see "replay" below. |
| Tips — "Learn how to take a screenshot" | Tips (com.apple.tips / tipsd) |
tipsd runs and the Tips window auto-launches despite the Phase 5¾ launchctl disable. |
Two things must be true — and the constraints are tight
This was verified on a live macOS 27 clone of the current base:
- SIP is ENABLED in the sealed base, and it is not MDM-enrolled (no
configuration profiles). That rules out three whole families of fix:
TCC.dbcannot be read or written from any shell (not even root) → no scripted Full Disk Access grant, no scripted per-app notification toggle.- PPPC (
com.apple.TCC…) andcom.apple.notificationsettingsprofiles are only honored via MDM — a manually-installed.mobileconfigis ignored. - The DND assertion store and the delivered-notification store are TCC-protected from the shell.
- The banners are REPLAYED from the base snapshot, not regenerated each boot.
BTM already marks the extensions
notified(it won't post again), yet the banner appears on every clone — so the base was sealed with these alerts still on screen (undismissed), and every clone inherits that screen state.killall NotificationCenter/usernoteddo not clear persistent alerts (the UI just relaunches and re-draws them), which is why the existing timer fails.
Do NOT use a blanket suppressor (DND / notifications-off)
A tester may be exercising an app's own notifications, so the fix must be surgical — kill only these three sources and leave the notification framework fully working. That rules out Do Not Disturb and any global "notifications off": DND is verified to suppress new notifications, so it would also swallow the banners a developer is trying to see.
It also means the existing killall NotificationCenter LaunchAgent (Phase
5⅞+) must be removed — beyond being ineffective against these persistent
alerts, its 60-second sweep would dismiss an app-under-test's intended
notifications. It is actively wrong for the notification-testing use case.
The fix: surgical, at base-build time, captured in the snapshot
Because SIP blocks scripting the relevant stores, the durable fix is a small set of targeted settings applied once while building the golden base — each scoped to a single source, each captured in the sealed snapshot, none touching the notification framework as a whole:
- NucleicVMAgent → Full Disk Access. Removes Data Access Blocked at the source and unblocks the agent's native path. Only affects the agent.
- Tips → notifications off (and actually stop
tipsd). Removes Tips. Per-app; every other app still notifies normally. - Seal the base clean. Dismiss any remaining on-screen alert before the final shutdown (Notification Center ▸ Clear All). BTM won't re-post the extensions banner once it's dismissed, so the clones stay clean.
- Remove the
killall NotificationCenterLaunchAgent (Phase 5⅞+).
How you apply 1–2 depends on how you build the base — pick one lane:
Lane A — build with SIP off (matches the script's existing TCC path)
The provisioner already writes the agent's other TCC grants via sqlite3 when
SIP is disabled (Phase 7c/7d). In that same window:
- FDA: add
kTCCServiceSystemPolicyAllFilesfor the agent bundle to the Phase 7d grant loop — one extra service, keyed byxyz.blakeslee.nucleic.vmagentwith the app's designated requirement. - Tips: the per-app notification flag lives in
~/Library/Preferences/com.apple.ncprefs.plist(user domain, not SIP-protected) — settable while building, but the format is opaque; the reliable path is the GUI toggle in Lane B, done once and snapshotted.
Lane B — SIP stays on (this base today): GUI toggles during the build
The base build already drives a GUI session, and GUI settings persist into the snapshot. Do these once, before sealing:
- FDA: System Settings ▸ Privacy & Security ▸ Full Disk Access ▸ add
NucleicVMAgent. - Tips: System Settings ▸ Notifications ▸ Tips ▸ turn Allow Notifications off.
- Then Notification Center ▸ Clear All, and shut down to seal.
Lane C — adopt MDM
If the base is ever MDM-enrolled, the two profiles in this directory are the clean declarative form of 1–2 (they are per-app / agent-scoped, i.e. not a blanket suppressor):
nucleic-vmagent-fda.mobileconfig— Full Disk Access for the agent.nucleic-suppress-notifications.mobileconfig— disables notifications forcom.apple.tipsandcom.apple.BTMNotificationAgentonly.
Both validate with plutil -lint. They are inert without MDM.
Summary
- Root-cause each source (FDA for the agent; Tips off); do not blanket-suppress.
- Seal the base with the alerts dismissed — that is what actually stops the per-boot replay.
- Delete the
killall NotificationCentertimer; it is ineffective here and harmful to the notification-testing use case. - Lane A (SIP-off build) makes FDA scriptable; Lane B (GUI, SIP-on) works on the current base; Lane C (MDM) uses the profiles here.