A modern GUI for managing macOS LaunchAgents.
- 🎯 Manage LaunchAgents with an intuitive interface
- 👁️ View user-level and system-level services
- 📊 View service status in real-time
▶️ Start/Stop user services with one click- ⚡ Run Now (Kickstart) — start a service immediately with one click (
launchctl kickstart -k) - 📋 View service logs (stdout/stderr) with ANSI color rendering (16-color SGR sequences are shown as colored text instead of raw
[31mescape codes); services without a configured log path or a not-yet-created log file show a clear placeholder instead of a generic error - 🧹 Clear stdout / stderr logs from the Logs tab (one-click in-place truncate; system daemons fall back to the privileged helper only when the file is not user-writable)
- 🔄 Auto-refresh the Logs tab (
tail -f-style): an optional toggle reloads the current stream every 2 seconds; it turns itself off when a load has no path, is not found, or fails, and stays independent of Auto-scroll - ➕ Create and configure new services
- ⏰ Schedule services with Calendar Interval or Fixed Interval
- 📅 Cron-style range (
9-17) and enumeration (1,3,5) syntax with automatic expansion - 🌐 Configure environment variables for services
- ✏️ Edit existing service configurations
- 🧬 Preserve advanced launchd keys on edit — keys LaunchPal has no UI for (e.g.
ProcessType,Nice,MachServices,Sockets, resource limits) are kept verbatim when you update a service, instead of being dropped - 🔍 Browse system services (read-only) with heuristic status detection (no elevation required); ambiguous matches are flagged with an info icon
- 🔐 Admin Mode — manage
/Library/LaunchDaemonssystem services with a single authorization per session (no persistent root process; helper exits when LaunchPal does) - 📄 Inspect plist files with syntax highlighting
- 📂 Reveal plist files in Finder with one click
- 💾 Automatic backup before modifications
- 🔍 Side-by-side diff preview before restoring a backup (binary plists are auto-converted to XML)
brew install --cask chenwei791129/apps/launchpalOr add the tap first:
brew tap chenwei791129/apps
brew install --cask launchpalNote: LaunchPal is not code-signed. The quarantine attribute is automatically removed during Homebrew installation so macOS Gatekeeper will not block the app.
Download the latest release from the Releases page.
LaunchPal is currently not signed with an Apple Developer certificate. macOS will block unsigned applications from running by default.
After downloading the .dmg file, open it and drag LaunchPal.app to the Applications folder. Then remove the quarantine attribute before running it:
xattr -dr com.apple.quarantine /Applications/launchpal.appAlternatively, you can try right-clicking the app and selecting "Open" from the context menu, which may prompt you to allow the unsigned app to run.
If you prefer to build from source:
# Clone the repository
git clone https://github.com/chenwei791129/launchpal.git
cd launchpal
# Install dependencies
make setup
# Build the application
make build
# The app will be in build/bin/launchpal.appLaunchPal can manage system services under /Library/LaunchDaemons via an optional Admin Mode:
- Open Settings → Admin Mode → Enable Admin Mode.
- macOS prompts once for your password (or Touch ID) and launches a root-privileged helper process.
- While Admin Mode is enabled, the System Services page lets you Start / Stop / Restart / Edit / Delete / Create daemons.
- Click Disable Admin Mode (or quit LaunchPal) to stop the helper — nothing persists on the system.
Why session-scoped? LaunchPal is unsigned and cannot register a persistent privileged helper. The session-scoped model trades "enter your password once per launch" for "no root daemon lingers on your machine after LaunchPal exits". The helper exits automatically if LaunchPal crashes or is force-quit (parent PID watchdog, 2-second response time).
Scope of Admin Mode writes: only /Library/LaunchDaemons/. /System/Library/LaunchDaemons/ remains read-only under Admin Mode (SIP would reject writes anyway).
Helper launch integrity: because LaunchPal is unsigned, it protects the root-privileged helper against tampering with a root-owned trust anchor. The first time you enable Admin Mode, the helper installs a copy of itself at /Library/Application Support/LaunchPal/launchpal-privhelper, owned root:wheel with mode 0755 — a location no non-root process can write. Every subsequent enable launches that protected copy directly, so a helper planted in the (user-writable) app bundle can never be run as root once the protected copy exists. As defense-in-depth, the SHA-256 of the packaged helper is pinned into the app binary at build time and checked before a bundle copy is ever launched (first install or a legitimate app update); the pin only gates the bundle copy and is never required to launch the protected copy. This requires no extra prompts — provisioning happens inside the same one-per-session authorization, and brew install never asks for sudo. Residual risk: the very first enable (and the first enable after each app update) still runs the bundle copy once — this bootstrap window cannot be fully closed without a paid Apple Developer signing identity.
- User services (
~/Library/LaunchAgents) can be managed without authorization. - System services (
/Library/LaunchDaemons) require Admin Mode; authorization is prompted once per LaunchPal session and not cached across sessions (by design — no persistent root daemon). - Apple system services (
/System/Library/LaunchDaemons) are always read-only. - Some system services may require Full Disk Access permission to view.
- Editing a system daemon requires LaunchPal to read its existing plist to preserve advanced (unmodeled) keys; without Full Disk Access that read fails and the edit falls back to writing only the keys shown in the form.
- A
Disabledkey in a service plist is preserved on edit (LaunchPal does not model it), so editing a disabled service keeps it disabled. There is no in-app control to clearDisabled; uselaunchctl enableto re-enable such a service.
MIT License - see LICENSE file for details.



