|
#!/bin/bash |
|
# golden-gate-debloater.sh — MDM-safe AI / telemetry trim for macOS 27 Golden Gate (runs on 26 Tahoe too) |
|
# Companion: golden-gate-restore.sh — undoes everything this script records. |
|
# |
|
# WHAT IT DOES |
|
# 1. launchctl disable (+ bootout) a curated set of Apple Intelligence, Siri, |
|
# suggestion and telemetry agents in YOUR user domain (gui/<uid>), plus a few |
|
# system daemons (system/…, asks for your admin password once). |
|
# 2. A handful of privacy defaults: Siri off, "Improve Siri & Dictation" opt-out, |
|
# Siri menu-bar icon off, Look Up suggestions off, personalised ads off, |
|
# analytics sharing off, new documents save to disk instead of iCloud. |
|
# 3. Records every change in ~/Library/Application Support/golden-gate-debloater/state.tsv |
|
# so golden-gate-restore.sh can put things back exactly as they were. |
|
# |
|
# EVERY SETTING IS DOCUMENTED: run ./golden-gate-debloater.sh --explain for the full catalogue |
|
# (what each label/key does, which apps are affected, how risky it is), or |
|
# --explain siri to filter. The dry run prints the same text next to each step. |
|
# |
|
# WHAT IT NEVER TOUCHES (on purpose — MDM, security, or things you would miss) |
|
# ManagedClient*, mdmclient*, dmd / remotemanagementd / teslad (DDM), apsd (push), |
|
# akd / appleaccountd / accountsd, softwareupdated / mobileassetd, App Store and |
|
# commerce daemons, tccd / syspolicyd / trustd / securityd, sysextd and network |
|
# extensions (EDR, VPN), SIP, FileVault, Spotlight indexing, iCloud, Time Machine, |
|
# screen sharing, dhcp6d / netbiosd, Exchange sync (dataaccessd / calaccessd), |
|
# Shortcuts (siriactionsd), Quick Look, widgets (chronod), AirDrop / Continuity, |
|
# biomed / coreduetd (Shortcuts and Focus depend on them), identityservicesd. |
|
# |
|
# USAGE (run as your normal user, NOT with sudo — the gui domain is derived from your uid) |
|
# chmod +x golden-gate-debloater.sh golden-gate-restore.sh |
|
# ./golden-gate-debloater.sh --explain [filter] read the catalogue first |
|
# ./golden-gate-debloater.sh --dry-run print what would run (with descriptions), change nothing |
|
# ./golden-gate-debloater.sh apply |
|
# ./golden-gate-debloater.sh --status show the state of every label (run this after the reboot) |
|
# ./golden-gate-debloater.sh --footprint RSS and accumulated CPU time of every running target (before/after) |
|
# ./golden-gate-debloater.sh --scan list AI-looking launchd plists on this OS that the lists miss |
|
# options: --with-media-analysis also mediaanalysisd + photoanalysisd |
|
# (costs Live Text, Visual Look Up, Visual Intelligence, Photos people) |
|
# --with-diagnostics also ReportCrash / ReportPanic / spindump (no crash or hang logs afterwards) |
|
# --no-defaults skip step 2 |
|
# --no-system skip the system/ (sudo) part |
|
# |
|
# BEFORE RUNNING: System Settings → Apple Intelligence & Siri → turn both off. |
|
# That is the supported switch; this script only stops the leftovers idling in the background. |
|
# |
|
# SIP stays ON. With SIP on, "launchctl disable" in gui/ generally sticks, system/ partly, |
|
# and "bootout system/…" usually fails — expected and harmless. Anything still running after |
|
# a reboot is pinned by Apple, not by your MDM: leave it. |
|
# |
|
# Written for the bash 3.2 that ships with macOS. |
|
|
|
set -u |
|
|
|
[[ -n ${BASH_VERSION:-} ]] || { echo "Please run this with bash: ./golden-gate-debloater.sh"; exit 1; } |
|
|
|
STATE_DIR="${GG_STATE_DIR:-$HOME/Library/Application Support/golden-gate-debloater}" |
|
STATE_FILE="$STATE_DIR/state.tsv" |
|
LOG_FILE="$STATE_DIR/last-run.log" |
|
|
|
# ═════════════════════════════════════════════════════════════════════════════ |
|
# LISTS — keep in sync with golden-gate-restore.sh |
|
# Labels that do not exist on the running OS are detected and skipped (and said so). |
|
# The catalogue below (describe) holds the long description for every entry. |
|
# ═════════════════════════════════════════════════════════════════════════════ |
|
|
|
# 1. Apple Intelligence & Siri — user domain (gui/<uid>) |
|
AI_AGENTS=( |
|
com.apple.campo |
|
com.apple.generativeexperiencesd |
|
com.apple.intelligenceflowd |
|
com.apple.intelligencecontextd |
|
com.apple.intelligenceplatformd |
|
com.apple.knowledgeconstructiond |
|
com.apple.siriinferenced |
|
com.apple.siriknowledged |
|
com.apple.Siri.agent |
|
com.apple.assistantd |
|
com.apple.assistant_service |
|
com.apple.assistant_cdmd |
|
com.apple.sirittsd |
|
com.apple.SiriTTSTrainingAgent |
|
com.apple.corespeechd |
|
com.apple.naturallanguaged |
|
com.apple.voicebankingd |
|
com.apple.visualintelligenced |
|
com.apple.callintelligenced |
|
com.apple.intelligencetasksd |
|
com.apple.GenerativeFunctions.agentstored |
|
com.apple.mlhostd |
|
com.apple.ModelCatalogAgent |
|
) |
|
# 1b. Apple Intelligence — system domain (sudo) |
|
AI_DAEMONS=( |
|
com.apple.modelmanagerd |
|
com.apple.modelcatalogd |
|
com.apple.privatecloudcomputed |
|
) |
|
# 2. Suggestions, knowledge graph, Biome — user domain |
|
SUGGEST_AGENTS=( |
|
com.apple.suggestd |
|
com.apple.parsecd |
|
com.apple.parsec-fbf |
|
com.apple.knowledge-agent |
|
com.apple.duetexpertd |
|
com.apple.ContextStoreAgent |
|
com.apple.BiomeAgent |
|
com.apple.biomesyncd |
|
com.apple.routined |
|
com.apple.proactived |
|
com.apple.proactiveeventtrackerd |
|
com.apple.intelligentroutingd |
|
com.apple.spotlightknowledged |
|
com.apple.spotlightknowledged.importer |
|
com.apple.spotlightknowledged.updater |
|
) |
|
# 3. Telemetry, ads, tips, experiments |
|
TELEMETRY_AGENTS=( |
|
com.apple.ap.adprivacyd |
|
com.apple.ap.promotedcontentd |
|
com.apple.tipsd |
|
com.apple.inputanalyticsd |
|
com.apple.geoanalyticsd |
|
com.apple.UsageTrackingAgent |
|
com.apple.triald |
|
) |
|
TELEMETRY_DAEMONS=( |
|
com.apple.analyticsd |
|
com.apple.audioanalyticsd |
|
com.apple.wifianalyticsd |
|
com.apple.ecosystemanalyticsd |
|
com.apple.triald.system |
|
) |
|
# Optional groups |
|
MEDIA_AGENTS=( com.apple.mediaanalysisd com.apple.photoanalysisd ) |
|
DIAG_AGENTS=( com.apple.ReportCrash com.apple.ReportPanic ) |
|
DIAG_DAEMONS=( com.apple.spindump com.apple.metadata.mds.spindump ) |
|
|
|
# 4. Defaults: domain|key|type|value|needs_sudo |
|
DEFAULTS=( |
|
"com.apple.assistant.support|Assistant Enabled|bool|false|0" |
|
"com.apple.assistant.support|Siri Data Sharing Opt-In Status|int|2|0" |
|
"com.apple.Siri|StatusMenuVisible|bool|false|0" |
|
"com.apple.Siri|VoiceTriggerUserEnabled|bool|false|0" |
|
"com.apple.lookup.shared|LookupSuggestionsDisabled|bool|true|0" |
|
"com.apple.AdLib|allowApplePersonalizedAdvertising|bool|false|0" |
|
"NSGlobalDomain|NSDocumentSaveNewDocumentsToCloud|bool|false|0" |
|
"/Library/Application Support/CrashReporter/DiagnosticMessagesHistory|AutoSubmit|bool|false|1" |
|
"/Library/Application Support/CrashReporter/DiagnosticMessagesHistory|ThirdPartyDataSubmit|bool|false|1" |
|
) |
|
|
|
ALL_GUI=( "${AI_AGENTS[@]}" "${SUGGEST_AGENTS[@]}" "${TELEMETRY_AGENTS[@]}" "${MEDIA_AGENTS[@]}" "${DIAG_AGENTS[@]}" ) |
|
ALL_SYSTEM=( "${AI_DAEMONS[@]}" "${TELEMETRY_DAEMONS[@]}" "${DIAG_DAEMONS[@]}" ) |
|
|
|
# ═════════════════════════════════════════════════════════════════════════════ |
|
# CATALOGUE — one entry per setting. Sets D_RISK, D_WHAT, D_AFFECTS. |
|
# |
|
# Risk scale used throughout: |
|
# low background-only; the only thing you lose is the named feature, which you have |
|
# already switched off or never see. Fully reversible with golden-gate-restore.sh. |
|
# medium removes or degrades something people use every day (Live Text, Screen Time |
|
# reports, crash logs, Spoken Content voices, Dictation edge cases). Reversible, |
|
# but read the Affects line before opting in. |
|
# There is no "high": everything MDM-, account-, update- or security-related was left |
|
# out of the lists in the first place. gui/ entries are per user (other accounts on the |
|
# Mac are unaffected); system/ entries are machine-wide and need sudo. |
|
# ═════════════════════════════════════════════════════════════════════════════ |
|
describe() { |
|
D_RISK="?"; D_WHAT="(no description yet — please add one to describe())"; D_AFFECTS="unknown" |
|
case "$1" in |
|
|
|
# ── 1. Apple Intelligence & Siri ────────────────────────────────────────── |
|
com.apple.campo) |
|
D_RISK="low" |
|
D_WHAT="Background agent for the new Siri AI app that ships with Golden Gate (the bundle is " |
|
D_WHAT+="literally called Campo.app). This is the chat-style Siri that can search Mail, Messages, " |
|
D_WHAT+="Notes and Calendar, browse the web and act on what is on screen. The agent keeps the " |
|
D_WHAT+="app's services warm in the background and answers its menu-bar, Dock and Spotlight " |
|
D_WHAT+="invocations. Disabling it does not delete the app; it simply stops living in the background." |
|
D_AFFECTS="The Siri AI app and its menu-bar entry. If Apple Intelligence and Siri are already off " |
|
D_AFFECTS+="in System Settings, nothing you use. No MDM, account or security dependency." ;; |
|
|
|
com.apple.generativeexperiencesd) |
|
D_RISK="low" |
|
D_WHAT="The daemon behind the generative text and image features: Writing Tools (proofread, " |
|
D_WHAT+="rewrite, summarise, reply drafts), Genmoji, Image Playground / Image Wand and mail or " |
|
D_WHAT+="message smart replies. Apps reach it through a system extension point, which is why the " |
|
D_WHAT+="Writing Tools menu appears in every text field on the Mac. Once Apple Intelligence is off " |
|
D_WHAT+="in System Settings the features are gone anyway; this stops the process from being " |
|
D_WHAT+="pre-launched and holding memory." |
|
D_AFFECTS="Writing Tools entries in Mail, Notes, Pages, Messages, Safari and third-party editors; " |
|
D_AFFECTS+="Genmoji in the emoji picker; Image Playground. Medium if you actively use Writing Tools " |
|
D_AFFECTS+="— then leave Apple Intelligence on and skip the whole AI group." ;; |
|
|
|
com.apple.intelligenceflowd) |
|
D_RISK="low" |
|
D_WHAT="Session manager and router for Apple Intelligence requests. When Siri or an app asks for " |
|
D_WHAT+="a generative answer, this process decides whether the request is served by the on-device " |
|
D_WHAT+="model, by Private Cloud Compute or by an external model (the ChatGPT extension or the " |
|
D_WHAT+="third-party model delegation Golden Gate added), and streams the result back." |
|
D_AFFECTS="Siri AI conversations, Writing Tools, summaries and any model-delegation to third-party " |
|
D_AFFECTS+="assistants. Nothing outside the AI feature set." ;; |
|
|
|
com.apple.intelligencecontextd) |
|
D_RISK="low" |
|
D_WHAT="Collects contextual information — what is on screen, the frontmost app, recent activity — " |
|
D_WHAT+="and hands it to Siri and Apple Intelligence so they can answer questions about the current " |
|
D_WHAT+="screen. It is the component that lets Siri AI see what you are looking at." |
|
D_AFFECTS="On-screen awareness in Siri AI and the screen mode of Visual Intelligence. Turning it " |
|
D_AFFECTS+="off is privacy-positive on a work machine; nothing else consumes it." ;; |
|
|
|
com.apple.intelligenceplatformd) |
|
D_RISK="low" |
|
D_WHAT="Builds and queries the on-device personal knowledge graph: people, places, events and " |
|
D_WHAT+="topics extracted from Mail, Messages, Photos and Calendar. Personal-context answers in Siri " |
|
D_WHAT+="(when does the flight land, what did X send me) come from here. On a fresh install or after " |
|
D_WHAT+="a big update it runs long indexing passes, which is the CPU spike people notice." |
|
D_AFFECTS="Personal-context Siri answers and some Spotlight suggestions. Spotlight file, app and " |
|
D_AFFECTS+="contact search itself is unaffected (that is the Spotlight index, which stays on)." ;; |
|
|
|
com.apple.knowledgeconstructiond) |
|
D_RISK="low" |
|
D_WHAT="The worker process that does the heavy lifting for that knowledge graph: entity extraction " |
|
D_WHAT+="over your mail, messages and documents. It is the other half of intelligenceplatformd and " |
|
D_WHAT+="the more CPU-hungry one." |
|
D_AFFECTS="Same as intelligenceplatformd — personal-context Siri only." ;; |
|
|
|
com.apple.siriinferenced) |
|
D_RISK="low" |
|
D_WHAT="Runs the on-device inference models behind Siri Suggestions: predicting which app, contact " |
|
D_WHAT+="or action you are likely to want next, based on time, location and habits." |
|
D_AFFECTS="Siri Suggestions in Spotlight, the Share sheet, Dock/app suggestions and suggested " |
|
D_AFFECTS+="recipients in Messages. Suggestion quality drops; nothing stops working." ;; |
|
|
|
com.apple.siriknowledged) |
|
D_RISK="low" |
|
D_WHAT="Maintains Siri's short-term conversation context and its custom vocabulary — your contact " |
|
D_WHAT+="names, playlists, app names — so that follow-up questions and unusual names work." |
|
D_AFFECTS="Siri only: follow-up understanding and pronunciation of your contacts." ;; |
|
|
|
com.apple.Siri.agent) |
|
D_RISK="low" |
|
D_WHAT="The Siri user-interface process: the orb/window, the keyboard shortcut and the menu-bar " |
|
D_WHAT+="button, plus Type to Siri. Disabling it means the Siri UI can no longer be summoned even if " |
|
D_WHAT+="Siri is technically enabled." |
|
D_AFFECTS="Siri via keyboard shortcut, menu bar and Type to Siri. Dictation is a separate system " |
|
D_AFFECTS+="and keeps working. Medium instead of low if you actually use Siri on the Mac." ;; |
|
|
|
com.apple.assistantd) |
|
D_RISK="low" |
|
D_WHAT="The core Siri daemon: request sessions, execution, and synchronisation of Siri settings and " |
|
D_WHAT+="history with Apple. Also the process that talks to Apple's Siri servers for anything the " |
|
D_WHAT+="on-device stack cannot answer." |
|
D_AFFECTS="Siri in all forms (voice, typed, from the Siri AI app). Running Shortcuts by voice stops; " |
|
D_AFFECTS+="running them from the Shortcuts app or automations does not (that is siriactionsd, " |
|
D_AFFECTS+="deliberately left alone)." ;; |
|
|
|
com.apple.assistant_service) |
|
D_RISK="low" |
|
D_WHAT="Siri's execution service: performs the actions Siri decides on — open an app, send a " |
|
D_WHAT+="message, create a reminder, toggle a setting. It is the glue between the assistant and " |
|
D_WHAT+="the apps' intents." |
|
D_AFFECTS="Siri only. Nothing calls it when Siri is off." ;; |
|
|
|
com.apple.assistant_cdmd) |
|
D_RISK="low" |
|
D_WHAT="Siri natural-language understanding (the CDM/NLX component): turns a transcribed or typed " |
|
D_WHAT+="request into a structured intent. Apple's own description notes it also serves other " |
|
D_WHAT+="internal Apple teams, but no user-facing feature outside Siri depends on it." |
|
D_AFFECTS="Siri only." ;; |
|
|
|
com.apple.sirittsd) |
|
D_RISK="medium" |
|
D_WHAT="The Siri text-to-speech service that renders the Siri voices. The catch: the same engine is " |
|
D_WHAT+="used whenever a Siri voice is selected for an accessibility feature — Spoken Content (Speak " |
|
D_WHAT+="Selection), VoiceOver or Safari Reader read-aloud. With the service disabled those features " |
|
D_WHAT+="may fall silent or fall back to a legacy voice." |
|
D_AFFECTS="Siri speech; Accessibility → Spoken Content and VoiceOver if a Siri voice is chosen " |
|
D_AFFECTS+="there. If you use either, pick a non-Siri voice first or remove this label from AI_AGENTS." ;; |
|
|
|
com.apple.SiriTTSTrainingAgent) |
|
D_RISK="low" |
|
D_WHAT="Background training and asset maintenance for text-to-speech voices: downloads voice " |
|
D_WHAT+="quality updates and runs the adaptation steps for Personal Voice." |
|
D_AFFECTS="Personal Voice creation and Siri voice asset updates. Nothing else." ;; |
|
|
|
com.apple.corespeechd) |
|
D_RISK="medium" |
|
D_WHAT="The CoreSpeech daemon: the always-listening wake-word detector (\"Siri\" / \"Hey Siri\") and the " |
|
D_WHAT+="broker for speech sessions. On some builds parts of Dictation and Accessibility → Voice " |
|
D_WHAT+="Control are also brokered through CoreSpeech, so this is the one entry in the AI group " |
|
D_WHAT+="that can have a side effect outside Siri." |
|
D_AFFECTS="Voice activation of Siri (intended). Possibly Dictation (fn / microphone key) and Voice " |
|
D_AFFECTS+="Control. If either stops responding after the reboot, re-enable this label first: " |
|
D_AFFECTS+="launchctl enable gui/\$(id -u)/com.apple.corespeechd and log out and in." ;; |
|
|
|
com.apple.naturallanguaged) |
|
D_RISK="low" |
|
D_WHAT="The text post-editing daemon: the on-device grammar, phrasing and autocorrect-style " |
|
D_WHAT+="suggestions that Golden Gate expanded system-wide (grammar hints in addition to spelling). " |
|
D_WHAT+="Plain spell-checking with the red underline is a different, older mechanism and keeps working." |
|
D_AFFECTS="Grammar suggestions and blue/green underlines in Notes, Mail, Pages, TextEdit and " |
|
D_AFFECTS+="third-party text views. Medium if you rely on those hints while writing." ;; |
|
|
|
com.apple.voicebankingd) |
|
D_RISK="low" |
|
D_WHAT="Records and trains Personal Voice — the accessibility feature that builds a synthetic copy " |
|
D_WHAT+="of your own voice on device — and serves Live Speech playback with it." |
|
D_AFFECTS="Accessibility → Personal Voice and Live Speech only. Irrelevant unless you have created " |
|
D_AFFECTS+="a Personal Voice on this Mac." ;; |
|
|
|
com.apple.visualintelligenced) |
|
D_RISK="low" |
|
D_WHAT="The Visual Intelligence daemon, new on the Mac with Golden Gate: identifies objects, text, " |
|
D_WHAT+="plants, landmarks and products in screenshots, images or the current screen and hands the " |
|
D_WHAT+="result to Siri AI, ChatGPT, a web search or an App Store lookup. Only the identification " |
|
D_WHAT+="and hand-off layer lives here; the underlying OCR is mediaanalysisd." |
|
D_AFFECTS="Visual Intelligence in Spotlight, screenshots and Siri AI's screen mode. Live Text and " |
|
D_AFFECTS+="Visual Look Up keep working unless you also opt into --with-media-analysis." ;; |
|
|
|
com.apple.callintelligenced) |
|
D_RISK="low" |
|
D_WHAT="'Call intelligence' for the Phone app that Tahoe brought to the Mac: Call Screening (answers " |
|
D_WHAT+="unknown callers and asks for name and reason), Hold Assist detection (listens for a human " |
|
D_WHAT+="replacing the hold music), Live Translation of calls and Live Voicemail transcripts. On the " |
|
D_WHAT+="Mac these run through Continuity with your iPhone; all of them are opt-in features." |
|
D_AFFECTS="Those features in the Phone and FaceTime apps on this Mac. The call relay itself " |
|
D_AFFECTS+="(callservicesd, telephonyutilities) is untouched, so iPhone calls on the Mac still work. " |
|
D_AFFECTS+="Irrelevant if you never route calls through the Mac." ;; |
|
|
|
com.apple.intelligencetasksd) |
|
D_RISK="low" |
|
D_WHAT="New in Golden Gate's Apple Intelligence stack and undocumented by Apple. By name and family " |
|
D_WHAT+="it is the scheduler for background intelligence work — batched summarisation, notification " |
|
D_WHAT+="prioritisation, mail categorisation and similar jobs that run while the Mac is idle. " |
|
D_WHAT+="Nothing outside Apple Intelligence is known to call it; the description is inferred." |
|
D_AFFECTS="Background AI jobs only. If a summary-style feature stops refreshing after the trim, " |
|
D_AFFECTS+="this is the reason." ;; |
|
|
|
com.apple.GenerativeFunctions.agentstored) |
|
D_RISK="low" |
|
D_WHAT="Part of the GenerativeFunctions framework, the layer that Writing Tools and Foundation Models " |
|
D_WHAT+="requests run through. The name says it stores 'agents' — most plausibly the registry of AI " |
|
D_WHAT+="agents and extensions Siri AI can delegate to (the ChatGPT extension and the third-party " |
|
D_WHAT+="model delegation Golden Gate added). Undocumented; description inferred from the framework." |
|
D_AFFECTS="Siri AI's extension list and model delegation. Nothing outside the AI feature set." ;; |
|
|
|
com.apple.mlhostd) |
|
D_RISK="medium" |
|
D_WHAT="The ML host: the process that actually loads and runs the on-device Foundation Model, spawned " |
|
D_WHAT+="and supervised by modelmanagerd. This is where the memory goes when Apple Intelligence 'warms " |
|
D_WHAT+="up'. Because it lives in your user domain, the disable sticks even where the system-level " |
|
D_WHAT+="modelmanagerd refuses with SIP on." |
|
D_AFFECTS="Same as modelmanagerd: every on-device generative feature (Writing Tools, summaries, " |
|
D_AFFECTS+="Genmoji, on-device Siri AI turns) and third-party apps using the Foundation Models framework, " |
|
D_AFFECTS+="which should fall back gracefully. Medium for the same breadth." ;; |
|
|
|
com.apple.ModelCatalogAgent) |
|
D_RISK="low" |
|
D_WHAT="User-side half of the Model Catalog: tracks which AI model assets (the Foundation Model, its " |
|
D_WHAT+="adapters, Siri and vision models) are installed and requests downloads and updates through " |
|
D_WHAT+="MobileAsset. Stopping it stops the multi-gigabyte model downloads and refreshes." |
|
D_AFFECTS="Apple Intelligence model downloads and updates. If you re-enable Apple Intelligence later, " |
|
D_AFFECTS+="run golden-gate-restore.sh (or re-enable this label) so the models can update. Dictation and keyboard " |
|
D_AFFECTS+="models arrive through other channels and are unaffected." ;; |
|
|
|
# ── 1b. Apple Intelligence — system domain ───────────────────────────────── |
|
com.apple.modelmanagerd) |
|
D_RISK="medium" |
|
D_WHAT="Manages the on-device Foundation Models: loads and unloads the ~3-billion-parameter language " |
|
D_WHAT+="model and its adapters, and serves inference both to Apple's own features and to third-party " |
|
D_WHAT+="apps through the Foundation Models framework. It is the single largest memory and CPU " |
|
D_WHAT+="consumer in the AI stack, which is why 8 GB and 16 GB machines feel it most. Runs as a system " |
|
D_WHAT+="daemon, so this needs sudo, and with SIP on launchd may refuse or Apple may pin it — check " |
|
D_WHAT+="--status after the reboot." |
|
D_AFFECTS="Every on-device Apple Intelligence feature (Writing Tools, summaries, notification " |
|
D_AFFECTS+="prioritisation, Genmoji, on-device Siri AI turns) and any third-party app that adopted the " |
|
D_AFFECTS+="Foundation Models framework — those apps get an 'unavailable' result and should fall back " |
|
D_AFFECTS+="gracefully, but a badly written one may show an error. Broad, hence medium; still purely AI." ;; |
|
|
|
com.apple.privatecloudcomputed) |
|
D_RISK="low" |
|
D_WHAT="Client for Private Cloud Compute: verifies (attests) Apple's server images and ships the " |
|
D_WHAT+="requests that are too large for the on-device model. Without it, cloud-backed Apple " |
|
D_WHAT+="Intelligence requests fail immediately instead of leaving the Mac." |
|
D_AFFECTS="Cloud-backed Apple Intelligence requests only. Nothing else uses it." ;; |
|
|
|
com.apple.modelcatalogd) |
|
D_RISK="low" |
|
D_WHAT="The system half of the Model Catalog: the root-privileged side that owns the shared model " |
|
D_WHAT+="storage and performs the actual asset installs. Same purpose as ModelCatalogAgent." |
|
D_AFFECTS="Same as ModelCatalogAgent — model downloads and updates for Apple Intelligence only." ;; |
|
|
|
# ── 2. Suggestions, knowledge graph, Biome ───────────────────────────────── |
|
com.apple.suggestd) |
|
D_RISK="medium" |
|
D_WHAT="Scans the content of your Mail, Messages and Notes for contacts, events, addresses, " |
|
D_WHAT+="flight numbers and similar entities, and turns them into suggestions (the 'Siri found in " |
|
D_WHAT+="Mail' banners, suggested events, suggested recipients). It is a convenience feature, but " |
|
D_WHAT+="one some people use daily without realising it." |
|
D_AFFECTS="Suggested events and contacts in Calendar and Contacts, 'found in Mail' details, " |
|
D_AFFECTS+="suggested recipients in Mail and Messages, Spotlight hits for contacts that only appear in " |
|
D_AFFECTS+="mail, some Safari address autofill. On a work Mac with Exchange the Calendar suggestion " |
|
D_AFFECTS+="banner disappears. Remove from SUGGEST_AGENTS if you like those." ;; |
|
|
|
com.apple.parsecd) |
|
D_RISK="low" |
|
D_WHAT="Backs 'Siri Suggestions' in Spotlight, Safari and Look Up: as you type, it fetches web, " |
|
D_WHAT+="Wikipedia, Maps, App Store and Siri Knowledge results from Apple. Disabling it keeps your " |
|
D_WHAT+="keystrokes local and makes Spotlight a purely local search." |
|
D_AFFECTS="Spotlight shows only local results (files, apps, contacts, calculator, definitions); the " |
|
D_AFFECTS+="Safari smart search field loses Siri Suggestions (the search engine's own suggestions stay); " |
|
D_AFFECTS+="Look Up loses Siri Knowledge cards. Privacy-positive." ;; |
|
|
|
com.apple.parsec-fbf) |
|
D_RISK="low" |
|
D_WHAT="Periodically flushes and uploads Siri Search usage analytics to Apple. Pure telemetry for " |
|
D_WHAT+="the parsecd feature above." |
|
D_AFFECTS="Nothing user-visible." ;; |
|
|
|
com.apple.knowledge-agent) |
|
D_RISK="low" |
|
D_WHAT="CoreDuet's knowledge-store agent: records app usage, interaction and focus events that the " |
|
D_WHAT+="prediction engines feed on. Historical data stays on disk; only new recording stops." |
|
D_AFFECTS="Quality of Siri Suggestions and proactive predictions; Screen Time's 'most used' ranking " |
|
D_AFFECTS+="may be slightly less accurate. No functional breakage." ;; |
|
|
|
com.apple.duetexpertd) |
|
D_RISK="low" |
|
D_WHAT="The 'proactive' prediction engine: decides which apps, contacts and actions to surface next " |
|
D_WHAT+="(Dock recents suggestions, Spotlight top-hit ranking, Share-sheet suggested people, Handoff " |
|
D_WHAT+="prompts, Time to Leave). It consumes the CoreDuet and Biome data streams." |
|
D_AFFECTS="Suggested apps and people in Spotlight, Share sheet, Dock and the Siri Suggestions widget " |
|
D_AFFECTS+="become generic or disappear. Nothing else breaks." ;; |
|
|
|
com.apple.ContextStoreAgent) |
|
D_RISK="low" |
|
D_WHAT="CoreDuet's context store: keeps a short rolling record of device context (current app, " |
|
D_WHAT+="Focus state, location cluster, motion) that suggestion engines and Focus filters query." |
|
D_AFFECTS="Suggestion quality; Focus filters keep working because Focus itself (donotdisturbd) is " |
|
D_AFFECTS+="untouched. Nothing else." ;; |
|
|
|
com.apple.BiomeAgent) |
|
D_RISK="medium" |
|
D_WHAT="Biome is the event-stream database behind personalisation: app launches, notifications, " |
|
D_WHAT+="Safari and Messages events and more are streamed into it and consumed by Siri Suggestions, " |
|
D_WHAT+="Screen Time, the Journaling Suggestions API and Apple Intelligence's personal context. This " |
|
D_WHAT+="agent runs the user-level Biome operation graphs. The system half (biomed) is deliberately " |
|
D_WHAT+="not touched because Shortcuts and Focus depend on it." |
|
D_AFFECTS="Screen Time reports can show gaps; Siri Suggestions degrade; apps using Journaling " |
|
D_AFFECTS+="Suggestions show fewer prompts. Some daemons write 'Biome unavailable' log noise. " |
|
D_AFFECTS+="Shortcuts automations are unaffected. Medium because of Screen Time." ;; |
|
|
|
com.apple.biomesyncd) |
|
D_RISK="low" |
|
D_WHAT="Syncs Biome event streams between your devices through iCloud, so suggestions on the Mac " |
|
D_WHAT+="know what you did on the iPhone. A frequent source of unexplained background network and " |
|
D_WHAT+="CPU activity on fresh installs." |
|
D_AFFECTS="Cross-device continuity of suggestions only. Nothing on a Mac that is not signed into " |
|
D_AFFECTS+="a personal iCloud account." ;; |
|
|
|
com.apple.routined) |
|
D_RISK="low" |
|
D_WHAT="Learns your 'Significant Locations' — places you visit often and when — from location " |
|
D_WHAT+="events, to predict future visits. locationd itself (time zone, Find My, Weather, corporate " |
|
D_WHAT+="tools) stays enabled; only the learning stops." |
|
D_AFFECTS="Calendar and Maps 'time to leave' / travel-time hints, Photos Memories place grouping, " |
|
D_AFFECTS+="location-based Siri Suggestions. On a desk-bound Mac: nothing." ;; |
|
|
|
com.apple.proactived) |
|
D_RISK="low" |
|
D_WHAT="The current proactive-suggestions engine — the successor to duetexpertd, which still exists " |
|
D_WHAT+="as a thin shim. Computes the app, contact and action predictions from CoreDuet and Biome data." |
|
D_AFFECTS="Suggested apps in Spotlight and the Dock, Share-sheet people suggestions, the Siri " |
|
D_AFFECTS+="Suggestions widget. Suggestions get generic; nothing breaks." ;; |
|
|
|
com.apple.proactiveeventtrackerd) |
|
D_RISK="low" |
|
D_WHAT="Tracks the events (app launches, notification interactions, activity) that the proactive " |
|
D_WHAT+="engine learns from." |
|
D_AFFECTS="Suggestion quality only." ;; |
|
|
|
com.apple.intelligentroutingd) |
|
D_RISK="low" |
|
D_WHAT="Per Apple's own man page: a per-user daemon that provides recommendations based on history " |
|
D_WHAT+="patterns — another member of the Siri Suggestions family. Notorious for runaway resource use " |
|
D_WHAT+="(users report 99% CPU and 18 to 40 GB of RAM), and force-quitting it changes nothing visible, " |
|
D_WHAT+="which says how essential it is." |
|
D_AFFECTS="Suggestion quality. No known dependency." ;; |
|
|
|
com.apple.spotlightknowledged|com.apple.spotlightknowledged.importer|com.apple.spotlightknowledged.updater) |
|
D_RISK="medium" |
|
D_WHAT="SpotlightKnowledge: the Core Spotlight 'knowledge events' index (~/Library/Metadata/" |
|
D_WHAT+="CoreSpotlight/SpotlightKnowledgeEvents) that records what you open, receive and do, so that " |
|
D_WHAT+="Spotlight can rank results by context and Siri AI can search things like the PDF a colleague " |
|
D_WHAT+="sent last week. Golden Gate's rebuilt search foundation sits on it. It is NOT the file index " |
|
D_WHAT+="(mds / mdworker), which stays on. On Tahoe it became notorious for 30 to 45 GB memory leaks " |
|
D_WHAT+="after sleep. .importer feeds it, .updater maintains it; the three are disabled together." |
|
D_AFFECTS="Spotlight's contextual ranking and recents, Siri AI's search across your personal data. " |
|
D_AFFECTS+="Plain file, app, contact, calculator and definition search continues. Medium because Spotlight " |
|
D_AFFECTS+="is daily-use — remove the three labels from SUGGEST_AGENTS if ranking gets noticeably worse." ;; |
|
|
|
# ── 3. Telemetry, ads, tips, experiments — user domain ───────────────────── |
|
com.apple.ap.adprivacyd) |
|
D_RISK="low" |
|
D_WHAT="Apple's advertising-privacy daemon: manages the advertising identifier and the " |
|
D_WHAT+="Personalised Ads opt-in state and talks to Apple's ad platform." |
|
D_AFFECTS="Personalisation of ads in the App Store, News and Stocks. Nothing else." ;; |
|
|
|
com.apple.ap.promotedcontentd) |
|
D_RISK="low" |
|
D_WHAT="Fetches Apple's promoted content (App Store search ads and 'suggested' placements, News " |
|
D_WHAT+="promotions) and reports impressions and taps back." |
|
D_AFFECTS="App Store ads may still appear but are no longer personalised or measured. Nothing else." ;; |
|
|
|
com.apple.tipsd) |
|
D_RISK="low" |
|
D_WHAT="The Tips app's background service: schedules the 'Tips' notifications and welcome prompts " |
|
D_WHAT+="after updates." |
|
D_AFFECTS="Tips notifications stop. The Tips app itself still opens on demand." ;; |
|
|
|
com.apple.inputanalyticsd) |
|
D_RISK="low" |
|
D_WHAT="Collects keyboard and trackpad usage diagnostics (typing statistics, autocorrect " |
|
D_WHAT+="acceptance rates) for users who opted into sharing analytics." |
|
D_AFFECTS="Nothing user-visible." ;; |
|
|
|
com.apple.geoanalyticsd) |
|
D_RISK="low" |
|
D_WHAT="Uploads Maps / GeoServices usage analytics." |
|
D_AFFECTS="Nothing user-visible. Maps itself is untouched." ;; |
|
|
|
com.apple.UsageTrackingAgent) |
|
D_RISK="medium" |
|
D_WHAT="Records per-app usage time, notification counts and pickups — the raw data behind Screen " |
|
D_WHAT+="Time. Without it Screen Time has nothing to report on this Mac and App Limits may not fire." |
|
D_AFFECTS="Screen Time reports, App Limits and Downtime statistics for this user. Medium if you " |
|
D_AFFECTS+="(or a family setup) rely on Screen Time; otherwise a pure tracker. Remove from " |
|
D_AFFECTS+="TELEMETRY_AGENTS if you want Screen Time to keep working." ;; |
|
|
|
com.apple.triald) |
|
D_RISK="low" |
|
D_WHAT="'Trial' is Apple's A/B-experiment and staged-rollout client. It downloads experiment " |
|
D_WHAT+="configurations and variant ML assets (Siri, Dictation, autocorrect models) and reports " |
|
D_WHAT+="results back. Frequently blamed for background CPU and network on fresh installs." |
|
D_AFFECTS="You get default feature behaviour instead of experimental variants; some ML model " |
|
D_AFFECTS+="refreshes that Apple rolls out through Trial (Dictation, autocorrect) may lag. No breakage." ;; |
|
|
|
# ── 3b. Telemetry — system domain ────────────────────────────────────────── |
|
com.apple.analyticsd) |
|
D_RISK="low" |
|
D_WHAT="The central analytics daemon: aggregates diagnostic and usage events from the whole OS " |
|
D_WHAT+="into the data you see in Console → Analytics Data, and uploads them if sharing is on. With " |
|
D_WHAT+="SIP on, bootout is refused; the disable is usually written and honoured at the next boot — " |
|
D_WHAT+="verify with --status." |
|
D_AFFECTS="Console's Analytics Data view, some Feedback Assistant attachments, Apple support " |
|
D_AFFECTS+="diagnostics. A few subsystems log warnings when it is missing. Nothing MDM-related." ;; |
|
|
|
com.apple.audioanalyticsd) |
|
D_RISK="low" |
|
D_WHAT="CoreAudio usage and quality analytics (sample-rate changes, dropouts, device switches)." |
|
D_AFFECTS="Nothing user-visible. Audio itself is untouched." ;; |
|
|
|
com.apple.wifianalyticsd) |
|
D_RISK="low" |
|
D_WHAT="Wi-Fi connection-quality analytics upload." |
|
D_AFFECTS="Nothing user-visible. Wireless Diagnostics still works." ;; |
|
|
|
com.apple.ecosystemanalyticsd) |
|
D_RISK="low" |
|
D_WHAT="Cross-device ('ecosystem') analytics: how your Apple devices are used together." |
|
D_AFFECTS="Nothing user-visible." ;; |
|
|
|
com.apple.triald.system) |
|
D_RISK="low" |
|
D_WHAT="The system-level half of Trial (see com.apple.triald): experiment assets for root-owned " |
|
D_WHAT+="components." |
|
D_AFFECTS="Same as triald: default rollouts instead of experiments. No breakage." ;; |
|
|
|
# ── optional: media analysis ─────────────────────────────────────────────── |
|
com.apple.mediaanalysisd) |
|
D_RISK="medium" |
|
D_WHAT="The on-device computer-vision pipeline: OCR for Live Text, Visual Look Up, subject lifting " |
|
D_WHAT+="and background removal, scene and object classification for images and video — used by " |
|
D_WHAT+="many apps, not just Photos. Only disabled with --with-media-analysis." |
|
D_AFFECTS="Live Text in Preview, Quick Look, Safari, Photos and screenshots; Visual Look Up and " |
|
D_AFFECTS+="Golden Gate's Visual Intelligence; Remove Background in Preview and Quick Actions; Spotlight " |
|
D_AFFECTS+="search for text inside images; Photos scene search. Photos may show 'analysing' forever. " |
|
D_AFFECTS+="Real feature loss, hence medium." ;; |
|
|
|
com.apple.photoanalysisd) |
|
D_RISK="medium" |
|
D_WHAT="Photos-library analysis: face, people and pet recognition, Memories generation, " |
|
D_WHAT+="aesthetics scoring and duplicate detection. Only disabled with --with-media-analysis." |
|
D_AFFECTS="Photos.app: People & Pets album stops updating, no new Memories, Featured Photos widget " |
|
D_AFFECTS+="and the Duplicates album go stale; Photos may sit at 'Analysing…'. Irrelevant if you do " |
|
D_AFFECTS+="not use Photos on this Mac." ;; |
|
|
|
# ── optional: diagnostics ────────────────────────────────────────────────── |
|
com.apple.ReportCrash) |
|
D_RISK="medium" |
|
D_WHAT="Writes the .ips crash reports for user-level processes into ~/Library/Logs/" |
|
D_WHAT+="DiagnosticReports and shows the 'quit unexpectedly' dialog. Only disabled with " |
|
D_WHAT+="--with-diagnostics." |
|
D_AFFECTS="No crash logs for your apps: harder debugging, Console → Crash Reports stays empty, " |
|
D_AFFECTS+="Feedback Assistant and IT cannot attach reports. The 'unexpectedly quit / Reopen' dialog " |
|
D_AFFECTS+="disappears. Medium for anyone who develops or troubleshoots software." ;; |
|
|
|
com.apple.ReportPanic) |
|
D_RISK="low" |
|
D_WHAT="Shows the 'your computer was restarted because of a problem' dialog after a kernel panic " |
|
D_WHAT+="and offers to send the report to Apple. The kernel still records the panic log itself." |
|
D_AFFECTS="Only that dialog. Panic logs remain in /Library/Logs/DiagnosticReports." ;; |
|
|
|
com.apple.spindump) |
|
D_RISK="medium" |
|
D_WHAT="Samples hung or unresponsive processes and writes .spin / .hang reports; it also backs " |
|
D_WHAT+="Activity Monitor's Sample Process and Spindump commands and the system's hang detection. " |
|
D_WHAT+="Real-time-audio users disable it because a sampling pass can stall processes for a moment. " |
|
D_WHAT+="Only disabled with --with-diagnostics." |
|
D_AFFECTS="Activity Monitor sampling, the spindump CLI, hang diagnostics that Apple support or " |
|
D_AFFECTS+="developers ask for. Nothing else." ;; |
|
|
|
com.apple.metadata.mds.spindump) |
|
D_RISK="low" |
|
D_WHAT="Spotlight-specific hang sampler: captures a spindump of the metadata server when it stalls. " |
|
D_WHAT+="Only disabled with --with-diagnostics." |
|
D_AFFECTS="Spotlight hang diagnostics only. Indexing and search are untouched." ;; |
|
|
|
# ── 4. defaults ──────────────────────────────────────────────────────────── |
|
"com.apple.assistant.support|Assistant Enabled") |
|
D_RISK="low" |
|
D_WHAT="The preference behind System Settings → Apple Intelligence & Siri → Siri toggle. Writing " |
|
D_WHAT+="it here mirrors switching Siri off in Settings and makes the state explicit even if the " |
|
D_WHAT+="Settings pane later re-arranges. On a managed Mac an MDM 'allowAssistant' restriction wins " |
|
D_WHAT+="either way, so this can never conflict with policy." |
|
D_AFFECTS="Siri (voice, typed, keyboard shortcut). Dictation and Spotlight are unaffected." ;; |
|
|
|
"com.apple.assistant.support|Siri Data Sharing Opt-In Status") |
|
D_RISK="low" |
|
D_WHAT="The 'Improve Siri & Dictation' choice: whether audio recordings and transcripts may be " |
|
D_WHAT+="shared with Apple. Value 2 = opted out, 1 = opted in, absent = never asked. Should Apple " |
|
D_WHAT+="have changed the semantics in 27, the worst case is a no-op." |
|
D_AFFECTS="Only what leaves the Mac. No feature depends on it." ;; |
|
|
|
"com.apple.Siri|StatusMenuVisible") |
|
D_RISK="low" |
|
D_WHAT="Hides the Siri icon in the menu bar (System Settings → Control Center → Siri)." |
|
D_AFFECTS="Cosmetic. Siri can still be summoned by keyboard shortcut if it is enabled." ;; |
|
|
|
"com.apple.Siri|VoiceTriggerUserEnabled") |
|
D_RISK="low" |
|
D_WHAT="Turns off the 'Listen for Siri' wake word (\"Siri\" / \"Hey Siri\"). Besides privacy this " |
|
D_WHAT+="stops the always-on audio pipeline that listens for the trigger." |
|
D_AFFECTS="Voice activation of Siri only. Dictation and the microphone in other apps are unaffected." ;; |
|
|
|
"com.apple.lookup.shared|LookupSuggestionsDisabled") |
|
D_RISK="low" |
|
D_WHAT="Removes Siri Suggestions — Siri Knowledge, Wikipedia, App Store, music and movie cards — " |
|
D_WHAT+="from the Look Up popover (force-click or Ctrl-Cmd-D) and Spotlight previews, so looked-up " |
|
D_WHAT+="words are not sent to Apple. Dictionary and Thesaurus results remain." |
|
D_AFFECTS="Look Up shows dictionary results only. Nothing else." ;; |
|
|
|
"com.apple.AdLib|allowApplePersonalizedAdvertising") |
|
D_RISK="low" |
|
D_WHAT="The 'Personalised Ads' switch (System Settings → Privacy & Security → Apple Advertising)." |
|
D_AFFECTS="Ads in the App Store, News and Stocks become non-personalised. Nothing else." ;; |
|
|
|
"NSGlobalDomain|NSDocumentSaveNewDocumentsToCloud") |
|
D_RISK="low" |
|
D_WHAT="Makes the Save dialog for new documents default to a local folder (last used, or Documents) " |
|
D_WHAT+="instead of iCloud Drive. Sensible on a work Mac where files should not land in a personal " |
|
D_WHAT+="iCloud by accident. Existing documents are untouched and iCloud Drive can still be chosen " |
|
D_WHAT+="manually. This is a convenience default from the Bynens dotfile, not an AI setting — delete " |
|
D_WHAT+="the line from DEFAULTS if you prefer Apple's behaviour." |
|
D_AFFECTS="Every document-based app: TextEdit, Preview, Pages, Numbers, Keynote and many " |
|
D_AFFECTS+="third-party editors. Only the pre-selected folder in the Save dialog changes." ;; |
|
|
|
"/Library/Application Support/CrashReporter/DiagnosticMessagesHistory|AutoSubmit") |
|
D_RISK="low" |
|
D_WHAT="System Settings → Privacy & Security → Analytics & Improvements → 'Share Mac Analytics'. " |
|
D_WHAT+="Stops the daily upload of analytics and diagnostic reports to Apple. Lives in a root-owned " |
|
D_WHAT+="plist, hence sudo. On managed Macs this switch is frequently pinned by a configuration " |
|
D_WHAT+="profile — then the write fails or is overridden, which is fine and expected." |
|
D_AFFECTS="Only what leaves the Mac. Feedback Assistant still works when you use it deliberately." ;; |
|
|
|
"/Library/Application Support/CrashReporter/DiagnosticMessagesHistory|ThirdPartyDataSubmit") |
|
D_RISK="low" |
|
D_WHAT="The 'Share with App Developers' switch next to it: whether crash data of third-party apps " |
|
D_WHAT+="is forwarded to their developers through Apple." |
|
D_AFFECTS="Only what leaves the Mac. Third-party apps' own crash reporters (Sentry etc.) are separate." ;; |
|
|
|
esac |
|
} |
|
|
|
# ═════════════════════════════════════════════════════════════════════════════ |
|
# Options |
|
# ═════════════════════════════════════════════════════════════════════════════ |
|
DRY_RUN=0; MODE=apply; WITH_MEDIA=0; WITH_DIAG=0; DO_DEFAULTS=1; DO_SYSTEM=1; FILTER="" |
|
for arg in "$@"; do |
|
case "$arg" in |
|
--dry-run) DRY_RUN=1 ;; |
|
--status) MODE=status ;; |
|
--scan) MODE=scan ;; |
|
--footprint) MODE=footprint ;; |
|
--explain) MODE=explain ;; |
|
--with-media-analysis) WITH_MEDIA=1 ;; |
|
--with-diagnostics) WITH_DIAG=1 ;; |
|
--no-defaults) DO_DEFAULTS=0 ;; |
|
--no-system) DO_SYSTEM=0 ;; |
|
-h|--help) sed -n '2,49p' "$0"; exit 0 ;; |
|
-*) echo "unknown option: $arg (try --help)"; exit 2 ;; |
|
*) FILTER=$arg ;; # free text = filter for --explain / --status |
|
esac |
|
done |
|
|
|
# ═════════════════════════════════════════════════════════════════════════════ |
|
# Helpers |
|
# ═════════════════════════════════════════════════════════════════════════════ |
|
mkdir -p "$STATE_DIR" 2>/dev/null || true |
|
|
|
say() { printf '%s\n' "$*" | tee -a "$LOG_FILE" 2>/dev/null || printf '%s\n' "$*"; } |
|
run() { if (( DRY_RUN )); then say " DRY: $*"; return 0; fi; "$@"; } # run, show in dry-run |
|
runq() { if (( DRY_RUN )); then say " DRY: $*"; return 0; fi; "$@" >/dev/null 2>&1; } # run quietly (failures expected) |
|
wrap() { printf '%s\n' "$2" | fold -s -w 86 | sed "s/^/$1/"; } # wrap: indent text |
|
lower(){ printf '%s' "$1" | tr '[:upper:]' '[:lower:]'; } |
|
|
|
matches_filter() { # id → true if no filter or filter is a substring (case-insensitive) |
|
[[ -z $FILTER ]] && return 0 |
|
[[ $(lower "$1") == *"$(lower "$FILTER")"* ]] |
|
} |
|
|
|
explain_entry() { # kind(gui|system|default) id |
|
local kind=$1 id=$2 head |
|
matches_filter "$id" || return 0 |
|
describe "$id" |
|
if [[ $kind == default ]]; then head="defaults ${id%%|*} → ${id#*|}"; else head="$id [$kind]"; fi |
|
printf '\n%s — risk: %s\n' "$head" "$D_RISK" |
|
wrap " " "What: $D_WHAT" |
|
wrap " " "Affects: $D_AFFECTS" |
|
} |
|
explain_inline() { # used by the dry run under each step |
|
wrap " " "what: $D_WHAT" |
|
wrap " " "affects: $D_AFFECTS" |
|
} |
|
|
|
SUDO_OK=0 |
|
SUDO_KEEPALIVE_PID="" |
|
start_sudo_keepalive() { |
|
( while true; do sudo -n true 2>/dev/null; sleep 50; kill -0 "$$" 2>/dev/null || exit; done ) & |
|
SUDO_KEEPALIVE_PID=$! |
|
} |
|
trap '[[ -n "$SUDO_KEEPALIVE_PID" ]] && kill "$SUDO_KEEPALIVE_PID" 2>/dev/null' EXIT |
|
|
|
want_sudo() { |
|
(( DO_SYSTEM )) || return 0 |
|
if (( DRY_RUN )); then SUDO_OK=1; return 0; fi |
|
say "" |
|
say "Admin password needed once for the system/ daemons and the analytics-sharing plist" |
|
say "(press Ctrl-C at the prompt if you'd rather not; or rerun with --no-system):" |
|
if sudo -v; then SUDO_OK=1; start_sudo_keepalive; else say "no admin rights — system/ part skipped"; fi |
|
} |
|
|
|
agent_exists() { # label domain(gui|system) |
|
local label=$1 dom=$2 |
|
if [[ $dom == gui ]]; then |
|
[[ -f /System/Library/LaunchAgents/$label.plist ]] || launchctl print "gui/$UID/$label" >/dev/null 2>&1 |
|
else |
|
[[ -f /System/Library/LaunchDaemons/$label.plist ]] || launchctl print "system/$label" >/dev/null 2>&1 |
|
fi |
|
} |
|
|
|
record_agent() { # domain label |
|
(( DRY_RUN )) && return 0 |
|
local line; line=$(printf 'agent\t%s\t%s' "$1" "$2") |
|
grep -qxF "$line" "$STATE_FILE" 2>/dev/null && return 0 |
|
printf '%s\n' "$line" >> "$STATE_FILE" |
|
} |
|
record_default() { # domain key type prev (first recording wins, so reruns keep the true original) |
|
(( DRY_RUN )) && return 0 |
|
local prefix; prefix=$(printf 'default\t%s\t%s\t' "$1" "$2") |
|
grep -qF "$prefix" "$STATE_FILE" 2>/dev/null && return 0 |
|
printf 'default\t%s\t%s\t%s\t%s\n' "$1" "$2" "$3" "$4" >> "$STATE_FILE" |
|
} |
|
|
|
disable_label() { # domain label |
|
local dom=$1 label=$2 target |
|
if ! agent_exists "$label" "$dom"; then |
|
say " · $label — not present on this system, skipped"; return 0 |
|
fi |
|
describe "$label" |
|
if [[ $dom == gui ]]; then |
|
target="gui/$UID/$label" |
|
runq launchctl bootout "$target" # stops it now; "not loaded" is fine |
|
if run launchctl disable "$target"; then |
|
say " ✓ $label — disabled ($target) [risk: $D_RISK]"; record_agent gui "$label" |
|
else |
|
say " ✗ $label — launchctl disable refused" |
|
fi |
|
else |
|
target="system/$label" |
|
(( SUDO_OK )) || { say " · $label — skipped (no sudo)"; return 0; } |
|
runq sudo launchctl bootout "$target" # fails with SIP on — expected |
|
if run sudo launchctl disable "$target"; then |
|
say " ✓ $label — disabled for next boot ($target) [risk: $D_RISK]"; record_agent system "$label" |
|
else |
|
say " ✗ $label — launchctl disable refused (SIP / pinned by Apple)" |
|
fi |
|
fi |
|
(( DRY_RUN )) && explain_inline |
|
return 0 |
|
} |
|
|
|
apply_default() { # "domain|key|type|value|needs_sudo" |
|
local dom key type val needs_sudo prev S="" |
|
IFS='|' read -r dom key type val needs_sudo <<< "$1" |
|
describe "$dom|$key" |
|
if [[ $needs_sudo == 1 ]]; then |
|
(( SUDO_OK )) || { say " · $dom :: $key — skipped (no sudo)"; return 0; } |
|
S=sudo |
|
fi |
|
prev=$($S defaults read "$dom" "$key" 2>/dev/null) || prev="__absent__" |
|
record_default "$dom" "$key" "$type" "$prev" |
|
if runq $S defaults write "$dom" "$key" "-$type" "$val"; then |
|
say " ✓ $dom :: $key = $val (was: $prev) [risk: $D_RISK]" |
|
else |
|
say " ✗ $dom :: $key — write failed (locked by a configuration profile?)" |
|
fi |
|
(( DRY_RUN )) && explain_inline |
|
return 0 |
|
} |
|
|
|
confirm() { |
|
(( DRY_RUN )) && return 0 |
|
local ans="" |
|
printf '%s [y/N] ' "$1"; read -r ans |
|
[[ $ans == y || $ans == Y ]] |
|
} |
|
|
|
# ═════════════════════════════════════════════════════════════════════════════ |
|
# Modes |
|
# ═════════════════════════════════════════════════════════════════════════════ |
|
preflight() { |
|
if [[ $EUID -eq 0 ]]; then |
|
echo "Run this as your normal user, not with sudo — it needs your own uid for the gui domain."; exit 1 |
|
fi |
|
local ver major arch enroll |
|
ver=$(sw_vers -productVersion 2>/dev/null || echo "?"); major=${ver%%.*}; arch=$(uname -m) |
|
say "golden-gate-debloater · $(date)" |
|
say "macOS $ver ($arch), uid $UID, state: $STATE_FILE" |
|
case $major in |
|
27) ;; |
|
26) say "note: Tahoe — com.apple.campo (Siri AI app) will simply be reported as not present." ;; |
|
*) say "warning: written for macOS 26/27; labels may differ on $ver." ;; |
|
esac |
|
enroll=$(profiles status -type enrollment 2>/dev/null | tr '\n' ' ' | sed 's/ */ /g') |
|
[[ -n $enroll ]] && say "enrollment: $enroll" |
|
say "Nothing MDM-, push-, account-, update- or security-related is in any list below." |
|
} |
|
|
|
apply() { |
|
preflight |
|
say "" |
|
say "Before continuing: System Settings → Apple Intelligence & Siri → both OFF." |
|
(( DRY_RUN )) && say "(dry run — nothing will be changed; descriptions follow each step, risk in brackets)" |
|
confirm "Apply the trim now?" || { say "aborted, nothing changed."; exit 0; } |
|
want_sudo |
|
|
|
say ""; say "== 1/4 Apple Intelligence & Siri (gui/$UID)" |
|
local l |
|
for l in "${AI_AGENTS[@]}"; do disable_label gui "$l"; done |
|
|
|
say ""; say "== 2/4 Suggestions, knowledge graph, Biome (gui/$UID)" |
|
for l in "${SUGGEST_AGENTS[@]}"; do disable_label gui "$l"; done |
|
|
|
say ""; say "== 3/4 Telemetry, ads, tips, experiments (gui/$UID)" |
|
for l in "${TELEMETRY_AGENTS[@]}"; do disable_label gui "$l"; done |
|
if (( WITH_MEDIA )); then |
|
say " -- optional: media analysis (Live Text / Visual Look Up / Visual Intelligence will stop working)" |
|
for l in "${MEDIA_AGENTS[@]}"; do disable_label gui "$l"; done |
|
fi |
|
if (( WITH_DIAG )); then |
|
say " -- optional: crash & hang diagnostics" |
|
for l in "${DIAG_AGENTS[@]}"; do disable_label gui "$l"; done |
|
fi |
|
|
|
if (( DO_SYSTEM )); then |
|
say ""; say "== 4/4 System daemons (system/ — takes effect at next boot)" |
|
for l in "${AI_DAEMONS[@]}" "${TELEMETRY_DAEMONS[@]}"; do disable_label system "$l"; done |
|
if (( WITH_DIAG )); then for l in "${DIAG_DAEMONS[@]}"; do disable_label system "$l"; done; fi |
|
else |
|
say ""; say "== 4/4 System daemons — skipped (--no-system)" |
|
fi |
|
|
|
if (( DO_DEFAULTS )); then |
|
say ""; say "== defaults" |
|
local d |
|
for d in "${DEFAULTS[@]}"; do apply_default "$d"; done |
|
fi |
|
|
|
say "" |
|
say "Done. Reboot, then run: ./golden-gate-debloater.sh --status" |
|
say "Undo any time with: ./golden-gate-restore.sh (state file: $STATE_FILE)" |
|
say "Rows marked ✗, or still 'running' after the reboot, are held by Apple — leave them." |
|
say "Log: $LOG_FILE" |
|
} |
|
|
|
explain() { |
|
cat <<'EOF' |
|
golden-gate-debloater — catalogue of every setting it can change |
|
=================================================== |
|
Risk scale: |
|
low background-only; you lose only the named feature, which you have already switched |
|
off or never see. Fully reversible with golden-gate-restore.sh. |
|
medium removes or degrades something people use every day (Live Text, Screen Time reports, |
|
crash logs, Spoken Content voices, Dictation edge cases). Reversible — read Affects. |
|
There is no "high": everything MDM-, account-, update- or security-related is not in the |
|
lists at all. gui/ entries are per user (other accounts unaffected); system/ entries are |
|
machine-wide and need sudo. Labels absent on your OS build are skipped automatically. |
|
EOF |
|
local l d |
|
hdr() { [[ -z $FILTER ]] && { echo; echo "$1"; }; return 0; } |
|
hdr "── 1. Apple Intelligence & Siri — user domain ──────────────────────────────────" |
|
for l in "${AI_AGENTS[@]}"; do explain_entry gui "$l"; done |
|
hdr "── 1b. Apple Intelligence — system domain (sudo) ───────────────────────────────" |
|
for l in "${AI_DAEMONS[@]}"; do explain_entry system "$l"; done |
|
hdr "── 2. Suggestions, knowledge graph, Biome — user domain ────────────────────────" |
|
for l in "${SUGGEST_AGENTS[@]}"; do explain_entry gui "$l"; done |
|
hdr "── 3. Telemetry, ads, tips, experiments ────────────────────────────────────────" |
|
for l in "${TELEMETRY_AGENTS[@]}"; do explain_entry gui "$l"; done |
|
for l in "${TELEMETRY_DAEMONS[@]}";do explain_entry system "$l"; done |
|
hdr "── optional: media analysis (--with-media-analysis) ────────────────────────────" |
|
for l in "${MEDIA_AGENTS[@]}"; do explain_entry gui "$l"; done |
|
hdr "── optional: diagnostics (--with-diagnostics) ──────────────────────────────────" |
|
for l in "${DIAG_AGENTS[@]}"; do explain_entry gui "$l"; done |
|
for l in "${DIAG_DAEMONS[@]}"; do explain_entry system "$l"; done |
|
hdr "── 4. defaults ─────────────────────────────────────────────────────────────────" |
|
for d in "${DEFAULTS[@]}"; do explain_entry default "${d%%|*}|$(printf '%s' "$d" | cut -d'|' -f2)"; done |
|
if [[ -z $FILTER ]]; then |
|
echo; echo "── Seen by --scan, deliberately NOT touched ─────────────────────────────────────" |
|
cat <<'EOF' |
|
|
|
com.apple.siriactionsd Shortcuts runtime: runs and syncs your shortcuts and automations. Not AI. |
|
com.apple.siriappintentsd Indexes App Intents from installed apps; Spotlight actions and the Shortcuts |
|
app's action list depend on it. Disabling breaks both. |
|
com.apple.biomed / coreduetd System halves of Biome and CoreDuet; Shortcuts, Focus and Screen Time rely on them. |
|
com.apple.corespeechd.system System-session half of CoreSpeech; same Dictation / Voice Control caution as the |
|
user one, and the user one already stops voice trigger for your session. |
|
com.apple.biometrickitd Touch ID. Matched the *biome* pattern by accident — never disable. |
|
com.apple.cmio.* Core Media IO camera assistants: built-in camera (VDCAssistant), USB webcams, |
|
iPhone screen capture. Matched *assistant* — never disable. |
|
com.apple.AddressBook.AssistantService Contacts data service used by Mail, Messages and Siri. Not AI; contacts |
|
services are known to freeze the App Store when killed. |
|
com.apple.speech.* / speechmaintenanced Classic speech synthesis (VoiceOver, Spoken Content, the say command), |
|
voice and Dictation asset installers. Accessibility, not AI bloat. |
|
com.apple.unmountassistant.* The "disk in use" dialog when ejecting volumes. Matched *assistant*. |
|
EOF |
|
fi |
|
echo |
|
} |
|
|
|
DIS_GUI=""; DIS_SYS="" |
|
status_row() { # domain label |
|
local dom=$1 label=$2 present=no disabled=no running=- out target dis |
|
matches_filter "$label" || return 0 |
|
agent_exists "$label" "$dom" && present=yes |
|
if [[ $dom == gui ]]; then target="gui/$UID/$label"; dis=$DIS_GUI; else target="system/$label"; dis=$DIS_SYS; fi |
|
printf '%s\n' "$dis" | grep -qF "\"$label\" => disabled" && disabled=yes |
|
if out=$(launchctl print "$target" 2>/dev/null); then |
|
if printf '%s\n' "$out" | grep -q 'state = running'; then running=yes; else running=no; fi |
|
fi |
|
describe "$label" |
|
printf ' %-40s %-8s %-9s %-8s %s\n' "$label" "$present" "$disabled" "$running" "$D_RISK" |
|
} |
|
status() { |
|
DIS_GUI=$(launchctl print-disabled "gui/$UID" 2>/dev/null) |
|
DIS_SYS=$(launchctl print-disabled system 2>/dev/null) |
|
printf '\n %-40s %-8s %-9s %-8s %s\n' "gui/$UID" "present" "disabled" "running" "risk" |
|
local l |
|
for l in "${ALL_GUI[@]}"; do status_row gui "$l"; done |
|
printf '\n %-40s %-8s %-9s %-8s %s\n' "system" "present" "disabled" "running" "risk" |
|
for l in "${ALL_SYSTEM[@]}"; do status_row system "$l"; done |
|
echo |
|
echo " running = '-' means launchd has no such service loaded (disabled + rebooted, or not present)." |
|
echo " ./golden-gate-debloater.sh --explain <label> shows what a row does." |
|
} |
|
|
|
# Labels the scan patterns hit that are deliberately NOT in the lists (see --explain, last section). |
|
scan_excluded() { # label → true if it is a known, intentional exclusion |
|
case "$1" in |
|
com.apple.siriactionsd|com.apple.siriappintentsd|com.apple.biomed|com.apple.coreduetd|\ |
|
com.apple.corespeechd.system|com.apple.biometrickitd|com.apple.AddressBook.AssistantService|\ |
|
com.apple.speechmaintenanced|com.apple.speech.*|com.apple.cmio.*|com.apple.unmountassistant.*) return 0 ;; |
|
esac |
|
return 1 |
|
} |
|
footprint_row() { # domain label |
|
local dom=$1 label=$2 target out pid rss cpu |
|
matches_filter "$label" || return 0 |
|
if [[ $dom == gui ]]; then target="gui/$UID/$label"; else target="system/$label"; fi |
|
out=$(launchctl print "$target" 2>/dev/null) || return 0 |
|
pid=$(printf '%s\n' "$out" | sed -n 's/^[[:space:]]*pid = \([0-9][0-9]*\).*/\1/p' | head -1) |
|
[[ -n $pid ]] || return 0 |
|
read -r rss cpu <<< "$(ps -o rss=,cputime= -p "$pid" 2>/dev/null)" |
|
[[ -n ${rss:-} ]] || return 0 |
|
FP_TOTAL=$(( FP_TOTAL + rss )); FP_COUNT=$(( FP_COUNT + 1 )) |
|
printf ' %-40s %7s %8d MB %s\n' "$label" "$pid" "$(( rss / 1024 ))" "$cpu" |
|
} |
|
FP_TOTAL=0; FP_COUNT=0 |
|
footprint() { |
|
printf '\n %-40s %7s %11s %s\n' "running target" "pid" "RSS" "CPU time since start" |
|
local l |
|
for l in "${ALL_GUI[@]}"; do footprint_row gui "$l"; done |
|
for l in "${ALL_SYSTEM[@]}"; do footprint_row system "$l"; done |
|
printf ' %-40s %7s %8d MB\n' "total ($FP_COUNT processes)" "" "$(( FP_TOTAL / 1024 ))" |
|
echo |
|
echo " RSS is the idle footprint only; mlhostd grows to the size of the model when Apple Intelligence" |
|
echo " is actually used, and the indexers (spotlightknowledged, knowledgeconstructiond) run in bursts." |
|
echo " CPU time is cumulative since each process started — compare it over the same uptime before/after." |
|
} |
|
|
|
scan() { |
|
local known=" ${ALL_GUI[*]} ${ALL_SYSTEM[*]} " dir f label lw new="" excl="" |
|
for dir in /System/Library/LaunchAgents /System/Library/LaunchDaemons; do |
|
for f in "$dir"/*.plist; do |
|
[[ -f $f ]] || continue |
|
label=${f##*/}; label=${label%.plist} |
|
lw=$(lower "$label") |
|
case "$lw" in |
|
*intellig*|*generativ*|*siri*|*assistant*|*knowledge*|*model*|*campo*|*biome*|*trial*|*parsec*|*summar*|*visualint*|*mlhost*|*aiml*|*genmoji*|*writingtool*|*privatecloud*|*duet*|*proactive*|*speech*) |
|
[[ $known == *" $label "* ]] && continue |
|
if scan_excluded "$label"; then excl="$excl $f"$'\n'; else new="$new $f"$'\n'; fi ;; |
|
esac |
|
done |
|
done |
|
echo "AI-looking launchd plists on this OS that golden-gate-debloater.sh does not cover (candidates to look up):" |
|
if [[ -n $new ]]; then printf '%s' "$new"; else echo " (none — every match is either covered or a known exclusion)"; fi |
|
echo "(look each one up with 'man <name>' or a web search before adding it to the lists)" |
|
if [[ -n $excl ]]; then |
|
echo; echo "Matched the patterns but deliberately left alone (reasons: ./golden-gate-debloater.sh --explain, last section):" |
|
printf '%s' "$excl" |
|
fi |
|
} |
|
|
|
case $MODE in |
|
apply) apply ;; |
|
status) status ;; |
|
scan) scan ;; |
|
footprint) footprint ;; |
|
explain) explain ;; |
|
esac |