Create launchd plists in seconds, not minutes. No more copy-pasting boilerplate XML or hunting through Apple's Programming Guide for the right key.
Why mklaunchd?
Writing launchd plists by hand is tedious. You have to remember which keys go where, which scope your plist belongs in, what casing the values take, and how to escape your ProgramArguments array. One typo and your agent silently fails to load.
mklaunchd handles the boilerplate so you can focus on what matters: the command you want macOS to run. It writes the plist, places it in the correct directory, and loads it with launchctl in a single step.
Agents and Daemons
Create LaunchAgents (per-user) or LaunchDaemons (system-wide) with the right scope, paths, and load semantics. mklaunchd knows where each one belongs.
Schedules and Watchers
StartInterval for periodic runs, StartCalendarInterval for cron-like schedules, WatchPaths to trigger on filesystem changes. One flag each.
Built-in Validation
Catches missing executables, conflicting Label values, and the common plist mistakes that result in jobs that load silently and never run.
Load, Unload, Inspect
Wrap launchctl bootstrap, bootout, print, and the log files behind a single coherent CLI. No more guessing which command applies in your macOS version.
Install
Install via Homebrew:
brew install uRadical/tap/mklaunchd
Or download a pre-built binary from the releases page.
Quick Start
Create a per-user agent that runs a script on login:
Plist Types
mklaunchd supports the two scopes launchd actually uses, plus the trigger patterns that make them useful:
LaunchAgents
Per-user services that run when the user is logged in:
mklaunchd agent --label io.uradical.myapp --exec /usr/local/bin/myapp \
--keep-alive --run-at-load --install
LaunchDaemons
System-wide services that run regardless of login:
sudo mklaunchd daemon --label io.uradical.myservice \
--exec /usr/local/sbin/myservice --user _myservice --install
Scheduled Jobs
Cron-style scheduling with StartCalendarInterval, or periodic runs with StartInterval:
mklaunchd agent --label io.uradical.backup \
--exec /usr/local/bin/backup.sh --calendar "daily" --install
Path Watchers
Trigger when files change — the launchd equivalent of inotify:
mklaunchd agent --label io.uradical.deploy \
--exec /usr/local/bin/process-upload.sh \
--watch ~/Dropbox/uploads --install
Commands
agentCreate a LaunchAgentdaemonCreate a LaunchDaemonstatusCheck job statuslogsTail job logsprintShow launchctl print outputeditEdit an installed plistloadBootstrap a plistunloadBootout a pliststart/stopKickstart or stop a joblistList installed jobsuninstallRemove a plistdoctorDiagnose common issuesStandard Output and Logs
Tell launchd where to write stdout and stderr without remembering the keys:
mklaunchd agent --label io.uradical.myapp --exec /usr/local/bin/myapp \
--stdout ~/Library/Logs/myapp.out.log \
--stderr ~/Library/Logs/myapp.err.log --install
Or just tail what's already there:
mklaunchd logs io.uradical.myapp
Doctor
The most common launchd problems are silent: a typo'd Label, a non-executable path, a plist in the wrong directory, an environment variable that didn't propagate. mklaunchd doctor walks the installed jobs and flags the ones that look broken before you spend an evening figuring out why nothing's running.
mklaunchd doctor
Learn More
For full documentation, examples, and advanced usage, visit mklaunchd.sh. The companion book launchd Pocket Reference covers the underlying mechanics if you want to know what mklaunchd is doing under the hood.
mklaunchd is open source and MIT licensed. Contributions welcome on GitHub.