launchd
runs Daemons (/Library/LaunchDaemons
or /System/Library/LaunchDaemons
) as root, and will run them regardless of whether users are logged in or not. Launch Agents (/Library/LaunchAgents/
or ~/Library/LaunchAgents/
) are run when a user is logged in as that user. You can not use setuid to change the user running the script on daemons. The /System
directory is reserved for Mac OS X tasks so I recommend putting your launchd
plists into either the /Library
or the ~/Library
folder as it makes sense.
So the first step is determining if you're making an agent or a daemon.
The second step is to make your .plist
file. You can use GUI-based programs such as Lingon to help with this or just use your favourite text editor:
A sample .plist
for running a script every hour (StartInterval
or StartIntervalCalendar
are the keys we want - StartInterval
for an item to happen every x
seconds, StartIntervalCalendar
for a specific time and/or date. See 126907 on SuperUser for an example I made with StartCalendarInterval):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>local.IDENTIFIER_HERE.SOMETHING</string>
<key>OnDemand</key>
<true/>
<key>RunAtLoad</key>
<false/>
<key>UserName</key>
<string>USERNAME HERE</string>
<key>Program</key>
<string>/PATH/TO/SCRIPT</string>
<key>ProgramArguments</key>
<array>
<string>Argument_1</string>
<string>Argument_2</string>
</array>
<key>StartInterval</key>
<integer>3600</integer>
</dict>
</plist>
Modify the .plist
as necessary to point to your script and any arguments as necessary (arguments are on separate lines) and save the file with the same name as the Label value but with .plist
at the end. (for example, local.my-mac.flickrstats
would be saved as local.my-mac.flickrstats.plist
). If you haven't already, move that .plist
file to /Library/LaunchDaemons
when making a Daemon (runs all the time) or to ~/Library/LaunchAgents
(only you're logged in) or /Library/LaunchAgents
(any user is logged in).
To start the job you want to run launchctl
as necessary to load the file. For items in /Library
, you should use sudo: for example, sudo launchctl load -w /PATH/TO/PLIST
For reference also check out the following questions on Super User: Launchd command as root, Load a system wide daemon, and How can I get a script to run every day
Try moving the plist to /Library/LaunchDaemons/. Agents (other than pre-login agents) are run only after a user logs in and they are owned by the user. Also the UserName key has no effect for agents.
See the Daemons and Agents tech note.
Best Answer
Spotify uses a so-called Modern Login Item (in contrary to the deprecated Login Item).
The Modern Login Item doesn't require a classical daemon|agent.plist or a Login Item in System Preferences > Users & Groups > $USER.
Apple dev guidelines require the apps using such modern login items to provide a setting in the preferences of the app itself to disable autostart though.
AFAIU the autostart is managed with a separate autostart app in the app itself and Apple's ServiceManagement.framework. In Spotify the app is: /Applications/Spotify.app/Contents/Library/LoginItems/StartUpHelper.app
Further reading and an example app with source code (compiling requires Xcode): Modern Login Item