How to Audit and Manage launchd Daemons and User Agents in macOS Using launchctl

Every background process, recurring cron-style job, and system service in macOS is initialized and supervised by launchd, the master system bootstrap daemon (PID 1). Unlike legacy Unix init scripts or systemd, launchd manages background workloads via XML-formatted property list (.plist) files categorized into LaunchDaemons and LaunchAgents. When software uninstallation leaves orphaned daemons or misbehaving background jobs restart in tight crash loops, the modern launchctl command-line utility provides administrative control to audit and manage services.

Architectural Overview of macOS launchd Domains

Workloads in launchd are strictly separated by execution domain and privilege boundaries:

  • System LaunchDaemons (/Library/LaunchDaemons): Execute with root privileges at system startup before user login.
  • Global LaunchAgents (/Library/LaunchAgents): Execute per-user within the user GUI session context for all accounts on the Mac.
  • User LaunchAgents (~/Library/LaunchAgents): User-specific startup items belonging strictly to the logged-in user.
  • Domain Targets: Modern macOS utilizes domain specifiers such as gui/<uid> and system rather than legacy load/unload syntax.

Auditing Active Services with launchctl list and print

To inspect currently registered background workloads:

# List all running user agents in the current user session
launchctl list

# Inspect detailed telemetry for a specific service domain
launchctl print gui/$(id -u)/com.apple.Safari.History

In the launchctl list output, examine the three columns:

  • PID: Process ID if currently running (or - if idle/sleeping).
  • Status: Exit code of the last run. A non-zero number (such as 1 or negative values like -9) indicates repeated crashing.
  • Label: Unique reverse-DNS identifier for the service.

Enabling and Disabling Services Using Modern Subcommands

Apple deprecated launchctl load and unload in favor of granular bootstrap and bootout commands:

# Unload (stop) a user agent from the current user session
launchctl bootout gui/$(id -u)/com.example.maliciousagent

# Permanently disable a service from starting automatically
launchctl disable gui/$(id -u)/com.example.maliciousagent

# Load a newly created service plist into the user session
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.digitash.backup.plist

Managing Elevated System Daemons

Modifying system-level daemons requires executing launchctl with superuser privileges targeting the system domain:

# Inspect system-wide daemon status
sudo launchctl print system/com.example.daemon

# Stop and unload an orphaned system daemon
sudo launchctl bootout system /Library/LaunchDaemons/com.example.daemon.plist

Using modern launchctl commands ensures clean service termination without leaving orphaned socket bindings or memory leaks.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.