Skip to content
roeehrlPublic

About

Free, open-source launchd GUI and CLI for macOS: see every LaunchAgent and LaunchDaemon, find out why a job isn't running, and fix it. Lossless plist editor with diffs and backups.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

LD Manager icon

LD Manager

Know what runs on your Mac. Fix what doesn’t.
A free, open-source, native macOS app and CLI for LaunchAgents and LaunchDaemons.

English | 简体中文 | 日本語

CI MIT licence macOS 26+ Swift 6.2 SwiftUI

What it does · Install · CLI · Why not…? · FAQ · Contributing

A failed job in LD Manager: the inspector shows exit 78 because the program is missing, the Doctor offers the fix, the editor shows a one-line diff, and the job turns green
A job fails with exit 78; LD Manager shows why, the Doctor offers the fix, the editor shows the diff, and the job runs. All data in these images is made up.

launchctl tells you Bootstrap failed: 5: Input/output error and leaves you to guess. LD Manager reads every layer launchd has — the plist on disk, whether it's loaded, the enable/disable override, the Login Items switch, the PID, the launch count and the last exit code — and tells you in plain words what's wrong and how to fix it.

What it does

LD Manager's main window: a table of launch jobs with their status, schedule, runs and last result, and an inspector showing every layer of the selected job's state
  • See every job and its real state. Your agents, agents for all users, system daemons and (read-only) Apple's own — each with one status joined from every layer: running, waiting, failed, disabled, off in Login Items, not loaded or invalid.
  • Find out why it fails. The Doctor checks for invalid plists, missing Labels, missing, non-executable or quarantined programs, an unexpanded ~, wrong ownership or permissions, missing log folders, restart loops, jobs enabled but not loaded, and failed runs — and offers a fix for each.
  • Read schedules and exit codes like a person. StartCalendarInterval {Weekday 1, Hour 9, Minute 30} is Mondays at 09:30, with the next runs. 78 is EX_CONFIG: usually a missing or non-executable program; -15 is killed by SIGTERM.
  • Edit without losing a key. A plain-language form, a Keys view and raw XML. Changes are applied to the file's own dictionary, so keys the form doesn't know survive. Every save shows a diff first and keeps a backup you can restore from Recent Changes.
  • Start, stop, enable, disable, load, unload — with a switch, a menu-bar extra for pinned jobs, or ldm.
  • Script it. ldm is the same core as a CLI, with --json, --dry-run that prints the exact launchctl commands, and documented exit codes.
The Doctor: a list of jobs that need attention and, for the selected one, each check, the evidence and a fix button
The Doctor explains the failure and offers the fix.
The editor: a form for program, schedule and log file, with a diff of the one changed key at the bottom
Lossless editing: see the diff before you save.
Recent Changes: a list of plist backups with Show and Restore buttons
Recent Changes: every save keeps a backup.
Terminal running ldm list, ldm doctor and ldm explain 78
ldm: the same Doctor in your terminal.

Requires macOS 26 or later.

Install

Download LD Manager for Mac (macOS 26 or later). It is signed and notarized by Apple: open the disk image and drag LD Manager to Applications. The ldm command is inside the app; install it from Settings → Command-line tool, or download ldm-macos.zip on its own. Every release lists SHA-256 checksums.

From source

You need Xcode 26 and XcodeGen (brew install xcodegen).

scripts/build-app.sh

This produces build/LD Manager.app with ldm bundled in Contents/Helpers. In the app, Settings → Command-line tool links it into /usr/local/bin.

The script signs with your first Developer ID Application or Apple Development certificate (hardened runtime, ready to notarize), or with SIGN_IDENTITY if set. SIGN_IDENTITY=- signs ad-hoc; everything works except the privileged helper.

To make a release (sign, notarize, staple, disk image, standalone ldm and checksums in build/release), run scripts/release.sh with App Store Connect API key credentials or a notarytool profile; see the top of the script.

The CLI also builds on its own:

swift build -c release --product ldm

Run the tests with swift test.

Quick start with ldm

ldm list --status problems     # jobs that need attention
ldm doctor report              # why "report" fails, and how to fix it
ldm explain 78                 # what an exit code means
ldm new backup --every 1h -- ~/bin/backup.sh
ldm logs backup -f

The ldm command

ldm list [--status failed|running|disabled|problems] [--scope user|allUsers|system] [--json|--plain]
ldm show <job> [--json] [--background]
ldm doctor [<job>] [--json] [--background]
ldm start|stop|restart|load|unload|enable|disable <job> [--dry-run]
ldm logs <job> [-n 40] [-f]
ldm new <name> (--every 15m | --cron "30 9 * * 1" | --keep-alive | --watch <path>) [--log <file>] -- <program> [args…]
ldm edit <job> [--program <path>] [--every …] [--log <file>] [--dry-run]
ldm remove <job> --confirm <label>
ldm explain <code>
ldm helper

A job can be named by its full label, its last label component, its file name, or any unique part of its label. --dry-run prints the exact launchctl commands instead of running them. Colors are off when output isn't a terminal or NO_COLOR is set.

--background re-reads Login Items › App Background Activity. macOS asks for your password each time, so without the flag ldm uses the last result it read.

Exit code Meaning
0 Success
1 General error
2 Usage error, or the name matches several jobs
3 No such job
4 Administrator authorization needed or cancelled
5 launchd rejected the operation
6 doctor found problems

Why not LaunchControl, Lingon or launchctl?

  • LaunchControl is the most complete launchd tool and worth its price if you live in launchd. LD Manager is free and open source, explains things in plainer language, and has a scriptable CLI with JSON output. LaunchControl has more expert features today.
  • Lingon makes creating jobs easy but shows less of why one isn't running. LD Manager is built around that question.
  • KnockKnock / BlockBlock show what persists on your Mac and alert on new items, for security. They don't edit, start or diagnose jobs. Use them together.
  • System Settings › Login Items only has on/off switches for registered items: no schedules, logs, exit codes or editing.
  • launchctl and a text editor work if you know launchd well. LD Manager translates the errors, shows the exact commands (--dry-run) and keeps a backup of every edit.
  • brew services only manages Homebrew formulae.

FAQ

Is it safe to edit system jobs with it? Every save shows a diff and keeps a backup first; Apple's jobs on the sealed system volume are read-only; changes to system daemons and /Library go through macOS's administrator prompt or the optional helper you approve once.

Does it send anything anywhere? No. It makes no network connections and has no analytics. It reads launchd's state with launchctl and your plist files on disk.

Why does it need macOS 26? It uses the current SwiftUI and the Login Items (Background Task Management) behaviour of recent macOS. Supporting older versions is open for discussion — see Contributing.

Why not the Mac App Store? Sandboxed apps can't drive launchctl or read other apps' launch jobs.

What does "LD" stand for? launchd.

How it works

There is no public API for launchd state, so LD Manager reads it the way an administrator would: launchctl print <domain> for each domain's services, launchctl print-disabled for overrides, launchctl print <domain>/<label> for a job's details, and the plist files themselves. Apple documents launchctl print's output as not being an API, so every parser ignores lines it doesn't recognise.

The App Background Activity switches (called Allow in the Background on earlier macOS versions) live in Background Task Management, a database only root can read. There is no public API for it, so LD Manager reads it with sfltool dumpbtm, which shows an administrator prompt every time it runs. Without the helper it is only read when you ask (Check Login Items… in the app, --background in the CLI); with the helper it is read silently, and the app keeps it fresh. The result is cached in ~/Library/Caches/LDManager. These switches can't be changed programmatically; the app opens the Login Items pane in System Settings instead.

The privileged helper

Changing system daemons and files in /Library needs root. Without help, every such action shows macOS's administrator prompt. LD Manager can instead install a small helper (SMAppService daemon, bundled in the app) that you approve once in System Settings › General › Login Items › App Background Activity.

  • Nothing is asked at launch. The first time you do something that needs root, LD Manager explains the helper and offers Continue, Use Password Instead or Cancel. Choosing passwords is remembered; a banner, not a dialog, reminds you.
  • On Continue, System Settings opens with a small guide beside it. LD Manager detects the approval on its own, confirms the helper answers, and finishes what you were doing.
  • The helper only accepts LD Manager and its bundled ldm, verified by code signature (same team, specific bundle identifiers). It does a fixed set of things, each validated: launchctl on the system domain, writing or removing plists in /Library/LaunchDaemons and /Library/LaunchAgents, fixing their permissions, creating log folders, removing quarantine, and reading Login Items.
  • Remove it any time in Settings › Privileged helper. ldm helper reports whether it is reachable. It exits when idle and launchd relaunches it from the current app, so updates take effect on their own (ldm helper --restart forces it).

Changes go through launchctl bootstrap, bootout, enable, disable, kickstart and kill. Changes to system daemons, and writes to /Library, ask for an administrator password through macOS.

Layout

Sources/LDCore   job model, plist reading and lossless editing, launchctl adapter,
                 schedules, exit codes, the Doctor
Sources/ldm      the CLI (Swift Argument Parser)
Sources/LDManagerHelper  the privileged helper (XPC, runs as root)
App/             the SwiftUI app (XcodeGen project.yml, Sources, Resources)
Tests/           unit tests for the parsers, schedules, editing and the Doctor
scripts/         app bundle build script and icon renderer
demo/            the invented demo world and the scripts that make the screenshots
docs/            research notes behind the design; docs/assets has the README images

Contributing

Issues and pull requests are welcome — bug reports with the output of ldm show <job> --json help most. Good places to start are issues labelled good first issue and help wanted. See CONTRIBUTING.md for the 60-second setup, and demo/ for the invented demo world the screenshots come from, so you never need to touch your own launch jobs to test a change.

Roadmap

  • Notifications when something adds or changes a launch job, and a timeline of upcoming runs.
  • A Background Items explorer: owner app, Team ID, orphaned items.
  • Shortcuts actions and templates for common jobs.

License

MIT — see LICENSE. LaunchControl, Lingon, KnockKnock and BlockBlock are products of their respective owners; LD Manager is not affiliated with them or with Apple.

About

Free, open-source launchd GUI and CLI for macOS: see every LaunchAgent and LaunchDaemon, find out why a job isn't running, and fix it. Lossless plist editor with diffs and backups.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages