Skip to content

Latest commit

 

History

23 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PrefWatch

A macOS monitoring tool that watches preference changes in real-time and generates the exact commands to reproduce them.

Key Features

  • Reproducible commands. Every change is emitted as the exact command that recreates it: defaults/PlistBuddy, or the right built-in CLI (networksetup, scselect, scutil, systemsetup, sharing, tmutil, nvram, spctl/socketfilterfw, mdutil, bioutil, pmset, lpadmin, lpoptions, cupsctl, launchctl, kickstart, dscl), or a python3 one-liner where macOS offers no CLI at all
  • ALL mode. Watch every domain at once; no need to know which one changed
  • Contextual notes. Inline # NOTE: comments: how to apply a change, the tool when defaults can't, or why it isn't reproducible (see Scope)
  • ByHost support. Emits -currentHost for per-hardware prefs (trackpad, Bluetooth)
  • Noise filtering. 500+ rules, so only real changes surface
  • Minimal dependencies. One zsh script + Python 3

Quick Start

Run in Terminal. Output is also logged and viewable in Console.app.

# Monitor all preferences
sudo ./prefwatch.sh

# Monitor a specific domain (no sudo, lower CPU)
./prefwatch.sh com.apple.finder

# Verbose mode
sudo ./prefwatch.sh -v

# Stop it
sudo pkill -f 'prefwatch\.sh'

Usage

Option Short Description Default
[domain] -- Domain to monitor (no sudo needed) ALL (sudo)
--verbose -v Show diffs and debug info Off
--debug -- Log # FILTERED: <dom> <key> (reason) when a detected change is suppressed (answers "why didn't my change appear?") Off
--log <path> -l Custom log file path Auto
--no-system -- Exclude /Library/Preferences Include
--exclude <glob> -e Domain patterns to exclude in ALL mode; naming a domain explicitly always watches it Built-in
--hot-domains <list> -- Comma-separated domains kept permanently active for instant first-change detection (pass NONE to disable) common System Settings panels (see HOT_DOMAINS)
--mdm -- Make emitted commands fleet-deployable from a root Jamf policy: user-domain commands are prefixed with a runAsUser helper, PlistBuddy paths use $loggedInUser/$UUID (ByHost) Off
--no-console -- Don't open Console.app or stop when it closes. Run until Ctrl+C (interactive/VM testing) Off
--fs-usage -- ALL mode as root: also run the fs_usage real-time detector next to polling (Jamf $12) Off

Jamf Pro Integration

Jamf reserves $1$3 (mount point, computer name, user), so PrefWatch takes its parameters from $4 onward: $4=domain, $5=log path, $6=include system, $7=only cmds, $8=exclusions, $9=MDM output, $10=hot domains, $11=debug, $12=fs_usage. Launches Console.app for live viewing; logs to stdout + file + syslog.

Scope

PrefWatch reproduces what lands in a watched plist (defaults/PlistBuddy), plus the out-of-band settings its CLIs cover (above).

A few changes it detects but can't reduce to one built-in command. It emits an explanatory # NOTE: instead: FileVault (needs a recovery key), the battery charge limit (SMC-managed), a new user account, a Dock reorder, Media Sharing, and a privacy permission (a PPPC profile, not a command). Where an install-first helper reproduces it, the NOTE names the tool (see Third-party tools).

Everything else is invisible. No output is expected, not a bug: internal app databases (Safari, Mail, Calendar), sandboxed app prefs (App Store apps keep theirs under ~/Library/Containers), and hardware state (display & keyboard brightness, HDR).

A # NOTE: also rides on a reproduced change: how to apply it (logout/login, killall, restart a service, run as root), or a caveat on the emitted command. A positional array index or a ByHost/display UUID that won't transplant, or a pane that writes every default on first open.

Third-party tools

For settings with no built-in command, a # NOTE: names the tool. And for default apps and the wallpaper it emits the tool's command outright, with the real value:

  • utiluti. Default apps (URL schemes & file types)
  • dockutil. Dock items and order
  • desktoppr. Desktop wallpaper, and the colour behind it

Detection

  • ALL mode without sudo covers ~/Library/Preferences. Root is what adds /Library/Preferences, the sharing commands and launchd state. Full Disk Access is what names a privacy permission; without it the change is reported, not named.
  • Detection is by polling, so latency depends on when cfprefsd flushes writes to disk. Hot domains are flushed every 0.5s so changes surface in a second or two; a cold domain can take about ten seconds on its first change. Pass it via --hot-domains upfront if that matters.

Security

PrefWatch logs plist diffs to /var/log/prefwatch-v*.log and syslog. These may contain user-specific data (IDs, tokens, paths, the privacy-permission table). The log is 0600, owned by the console user. Review before sharing. Use --exclude to skip sensitive domains.

License

MIT. See LICENSE.


CHANGELOG · Issues · Discussions

About

Making macOS preference management easy for admins and tinkerers — real-time monitoring with ready-to-use commands.

Resources

Contributing

Stars

74 stars

Watchers

2 watching

Forks

Releases

Contributors

Languages