macOS has several systems for running software automatically, of which three are accessible outside other apps and therefore suitable for running scripts of different kinds. Although long since deprecated, the standard Unix scheduler cron
is still available if you really must. LaunchServices also offers Login Items, but those are only launched once, when your Mac starts up. For general purposes, including running tasks which must occur at regular intervals, the primary mechanism is launchd
, with its control tool launchctl
.
launchd
Mac OS X 10.4 brought together the functions of a disparate group of Unix tools, including (x)inetd
, init
, and watchdogd
, into a single service manager launchd
, which is controlled by launchctl
. During startup, once the kernel is running and required kernel extensions have been loaded, launchd
is run with the process ID of 1, and it remains running until your Mac shuts down again.
Before you log in, launchd
runs services and other components which are specified in Property List files in the LaunchAgents and LaunchDaemons folders in /System/Library, then in /Library. Those in /System/Library are all part of macOS, owned by Apple, and now (macOS 11 and later) can’t be modified without unsealing the system, but those in /Library include many installed by third party products. As they’re run before the user logs in, they work for all users, so provide global services.
Once you have logged in, launchd
runs any services and other components specified in any LaunchAgent folder in ~/Library. Those are user-specific.
Launchd
is best suited to background services, which use it the most. You don’t need any tools beyond a Property List or text editor to craft its configuration files, although Peter Borg’s Lingon and Soma-zone’s LaunchControl make them much more accessible. It’s also widely abused by malware, which often installs its own LaunchAgents and LaunchDaemons to ensure its persistence across reboots, and to perform services which it requires.
Uninstalling a LaunchAgent or LaunchDaemon is simply a matter of trashing its Property List from the appropriate folder – a task sometimes necessary when you’ve uninstalled an app which doesn’t clean up properly after itself. If software does need to install one or more Property Lists in any of these folders, then it should also provide an effective uninstaller to remove them when required.
LaunchAgent or LaunchDaemon?
Apple defines a LaunchDaemon as a general background service, without any form of GUI. Specifically, LaunchDaemons are not allowed to connect to the macOS window server. LaunchAgents do have access to the GUI, and to other system features such as locating the current user’s Home folder, but generally have more limited interfaces than do regular apps.
Property lists
These Property List files contain keyed settings which determine what launchd
does with what. In Lingon and LaunchControl, these are presented in more understandable ways which should help you set them correctly. For example, the following property list, viewed in LaunchControl, runs my command tool blowhole
at startup and again every 3600 seconds, or one hour.
This equates to a property list containing just the following dictionary
<dict>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/sbin</string>
</dict>
<key>Label</key>
<string>co.eclecticlight.blowhole</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/blowhole</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>3600</integer>
</dict>
For tasks running at regular intervals, the most important keys are:
- ProgramArguments, which tells
launchd
what to run; - RunAtLoad, which determines whether it is run whenever your Mac starts up;
- StartInterval, which sets the time interval between launches.
To run a GUI app as a LaunchAgent, set the ProgramArguments to the executable binary of the app, in its Contents/MacOS folder.
If you prefer, you can use the launchctl
command tool to dynamically configure LaunchDaemons and LaunchAgents, but Apple has been progressively limiting its capabilities, and now you’re generally better off using a property list, which is also less prone to error.
So long as you’re working with a small number of daemons/agents, launchd
isn’t that complex, and certainly not difficult to use. It can get messier when you need to know about other tasks. One example of this is when your Mac starts crashing or freezing at 0200 every morning, but the logs provide insufficient information to identify what has caused the problem.
Further information
Apple’s documentation on launchd
is very old now, but is still a valuable reference, as is TN2083.
launchd, launchctl, cron,
and crontabs
are fully documented in their man
files. The best overall guide to launchd
is Soma-zone’s launchd.info, which explains how to make your own property list files and much more.
Lingon and LaunchControl are inexpensive, and worth every penny even if you only use them infrequently.