← All Tools

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:

mklaunchd
# Create a LaunchAgent
mklaunchd agent --label io.uradical.myapp --exec /usr/local/bin/myapp
 
# Install and load it now
mklaunchd agent --label io.uradical.myapp --exec /usr/local/bin/myapp --install
 
# Check status
mklaunchd status io.uradical.myapp

Plist Types

mklaunchd supports the two scopes launchd actually uses, plus the trigger patterns that make them useful:

agent daemon interval calendar watch keep-alive

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

mklaunchd commands
agentCreate a LaunchAgent
daemonCreate a LaunchDaemon
statusCheck job status
logsTail job logs
printShow launchctl print output
editEdit an installed plist
loadBootstrap a plist
unloadBootout a plist
start/stopKickstart or stop a job
listList installed jobs
uninstallRemove a plist
doctorDiagnose common issues

Standard 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.