Skip to content

Instantly share code, notes, and snippets.

@vardumper
Created October 10, 2026 12:06
Show Gist options
  • Select an option

  • Save vardumper/dc4aec5e90736c7bf837b9b891769bf0 to your computer and use it in GitHub Desktop.

Select an option

Save vardumper/dc4aec5e90736c7bf837b9b891769bf0 to your computer and use it in GitHub Desktop.
macOS Golden Gate Debloater - removes Siri, AI, Telemetry features to free up resources on Macbook Neo

Golden Gate debloater: how to use

Two scripts for macOS 26 (Tahoe) or 27 (Golden Gate):

  • golden-gate-debloater.sh turns off Apple Intelligence, Siri, suggestion, and telemetry background services, and sets a few privacy defaults. It records every change it makes.
  • golden-gate-restore.sh undoes what the debloater recorded, or resets everything it knows about to macOS defaults.

Both are written for the bash 3.2 that ships with macOS.

Before you start

  1. Open System Settings → Apple Intelligence & Siri and turn both off. This is the supported switch. The script only stops the leftover background services.

  2. Run both scripts as your normal user, not with sudo. The script needs your own user ID for the per-user services. It asks for your admin password only when it needs it.

  3. Make them executable:

    chmod +x golden-gate-debloater.sh golden-gate-restore.sh

Step 1: read what it does

./golden-gate-debloater.sh --explain          # full catalogue
./golden-gate-debloater.sh --explain siri     # only entries matching "siri"

Each entry shows a risk level:

  • low: runs in the background. You lose only a feature you have already turned off or never see.
  • medium: affects something you may use daily, such as Live Text, Screen Time, crash logs, or grammar hints. Read the "Affects" line before you opt in.

There is no "high" risk. Anything related to MDM, accounts, updates, security, sync, or the App Store is never in the lists.

Step 2: preview

./golden-gate-debloater.sh --dry-run

This prints every step with its description and changes nothing.

Step 3: apply

./golden-gate-debloater.sh

The script:

  1. Shows the OS version and any MDM enrollment it finds, then asks Apply the trim now? [y/N].
  2. Asks for your admin password once, for the system-level daemons and one privacy setting. Press Ctrl-C at that prompt, or use --no-system, to skip that part.
  3. Disables the per-user agents in four groups: Apple Intelligence and Siri, suggestions and the knowledge graph, and telemetry. It then disables the system daemons.
  4. Writes the privacy defaults: Siri off, Siri opt-out of improvement data, Siri menu-bar icon hidden, Look Up suggestions off, personalized ads off, analytics sharing off, and new documents saved locally instead of iCloud.

Every change is written to a state file so the restore script can reverse it.

Options

Option Effect
--with-media-analysis Also disables mediaanalysisd and photoanalysisd. Costs Live Text, Visual Look Up, Visual Intelligence, and Photos people recognition.
--with-diagnostics Also disables crash, panic, and hang reporting. You get no crash logs afterwards.
--no-defaults Skips the privacy defaults.
--no-system Skips the system-level part (no sudo).

Options can be combined, for example ./golden-gate-debloater.sh --no-system --dry-run.

Step 4: reboot and check

Reboot, then run:

./golden-gate-debloater.sh --status

This shows, for every known label, whether it is present, whether it is disabled, whether it is running, and its risk level. Labels marked ✗ or still running after the reboot are held by Apple. Leave them alone.

Other modes

./golden-gate-debloater.sh --footprint   # memory and CPU time per running target, for before/after comparison
./golden-gate-debloater.sh --scan        # AI-looking launchd plists the lists don't cover

--footprint shows idle memory only. Models like mlhostd grow when Apple Intelligence is actually used, and indexers run in bursts. Compare CPU time over the same uptime.

--scan lists candidates to look up. It also lists known intentional exclusions, such as Shortcuts (siriactionsd), Touch ID (biometrickitd), camera assistants (com.apple.cmio.*), and VoiceOver speech (com.apple.speech.*). Do not disable those.

Undoing it: golden-gate-restore.sh

./golden-gate-restore.sh --dry-run   # preview
./golden-gate-restore.sh             # restore from the state file
./golden-gate-restore.sh --all       # ignore the state file; re-enable everything and reset defaults
  • Default mode re-enables exactly the labels the debloater recorded and sets each defaults key back to its previous value. If no state file exists, it falls back to --all.
  • --all re-enables every label the debloater knows about and deletes the defaults keys it sets. Those keys return to macOS defaults, not to the values they had before. Use this when the state file is missing or you want a clean reset.
  • After a successful restore, the state file is archived as state.restored-<timestamp>.tsv in the state directory.
  • The restore script does not touch the Apple Intelligence or Siri switches in System Settings. Turn those back on yourself if you want them.
  • Reboot afterwards. Agents reload at login and daemons at boot.

Where things are stored

File Purpose
~/Library/Application Support/golden-gate-debloater/state.tsv Record of every change, used by the restore script
…/golden-gate-debloater/last-run.log Log from the debloater
…/golden-gate-debloater/last-restore.log Log from the restore script

To use a different state directory, set GG_STATE_DIR for both scripts:

GG_STATE_DIR=/path/to/dir ./golden-gate-debloater.sh --dry-run

Things to know

  • SIP stays on. With SIP on, disabling the system daemons often succeeds only partly, and bootout usually fails. This is expected and harmless.
  • Managed Macs. If a configuration profile pins a setting, its write fails or is overridden. The script reports this with ✗, which is fine.
  • Speech-to-text and grammar. Disabling corespeechd can affect Dictation or Voice Control. If either stops responding after a reboot, re-enable that label first:
    launchctl enable gui/$(id -u)/com.apple.corespeechd
    Then log out and back in.
  • Spoken Content and VoiceOver. If you use a Siri voice for accessibility, sirittsd affects it. Pick a non-Siri voice first, or remove that label from AI_AGENTS in the script.
  • Other accounts on the Mac are not affected by the per-user (gui/) changes. System-level (system/) changes apply to the whole machine.
  • Tahoe (26). com.apple.campo does not exist there, so the script reports it as not present and skips it.
  • Keeping the scripts in sync. The label lists are duplicated in both scripts. If you edit one, edit the other.
  • Document saving. The NSDocumentSaveNewDocumentsToCloud default is a convenience setting, not an AI setting. Delete its line from DEFAULTS if you want Apple's behaviour.
#!/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
#!/bin/bash
# golden-gate-restore.sh — undo golden-gate-debloater.sh
#
# Default: re-enable exactly the labels golden-gate-debloater.sh recorded, and put every defaults key
# back to the value it had before (both from state.tsv).
# --all: ignore / no state file: re-enable every label golden-gate-debloater.sh knows about and delete
# the defaults keys it sets (= back to macOS defaults).
# --dry-run: print only.
#
# Run as your normal user, not with sudo (admin password is asked once if needed).
# Reboot afterwards. The switches you flipped in System Settings (Apple Intelligence,
# Siri) are not touched — turn them back on there if you want them.
#
# Written for the bash 3.2 that ships with macOS.
set -u
[[ -n ${BASH_VERSION:-} ]] || { echo "Please run this with bash: ./golden-gate-restore.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-restore.log"
# ─────────────────────────────────────────────────────────────────────────────
# Lists — keep in sync with golden-gate-debloater.sh (used only with --all / missing state file)
# ─────────────────────────────────────────────────────────────────────────────
ALL_GUI=(
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
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
com.apple.ap.adprivacyd com.apple.ap.promotedcontentd com.apple.tipsd com.apple.inputanalyticsd
com.apple.geoanalyticsd com.apple.UsageTrackingAgent com.apple.triald
com.apple.mediaanalysisd com.apple.photoanalysisd
com.apple.ReportCrash com.apple.ReportPanic
)
ALL_SYSTEM=(
com.apple.modelmanagerd com.apple.modelcatalogd com.apple.privatecloudcomputed
com.apple.analyticsd com.apple.audioanalyticsd com.apple.wifianalyticsd
com.apple.ecosystemanalyticsd com.apple.triald.system
com.apple.spindump com.apple.metadata.mds.spindump
)
# domain|key (deleted with --all; the value before the trim is unknown then)
ALL_DEFAULTS=(
"com.apple.assistant.support|Assistant Enabled"
"com.apple.assistant.support|Siri Data Sharing Opt-In Status"
"com.apple.Siri|StatusMenuVisible"
"com.apple.Siri|VoiceTriggerUserEnabled"
"com.apple.lookup.shared|LookupSuggestionsDisabled"
"com.apple.AdLib|allowApplePersonalizedAdvertising"
"NSGlobalDomain|NSDocumentSaveNewDocumentsToCloud"
"/Library/Application Support/CrashReporter/DiagnosticMessagesHistory|AutoSubmit"
"/Library/Application Support/CrashReporter/DiagnosticMessagesHistory|ThirdPartyDataSubmit"
)
# ─────────────────────────────────────────────────────────────────────────────
DRY_RUN=0; USE_ALL=0
for arg in "$@"; do
case "$arg" in
--dry-run) DRY_RUN=1 ;;
--all) USE_ALL=1 ;;
-h|--help) sed -n '2,14p' "$0"; exit 0 ;;
*) echo "unknown option: $arg (try --help)"; exit 2 ;;
esac
done
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; "$@"; }
runq() { if (( DRY_RUN )); then say " DRY: $*"; return 0; fi; "$@" >/dev/null 2>&1; }
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() {
if (( DRY_RUN )); then SUDO_OK=1; return 0; fi
say "Admin password needed once for the system/ daemons and the analytics-sharing plist:"
if sudo -v; then SUDO_OK=1; start_sudo_keepalive; else say "no admin rights — system-level entries skipped"; fi
}
enable_label() { # domain label
local dom=$1 label=$2 target plist S=""
if [[ $dom == gui ]]; then
target="gui/$UID/$label"; plist="/System/Library/LaunchAgents/$label.plist"
else
target="system/$label"; plist="/System/Library/LaunchDaemons/$label.plist"; S=sudo
(( SUDO_OK )) || { say " · $label — skipped (no sudo)"; return 0; }
fi
if [[ ! -f $plist ]] && ! launchctl print "$target" >/dev/null 2>&1; then
# not on this OS — still clear a stale override, quietly
runq $S launchctl enable "$target"; say " · $label — not present on this system, override cleared"; return 0
fi
if run $S launchctl enable "$target"; then
say " ✓ $label — enabled"
else
say " ✗ $label — launchctl enable refused"
fi
[[ -f $plist ]] && runq $S launchctl bootstrap "${target%/*}" "$plist" || true # load now if possible; else next login/boot
}
restore_default() { # domain key type prev
local dom=$1 key=$2 type=$3 prev=$4 S=""
case $dom in
/*) (( SUDO_OK )) || { say " · $dom :: $key — skipped (no sudo)"; return 0; }; S=sudo ;;
esac
if [[ $prev == __absent__ ]]; then
if runq $S defaults delete "$dom" "$key"; then
say " ✓ $dom :: $key — removed (was not set before the trim)"
else
say " · $dom :: $key — already absent"
fi
else
if [[ $type == bool ]]; then
case $prev in 1|true|TRUE|yes|YES) prev=true ;; 0|false|FALSE|no|NO) prev=false ;; esac
fi
if runq $S defaults write "$dom" "$key" "-$type" "$prev"; then
say " ✓ $dom :: $key = $prev"
else
say " ✗ $dom :: $key — write failed (locked by a configuration profile?)"
fi
fi
}
delete_default() { # "domain|key"
local dom key S=""
IFS='|' read -r dom key <<< "$1"
case $dom in /*) (( SUDO_OK )) || { say " · $dom :: $key — skipped (no sudo)"; return 0; }; S=sudo ;; esac
if runq $S defaults delete "$dom" "$key"; then say " ✓ $dom :: $key — removed"; else say " · $dom :: $key — already absent"; fi
}
# ─────────────────────────────────────────────────────────────────────────────
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
say "golden-gate-restore · $(date)"
(( DRY_RUN )) && say "(dry run — nothing will be changed)"
if (( ! USE_ALL )) && [[ ! -s $STATE_FILE ]]; then
say "No state file at $STATE_FILE — falling back to --all (re-enable everything golden-gate-debloater.sh knows)."
USE_ALL=1
fi
if (( USE_ALL )); then
say "Mode: --all"
want_sudo
say ""; say "== re-enabling launchd labels"
for l in "${ALL_GUI[@]}"; do enable_label gui "$l"; done
for l in "${ALL_SYSTEM[@]}"; do enable_label system "$l"; done
say ""; say "== removing defaults keys (back to macOS defaults)"
for d in "${ALL_DEFAULTS[@]}"; do delete_default "$d"; done
else
say "Mode: from state file $STATE_FILE"
if grep -q $'^agent\tsystem\t' "$STATE_FILE" || grep -q $'^default\t/' "$STATE_FILE"; then
want_sudo
fi
say ""; say "== restoring recorded changes"
# fd 3 so that sudo / launchctl cannot swallow the file from stdin
while IFS=$'\t' read -r kind f1 f2 f3 f4 <&3; do
case "$kind" in
agent) enable_label "$f1" "$f2" ;;
default) restore_default "$f1" "$f2" "$f3" "$f4" ;;
''|'#'*) ;;
*) say " ? unknown state line: $kind" ;;
esac
done 3< "$STATE_FILE"
if (( ! DRY_RUN )); then
mv "$STATE_FILE" "$STATE_DIR/state.restored-$(date +%Y%m%d-%H%M%S).tsv"
say ""; say "State file archived in $STATE_DIR"
fi
fi
say ""
say "Done. Reboot to bring everything back (agents re-load at login, daemons at boot)."
say "Apple Intelligence / Siri themselves: System Settings → Apple Intelligence & Siri."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment