I was recently performing some routine cleanup on my Macbook (macOS Sequoia 15.1), and specifically, was taking a look at the System Preferences > Login Items & Extensions pane to audit what applications I have enabled for startup. There was one item in there (Dropshelf) which I could not find the .plist for. Usually, they’re stored in ~/Library/LaunchAgents, /Library/LaunchAgents, or /Library/LaunchDaemons. Trying to identify where the items in this pane were being sourced from, led me to doing some research on macOS login items and background tasks, their purposes, their locations, and some cool tools to manage them from the CLI.

macOS Persistence Types

The “Login Items & Extensions” pane is split into two sections: 1) “Open at Login” and 2) “Allow in the background”. The “Open at Login” is pretty easy, it simply references a .app file that will be executed when the user logs in. The “Allow in the background” is a bit more ambiguous, but for the most part, they come from LaunchAgents and LaunchDaemons via launchctl.

  • LaunchAgent: Run in the context of a user and load when the user logs in to their account.
  • LaunchDaemon: Run in the context of the system and load at system startup— independent of user sessions.

Before macOS 13, .plist files were the only method of enabling background tasks and were loaded and launched via the launchctl (basically macOS’s systemctl). However, in macOS versions >13, Apple implemented “background task management” (BTM) which is a file structure format for state management of background tasks. This is where the “Login Items & Extensions” pane pulls its data from.

macOS Persistence Locations

Open at Login

“Open at Login” is sourced from Apple’s “background task management” (BTM). In macOS <13, the BTM file is located at ~/Library/Application Support/com.apple.backgroundtaskmanagementagent/backgrounditems.btm and can be parsed using bgiparser. In macOS >=13, BTM is located at /private/var/db/com.apple.backgroundtaskmanagement and can be dumped using the built-in sfltool dumpbtm.

For example, let’s look at Raycast which is in the “Open at Login” pane.

We can use sfltool dumpbtm | grep -n5 Raycast:

735-                 UUID: 5C2D022A-88DF-40BF-BFA0-544FAABA3904
736:                 Name: Raycast
737:       Developer Name: Raycast Technologies Inc
738-      Team Identifier: SY64MV22J9
739-                 Type: app (0x2)
740-                Flags: [  ] (0)
741-          Disposition: [enabled, allowed, visible, notified] (0xb)
742-           Identifier: 2.com.raycast.macos
743:                  URL: file:///Applications/Raycast.app/
744-           Generation: 1
745-    Bundle Identifier: com.raycast.macos

If you want to remove “Open at Login” items, you must do it through the “Open at Login” pane, selecting the application and using the - icon.

Allow in the background

These items will (typically) be stored in either ~/Library/LaunchAgents, /Library/LaunchAgents, /Library/LaunchDaemons, /System/Library/LaunchDaemons, or /System/Library/LaunchAgents. In these folders, you will find .plist files which are loaded and launched via launchctl.

For example, brew_autoupdate:

We can use launchctl dumpstate | grep -n5 brew_autoupdate:

gui/501/com.github.domt4.homebrew-autoupdate = {
	active count = 0
	path = /Users/landoncrabtree/Library/LaunchAgents/com.github.domt4.homebrew-autoupdate.plist
	type = LaunchAgent

With this item, we see that it’s loaded from /Users/landoncrabtree/Library/LaunchAgents/com.github.domt4.homebrew-autoupdate.plist and we can remove this background item either by toggling it within the “Allow in the background” pane or by removing the file, ie rm -rf /Users/landoncrabtree/Library/LaunchAgents/com.github.domt4.homebrew-autoupdate.plist and then performing a reboot.

However, an interesting thing to note is that not all launchctl services require a .plist, nor do they need to be in a predefined path (ie: you can load a service from ~/Desktop/evil.plist if you wanted). For example, take a look at Dropshelf which is in the “Allow in Background” pane. Similar to our brew_autoupdate, we would hope to find the associated .plist:

Yet, launchctl dumpstate | grep -n5 Dropshelf:

gui/501/com.pilotmoon.Dropshelf.launcher = {
	active count = 0
	path = (submitted by smd.322)
	type = Submitted
	managed_by = com.apple.xpc.ServiceManagement

The path is “submitted by smd.322”. As it turns out, apps can use the Service Management (SM) framework API to register LaunchAgents and LaunchDaemons directly, without needing to create an associated .plist. This makes it a bit more tricky from the experienced macOS user side of things, as it appears it is not possible to delete these services via CLI but rather just disable by toggling the item in the “Allow in the background” pane.

(Side-note: I would think an associated plist (or other propriety smd file format) has to exist somewhere on the filesystem, but I haven’t been able to locate it just yet. If you know where it is, feel free to reach out to [email protected] and I can update this post accordingly).