An always-on macOS daemon that keeps Adobe Creative Cloud background components disabled — and keeps them disabled, even after Adobe updates silently re-enable them.
📖 New here? Start with the User Guide — install, daily use, Touch ID setup, whitelist, and troubleshooting in one place.
Adobe Toggle Manager blocks Adobe Creative Cloud background processes, LaunchAgents/LaunchDaemons, and Finder/QuickLook plugin extensions, and holds them blocked. A lightweight terminal UI lets you flip between Block, Lean, and Allow at any time. Your choice persists across reboot and logout.
Installing a single Adobe app drags in a swarm of always-running helpers: Creative Cloud daemons, the CCXProcess background agent, Core Sync, Adobe crash/telemetry reporters, and Finder/QuickLook plugin extensions. They launch at login, consume RAM and CPU, and phone home — whether or not you have any Adobe app open.
Disabling them by hand does not stick. Adobe ships its components as LaunchAgents that auto-restart, and every Adobe update happily re-enables what you turned off. Manually fighting this is whack-a-mole.
Adobe Toggle Manager solves it at the root:
- It discovers Adobe components dynamically by verifying each binary's
code-signing authority (
Developer ID Application: Adobe Inc./Adobe Systems Incorporated) — there is no brittle hard-coded name list to maintain, so it survives Adobe renaming or adding components. - It blocks them with
launchctl disable(for launchd jobs) andpluginkit -e ignore(for plugin extensions) — disabling auto-start at the source, not just killing a running process. - A background daemon re-applies the block whenever Adobe drifts back, with sub-second latency when the optional FSEvents watcher is active.
- Block — stops all running Adobe processes, disables all Adobe LaunchAgents and pluginkit extensions, and prevents new auto-starts.
- Lean — stops only curated Adobe bloat (background helpers such as CCXProcess, Core Sync, crash/telemetry reporters, and the auto-updater) while keeping the essentials a licensed app needs to launch and stay licensed. A middle ground between Block and Allow, aimed at paying users who want a fast, quiet Adobe without the always-on swarm. Conservative by design: only curated components are stopped, so unknown/new components keep running and a licensed app never breaks.
- Allow — re-enables previously disabled components; optional auto-start for Creative Cloud.
- Granular whitelist — a key in the TUI opens an
fzfmulti-select picker; whitelisted components stay permanently allowed even while the global state isblock. The whitelist persists across reboot. - Self-healing health probe — a
healthsubcommand plus a second LaunchAgent checks the daemon every few minutes and restarts it vialaunchctl kickstartif it is unhealthy. - JSON output —
status,discovery, andsummaryaccept--jsonfor monitoring integrations, with zero runtime dependencies (a pure-zsh encoder, nojq/pythonrequired). - NDJSON logging —
jq-pipeable structured log lines for queries. - Dynamic discovery — code-signing-authority matching instead of a static pattern list, robust against Adobe updates.
- Pluggable backends — discovery backends are swappable zsh modules
under
lib/backends/(today:launchdandpluginkit); new macOS subsystems can be added without touching the core. - FSEvents-driven — a small native Swift helper signals the daemon on file events, cutting drift-detection latency below one second; idle CPU is effectively zero. A 30-second polling fallback runs if the helper is not built.
- State-persistent — your last choice wins, even after reboot.
- Hardened —
0600state files, TOCTOU-resistant authority caching, strict label validation, a fixedPATH, and Touch ID for the optional privileged sweep. See SECURITY.md.
- macOS 14 (Sonoma) or newer.
- zsh — the system default shell on macOS.
- Xcode Command Line Tools (optional, recommended). Used only to
compile/run the FSEvents watcher for sub-second drift detection. Without
them, the daemon falls back to 30-second polling. Install once with
xcode-select --install. fzf(optional). Required only for the interactive whitelist picker. Install withbrew install fzf.- No paid Apple Developer account is required.
git clone https://github.com/bigas-ch/adobe-toggle-manager.git
cd adobe-toggle-manager
./install.shDownload the latest release tarball from the Releases page, then:
tar -xzf adobe-toggle-manager-*.tar.gz
cd adobe-toggle-manager-*
./install.shThe installer compiles the Swift FSEvents helper automatically if the Xcode Command Line Tools are present. The daemon runs correctly without it (30-second polling fallback).
It also creates a double-clickable Adobe Toggle.app in your Applications
folder (falling back to ~/Applications if the system folder is not writable)
that opens the TUI in Terminal — so you can launch the UI without the command
line. The uninstaller removes it.
The default state after install is block. To install without blocking
Adobe immediately:
ATM_INITIAL_STATE=allow ./install.sh./adobe-toggle # open the TUI (default)
./adobe-toggle status # state + daemon health (single line)
./adobe-toggle status --json # structured view for monitoring
./adobe-toggle discovery # dump discovered components (TSV)
./adobe-toggle discovery --json # discovered components as a JSON array
./adobe-toggle summary # aggregated view (events + state + disabled)
./adobe-toggle summary --json # same view, structured
./adobe-toggle health # health probe: exit 0 healthy, 1 unhealthy
./adobe-toggle config show
./adobe-toggle config set tick-interval 60
./adobe-toggle config set safety-tick-interval 300
./adobe-toggle config set notifications off
./adobe-toggle config set auto-start-cc true
./adobe-toggle config set adaptive-interval true # opt-in: trades drift latency for less CPU (default off)
./adobe-toggle --version
./adobe-toggle --help--daemon and --healthcheck are invoked by the installed LaunchAgents
and are not meant to be run by hand.
[a] Allow [b] Block [l] Lean [d] Discovery [s] Stats [u] Sudo-Sweep [e] Sudo-Unsweep [w] Whitelist [q] Exit
Actions apply immediately — the menu never blocks; a short status line confirms each action while you keep pressing keys.
[b]Block /[a]Allow flip the global state. When there is system-scope work that needs elevation, the matching sudo sweep (after Block) or un-sweep (after Allow) runs automatically right after the toggle — a single Touch ID prompt, and only when something actually needs it. Turn this off withconfig set auto-sudo-sweep false.[l]Lean sets the global state tolean: the daemon disables only curated Adobe bloat and re-enables everything else, so apps still launch and stay licensed. Whitelisted (user_allowed) components are always spared, and a component you explicitly blocked stays off. System-scope bloat is left to the explicit[u]sweep (no auto-chain in lean).[d]Discovery shows every Adobe component the daemon currently sees, grouped into LaunchAgents/Daemons and processes and tagged 🅑 bloat / 🅔 essential, so you can see exactly whatleanwould stop vs keep. Press ENTER to return.[u]Sudo-Sweep manually (re-)runs the system-scope LaunchDaemon sweep — the fallback when auto-sweep is disabled, or to run it again (authenticated with Touch ID — see Troubleshooting).[e]Sudo-Unsweep manually re-enables those system-scope LaunchDaemons (also Touch ID-authenticated).[w]Whitelist opens anfzfmulti-select picker. TAB selects, ENTER toggles the selection between whitelisted (always allowed) and auto-blocked. Whitelisted components are never blocked, even when the global state isblock. Requiresfzf.
Three subcommands accept --json for structured output with no external
dependencies:
$ ./adobe-toggle status --json
{"label":"com.user.adobe-toggle.daemon","state":"block","daemon":{"pid":49033,"ticks":1234,"heartbeat_age_s":42,"tick_interval_s":30,"safety_tick_interval_s":300,"healthy":true,"healthy_reason":"ok"},"backends":{"available":true}}A daemon is healthy when its PID is alive and its heartbeat age is
under twice the safety-tick interval. When unhealthy, healthy_reason
gives the cause (no-pid, pid-not-alive, no-heartbeat,
heartbeat-stale).
./uninstall.shThe uninstaller:
- Re-enables every Adobe component it had disabled (Adobe is fully restored), then
- removes both LaunchAgents — the daemon job
(
com.user.adobe-toggle.daemon) and the healthcheck job (com.user.adobe-toggle.healthcheck) — and the runtime files.
Preview exactly what it would do, without changing anything:
ATM_UNINSTALL_DRY_RUN=1 ./uninstall.shOther environment toggles:
ATM_UNINSTALL_FORCE=1— skip confirmation prompts.ATM_UNINSTALL_SKIP_RELEASE=1— remove the tool without re-enabling Adobe first.ATM_UNINSTALL_BACKUP_LOGS=yes|no|<path>— control whether logs are backed up before removal.
- Touch ID prompt during a Sudo-Sweep. System-scope Adobe
LaunchDaemons live under
/Library/LaunchDaemonsand require elevation. The TUI[u]Sudo-Sweep authenticates with Touch ID (viapam_tid.so) rather than asking for a password. Approve the Touch ID prompt to let the sweep disable system-scope components. The background daemon skips these and logs them; nothing else needs elevation. - macOS notification permission prompt. On first run the tool may ask
for permission to post notifications. Allow it for block/allow feedback,
or turn notifications off entirely:
./adobe-toggle config set notifications off. - Where are the logs? Structured NDJSON logs live in
~/Library/Application Support/AdobeToggleManager/logs. Tail the daemon log or pipe it throughjqto debug discovery and block actions. - Drift detection feels slow (~30s). The FSEvents watcher is not
running. Install the Xcode Command Line Tools
(
xcode-select --install) and re-run the installer to build it; this drops latency below one second. - The whitelist key does nothing. Install
fzf(brew install fzf).
| Component | File / path |
|---|---|
| Core | adobe-toggle |
| Installer | install.sh |
| Uninstaller | uninstall.sh |
| Backend: launchd | lib/backends/launchd.zsh |
| Backend: pluginkit | lib/backends/pluginkit.zsh |
| Backend interface spec | lib/backends/_interface.zsh |
| FSEvents helper (source) | swift/atm-watcher.swift |
| Whitelist manager | lib/whitelist.zsh |
| JSON encoder | lib/json.zsh |
| Tests | tests/*.bats |
| Runtime path | ~/Library/Application Support/AdobeToggleManager/ |
| Daemon LaunchAgent | ~/Library/LaunchAgents/com.user.adobe-toggle.daemon.plist |
| Healthcheck LaunchAgent | ~/Library/LaunchAgents/com.user.adobe-toggle.healthcheck.plist |
New macOS subsystems are added as a zsh file under lib/backends/ — see
lib/backends/_interface.zsh for the backend contract.
brew install bats-core
bats tests/See CONTRIBUTING.md for the full developer workflow.
This project follows Semantic Versioning 2.0.0. The public API — the surface that version numbers make promises about — is:
- the command-line interface: subcommands (
status,discovery,summary,health,config) and flags (--tui,--daemon,--json,--version); - the
configkeys and their accepted value domains; - process exit codes;
- the
--jsonoutput schema ofstatus,discovery, andsummary, including the global state value domain (block,lean,allow).
Internal library modules (lib/), log formats, on-disk state files, and TUI key
bindings are not part of the public API and may change in any release.
1.0.0 is the first public release; the tool matured internally through a 4.x
series that was never published (see CHANGELOG.md).
See SECURITY.md for the threat model, the deliberate trade-offs, and how to report a vulnerability.
MIT — see LICENSE.
Adobe Toggle Manager is an independent, unofficial tool. It is not affiliated with, endorsed by, or sponsored by Adobe Inc. "Adobe", "Creative Cloud", and related names are trademarks of Adobe Inc., used here only to describe the components this tool manages. See TRADEMARKS.md.