Skip to content

Instantly share code, notes, and snippets.

@masklinn
Last active December 24, 2025 22:07
Show Gist options
  • Select an option

  • Save masklinn/a532dfe55bdeab3d60ab8e46ccc38a68 to your computer and use it in GitHub Desktop.

Select an option

Save masklinn/a532dfe55bdeab3d60ab8e46ccc38a68 to your computer and use it in GitHub Desktop.
launchctl/launchd cheat sheet

I've never had great understanding of launchctl but the deprecation of the old commands with launchctl 2 (10.10) has been terrible as all resources only cover the old commands, and documentation for Apple utilities is generally disgracefully bad, with launchctl not dissembling.

Mad props to https://babodee.wordpress.com/2016/04/09/launchctl-2-0-syntax/ which contains most details

domains

Internally, launchd has several domains, but launchctl 1 would only ask for service names, inferring the domain based on context. This made for straightforward commands (once you've loaded a plist you just use the service name it specifies) but had rough edge cases or odd behaviours.

Launchctl 2 separates service names, domain targets and service targets:

  • a service target is <domain-target>/<service-name> and used to point to most services
  • a service name is what is specified in the plist file
  • a domain target is a namespace for services, each namespace has specific behaviours associated:
    • system is privileged (runs services as root) and requires root for interaction
    • user/<uid> runs as that user, but does not require that the user be logged in
    • gui/<uid> runs as that user, but is only active when the user is logged in at the GUI

important commands

bootstrap <domain-target> <paths...>

The paths can be plist files, XPC bundles, or directories of them. Each plist or bundle is loaded into the specified domain.

bootout <service-target> | <domain-target> <paths...>

Unloads the specified service(s).

WARNING

The paths are actually optional, you can unload an entire domain, which you probably should not do.

enable <service-target> | disable <service-target>

Marks the service as runnable (or not), allows overriding a Disabled plist key. Behaviour is a bit odd and I haven't looked much into it, you may need to bootstrap a service (it will complain that the service is disabled), enable it, then bootstrap it again.

kickstart <service-target>

Starts a service. -k will kill then restart existing instances.

Supposedly -p will print the service's pid (even if it's already started), doesn't seem to work for me.

print <service-target>

Dumps the service's definition, properties & metadata.

WARNING

The output of print is not officially structured, do not rely either on the format or on the information.

print <domain-target>

Prints the domain's metadata, including but not limited to all services in the domain.

kill <signame | signum> <service-target>

Sends a signal to a service's process (without having to look it up manually).

@rgaufman
Copy link

@theKosh Any, I seem to have lost the ability to launch any service in ~/Library/LaunchAgents - they all launch fine with user/501 but fail to launch with gui/501, the error I get is:

2022-12-23 12:11:07.908091 (gui/501 [100003]) <Notice>: entering bootstrap mode
2022-12-23 12:11:07.908359 (gui/501/homebrew.mxcl.memcached) <Error>: Caller specified a plist with bad ownership/permissions: path = /Volumes/Data/home/hackeron/Library/LaunchAgents/homebrew.mxcl.memcached.plist, caller = launchctl[14134]
2022-12-23 12:11:07.908376 (gui/501 [100003]) <Notice>: Bootstrap by launchctl[14134] for /Volumes/Data/home/hackeron/Library/LaunchAgents/homebrew.mxcl.memcached.plist failed (122: Path had bad ownership/permissions)
2022-12-23 12:11:07.908386 (gui/501 [100003]) <Notice>: exiting bootstrap mode

However the permissions seem fine and they launch without issues using user/501:

$ LaunchAgents  /bin/ls -ltra *.plist
-rw-r--r--@ 1 hackeron  staff   994 17 Nov 20:56 [email protected]
-rw-r--r--@ 1 hackeron  staff   743 22 Dec 20:01 homebrew.mxcl.mosquitto.plist
-rw-r--r--@ 1 hackeron  staff   986 22 Dec 20:03 homebrew.mxcl.mongodb-community.plist
-rw-r--r--@ 1 hackeron  staff   880 23 Dec 12:05 homebrew.mxcl.redis.plist
-rw-r--r--@ 1 hackeron  staff   726 23 Dec 13:11 homebrew.mxcl.memcached.plist
-rw-r--r--@ 1 hackeron  staff   929 23 Dec 13:54 [email protected]
-rw-r--r--@ 1 hackeron  staff  1329 23 Dec 14:03 actions.runner.tetherit-tetherbox.Roman-Mac-Mini-M1.plist
-rw-r--r--@ 1 hackeron  staff  1436 23 Dec 14:03 actions.runner.tetherit-tetherx-ansible.Roman-Mac-Mini-M1.plist
-rw-r--r--@ 1 hackeron  staff  1396 23 Dec 14:03 actions.runner.tetherit-tetherx.Roman-Mac-Mini-M1.plist

I recently updated to 13.1 and moved my home directory from /Users/hackeron to /Volumes/Data/home/hackeron as the internal SSD is 256GB, not sure if this is related to these changes and not quite sure what to try next. Any guesses?

@m1n9o
Copy link

m1n9o commented Jan 9, 2023

ec2-user ~ % sudo launchctl bootout system /System/Library/LaunchDaemons/com.apple.apsd.plist
/System/Library/LaunchDaemons/com.apple.apsd.plist: Operation not permitted while System Integrity Protection is engaged
Boot-out failed: 150: Operation not permitted while System Integrity Protection is engaged

Is that necessary to disable SIP first?

@ahmadelafify
Copy link

Perfect, I used this guide to help me uninstall some helpers that were lingering on my system.

sudo launchctl list
sudo launchctl bootout gui/501/application.com.macenhance.cDockHelper.25342452.25342576
sudo launchctl bootout gui/501/com.HyperartFlow.Barbee.LaunchAtLoginHelper

Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment