| name | macos-launchd-agents |
| description | Use when inspecting, disabling, unloading, re-enabling, or safely removing macOS app-installed launchd jobs, LaunchDaemons, LaunchAgents, plist startup items, login/background agents, or privileged helpers under /Library/PrivilegedHelperTools. Trigger when the user mentions launchctl, plist agents, app helpers, background items, "disable this agent", "unload daemon", or paths under /Library/LaunchDaemons, /Library/LaunchAgents, ~/Library/LaunchAgents, or /Library/PrivilegedHelperTools. |
macOS Launchd Agents
Overview
Use this skill for macOS app-installed launchd jobs: LaunchDaemons, LaunchAgents, and privileged helper tools. Prefer launchd state changes over deleting files first; disabling and unloading are reversible and easier to verify.
Quick Start
Use the helper script from this skill directory:
python3 scripts/launchd_agent.py search CleanMyMac
python3 scripts/launchd_agent.py inspect com.macpaw.CleanMyMac5.Agent
python3 scripts/launchd_agent.py disable /Library/LaunchDaemons/com.macpaw.CleanMyMac5.Agent.plist --confirm --admin-prompt
python3 scripts/launchd_agent.py verify com.macpaw.CleanMyMac5.Agent --domain system
If the script is not enough, run the equivalent launchctl commands directly and report exact results to the user.
Workflow
-
Identify the target.
- The user may provide a label, plist path, process name, or helper path.
- Search these locations first:
/Library/LaunchDaemons, /Library/LaunchAgents, ~/Library/LaunchAgents, and /Library/PrivilegedHelperTools.
- Read the plist with
plutil -p or the helper script. Confirm Label, Program, ProgramArguments, MachServices, KeepAlive, and RunAtLoad.
-
Determine the launchd domain.
/Library/LaunchDaemons/*.plist normally uses system.
~/Library/LaunchAgents/*.plist normally uses gui/$(id -u).
/Library/LaunchAgents/*.plist is a global agent definition usually loaded into a user GUI domain.
- For uncertain cases, inspect
system/<label>, gui/$(id -u)/<label>, and user/$(id -u)/<label>.
-
Inspect current state before changing it.
launchctl print system/<label>
launchctl print gui/$(id -u)/<label>
launchctl print-disabled system | rg '<label>|macpaw|vendor'
ps -axo pid=,args= | rg '[l]abel-or-program-name'
It is normal for launchctl print to fail with "Could not find service" after a job has been booted out.
- Disable and unload.
For a system LaunchDaemon, use an administrator prompt because non-interactive sudo usually cannot ask for a password:
osascript -e 'do shell script "launchctl disable system/com.example.Agent; launchctl bootout system /Library/LaunchDaemons/com.example.Agent.plist || true" with administrator privileges'
For a user LaunchAgent:
launchctl disable gui/$(id -u)/com.example.Agent
launchctl bootout gui/$(id -u) "$HOME/Library/LaunchAgents/com.example.Agent.plist" || true
- Verify.
launchctl print-disabled system | rg 'com.example.Agent'
launchctl print system/com.example.Agent
ps -axo pid=,args= | rg '[c]om.example.Agent'
Expected disabled state:
"com.example.Agent" => disabled
Expected unloaded state:
Could not find service "com.example.Agent" in domain for system
Safety Rules
- Do not delete plist files or privileged helper binaries unless the user explicitly asks for removal.
- If the user asks to "disable", leave files in place and only change launchd state.
- For removal, disable and boot out first, then report the exact plist and helper paths that would be removed. Prefer moving files to a dated quarantine directory over immediate deletion when the user has not demanded deletion.
- Do not attempt to disable or remove Apple system daemons protected by SIP. Explain the limitation instead.
- Quote all user-provided paths and labels. App helper names often contain dots and may appear in shell commands.
- Expect apps to reinstall their privileged helper the next time the app starts or updates. Mention this if the daemon returns after being disabled.
- When a privileged command needs a password in a non-interactive shell, use
osascript ... with administrator privileges rather than hanging on sudo.
Re-enable Pattern
sudo launchctl enable system/com.example.Agent
sudo launchctl bootstrap system /Library/LaunchDaemons/com.example.Agent.plist
Or with the helper script:
python3 scripts/launchd_agent.py enable /Library/LaunchDaemons/com.example.Agent.plist --confirm --admin-prompt
Available Scripts
scripts/launchd_agent.py - Search, inspect, disable, verify, and re-enable macOS launchd jobs. Disable and enable actions require --confirm.