Schedule with launchd
Load, test, and remove the job
Validate a LaunchAgent, start it in the user domain, inspect state and logs, then remove it cleanly.
The plist exists and the environment is pinned down. Now we hand the job to launchd, watch it run, and take it back out. Removal is part of the lesson, not an afterthought.
Validate the property list one more time:
plutil -lint ~/Library/LaunchAgents/com.flaviocopes.screenshot-sorter.plist
# OK
Load, run, inspect
Three commands. bootstrap loads the job into your user’s GUI domain. kickstart forces an immediate run. print shows you its state:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.flaviocopes.screenshot-sorter.plist
launchctl kickstart -k gui/$(id -u)/com.flaviocopes.screenshot-sorter
launchctl print gui/$(id -u)/com.flaviocopes.screenshot-sorter
kickstart -k runs the job now instead of waiting up to fifteen minutes for StartInterval. It makes testing bearable.
The print output is dense. Three parts matter: the state, the last exit code, and the program it resolved. For a quicker glance:
launchctl list | grep screenshot
# - 0 com.flaviocopes.screenshot-sorter
The first column is the PID, or - when idle. The second is the last exit status. Zero is what you want.
Then confirm the job did its actual work. Check the log files from the previous lesson and the destination folder. A zero exit code with an empty destination means the script ran and did nothing, which is its own bug.
When bootstrap fails
If bootstrap answers Bootstrap failed: 5: Input/output error, one of two things is true. The job is already loaded, so boot it out first. Or the plist has a problem plutil can’t see, like a program path that isn’t executable. Check ls -l on the script and look for the x.
Old tutorials
You’ll find launchctl load and launchctl unload in most blog posts. They still work, but they’re the legacy interface. bootstrap and bootout are what the current man launchctl documents. When in doubt, trust the man page on your machine over a blog post, including this one.
Remove it
Removal is bootout:
launchctl bootout gui/$(id -u)/com.flaviocopes.screenshot-sorter
Write the exact removal step in your runbook now, while it’s fresh. After removal, confirm the label no longer appears in launchctl list and the process has stopped.
Keep the plist file until the uninstall check passes. If removal reveals a problem, you can reload and retest without rewriting anything.
Try this: load your job, kickstart it, read the log, then boot it out and confirm it’s gone from launchctl list. Do the full cycle once before you trust the schedule.
Lesson completed