Schedule with launchd

Choose a LaunchAgent or LaunchDaemon

Run user automation in the user session and reserve system-wide daemons for work that genuinely needs system scope.

launchd runs jobs in two contexts. Pick the wrong one and you get confusing failures.

A LaunchAgent runs for a logged-in user. It can use that user’s files and session: the home folder, the user Keychain, the GUI.

A LaunchDaemon runs in the system context. It must not depend on a graphical session. Daemons exist for machine-wide services that run before anyone logs in, or without anyone logging in at all.

Location decides

Where you put the file decides which one you get:

~/Library/LaunchAgents/     agents for this user only
/Library/LaunchAgents/      agents for every user who logs in
/Library/LaunchDaemons/     system daemons, run as root by default

The /System/Library equivalents belong to macOS itself. Leave those alone.

Personal automation belongs in ~/Library/LaunchAgents. Sorting screenshots, tidying project folders, backing up your own data. All of it is user work on user files. Our screenshot sorter goes there.

Two domains

The two contexts also live in different launchd domains. A domain is the namespace launchd uses to track jobs. This matters for every command in the rest of this module:

launchctl print gui/$(id -u) | head    # your user's GUI domain
sudo launchctl print system | head     # the system domain

gui/501 is your user’s domain, where 501 is your user id. system is root’s. A job loaded in one is invisible in the other.

The trap

Your agent fails with a permission error. You notice that a daemon running as root would make the error disappear.

Don’t do it. Don’t turn a permission mistake into a root daemon.

That trade swaps a visible error for a job with maximum privilege. The job can’t see your login session. It has no access to your user Keychain. It may run while nobody is logged in to notice it misbehaving. And one wrong path in a root job can damage files no user-level bug could touch.

The fix for a permission error is fixing the permission. Not escalating past it.

Decide on paper

Before you write a plist, write down four things: the required user, the files it touches, whether it needs the network, and the trigger. Then choose the narrowest context that satisfies them.

If the answer involves your home directory or anything tied to your session, it’s an agent. That covers almost everything in this course, and almost everything I automate on my own Mac.

Try this for your task card: write the four lines, and confirm the answer is ~/Library/LaunchAgents. If it isn’t, ask yourself what in the task truly needs system scope.

Lesson completed