docs/bootstrap/launchd.md
mise can declare macOS user LaunchAgents in
[bootstrap.macos.launchd.agents] and apply them with
mise bootstrap macos launchd-agents apply or as part of
mise bootstrap:
Run this as the user who owns the agent in a macOS session with a GUI launchd
domain. Create the executable and any log directories before applying it.
The example's my-sync is a placeholder for your own program:
[bootstrap.macos.launchd.agents.my-sync]
program = "~/.local/bin/my-sync"
args = ["--watch"]
run_at_load = true
environment = { PATH = "/opt/homebrew/bin:/usr/bin:/bin" }
working_directory = "~"
stdout_path = "~/Library/Logs/my-sync.log"
stderr_path = "~/Library/Logs/my-sync.err.log"
Each agent is written to ~/Library/LaunchAgents/dev.mise.<name>.plist and
loaded with launchctl bootstrap gui/$UID ~/Library/LaunchAgents/dev.mise.<name>.plist. Agent names may contain letters,
numbers, ., _, and -. mise owns only the plist files it creates with the
dev.mise. label prefix.
The agent receives launchd's environment, not your interactive shell's
activation. Use explicit executable paths and declare required environment
variables. program and args form an argument vector; shell expressions such
as pipes and redirections need an explicitly invoked shell or a wrapper script.
| TOML key | launchd key |
|---|---|
program | ProgramArguments[0] |
args | ProgramArguments[1..] |
run_at_load | RunAtLoad |
keep_alive | KeepAlive |
keep_alive_on_failure | KeepAlive = { SuccessfulExit = false } |
start_interval | StartInterval |
throttle_interval | ThrottleInterval |
start_calendar_interval | StartCalendarInterval |
queue_directories | QueueDirectories |
environment | EnvironmentVariables |
working_directory | WorkingDirectory |
stdout_path | StandardOutPath |
stderr_path | StandardErrorPath |
keep_alive and keep_alive_on_failure are mutually exclusive. Set only one:
the former keeps the process running after any exit, while the latter restarts
it only after a failure.
| kickstart | run launchctl kickstart |
program, working_directory, stdout_path, stderr_path, and each entry in
queue_directories expand bare ~ and ~/ to the current user's home
directory before writing the plist. args are passed through exactly as
written.
start_calendar_interval accepts minute (0-59), hour (0-23), day
(1-31), weekday (0-7), and month (1-12), and writes the corresponding
launchd calendar keys. For multiple independent calendar schedules, use an
array of inline tables:
[bootstrap.macos.launchd.agents.daily-sync]
program = "~/.local/bin/my-sync"
start_calendar_interval = [{ hour = 3 }, { hour = 12, weekday = 1 }]
start_interval and start_calendar_interval are independent launchd
triggers. If both are set, launchd can start the agent from either schedule.
throttle_interval is the minimum number of seconds launchd waits between
runs of the agent (launchd's default is 10).
queue_directories starts the agent whenever any of the listed directories is
non-empty; launchd expects the agent to drain them. launchd requires absolute
paths here, so each entry must start with /, or be ~ or a ~/ path that
expands to one.
mise bootstrap macos launchd-agents status lists entries as skipped and
mise bootstrap macos launchd-agents apply ignores them.mise bootstrap macos launchd-agents apply and mise bootstrap do.~/Library/LaunchAgents. System
daemons in /Library/LaunchDaemons are not supported.mise bootstrap macos launchd-agents status # shows LaunchAgent state
mise bootstrap macos launchd-agents status --json # machine-readable
mise bootstrap macos launchd-agents status --missing # exit 1 if any agent is missing, changed, or unloaded
mise bootstrap macos launchd-agents apply # write and load missing/changed agents
mise bootstrap macos launchd-agents apply --dry-run # print the commands without running them
mise bootstrap macos launchd-agents apply --yes # skip the confirmation prompt
status reports each agent as loaded, unloaded, differs, or missing.
apply rewrites changed plists, unloads the old job if present, loads the new
job, enables it, and runs kickstart only when kickstart = true.