The missing service dashboard for macOS.
Launchdeck gives launchd jobs and Homebrew services one fast, readable control surface: status, schedules, plist metadata, logs, and guarded actions without spelunking through launchctl, brew services, and scattered plist files.
It is built for real developer machines, where background work lives across ~/Library/LaunchAgents, /Library/LaunchDaemons, Apple-managed jobs, vendor helpers, and Homebrew formulas. Launchdeck keeps the noisy system universe available when you need it, but starts with the services you are most likely to care about.
Why Launchdeck?
macOS service management is powerful, but the day-to-day experience is fragmented:
launchctlknows runtime state, but its output is dense and domain-oriented.- Plist files explain schedules, logs,
RunAtLoad, andKeepAlive, but they are spread across multiple directories. brew servicesis convenient, but only sees the Homebrew side of the world.- A stopped process might actually be a scheduled job waiting for its next run.
- Killing a process is not the same thing as unloading a launchd job.
Launchdeck brings those pieces together and adds the safety rails you want before changing anything. It shows the command before it runs, blocks risky system/vendor actions, preserves selection by service identity across refreshes, and makes logs and schedules visible where you make decisions.
Install
Install the latest macOS release binary:
brew install sderosiaux/tap/launchdeck
Without Homebrew:
curl -fsSL https://raw.githubusercontent.com/sderosiaux/launchdeck/main/scripts/install.sh | shThe installer writes to ~/.local/bin by default. Override it with:
BIN_DIR=/usr/local/bin sh -c "$(curl -fsSL https://raw.githubusercontent.com/sderosiaux/launchdeck/main/scripts/install.sh)"Install from source with Cargo:
Install from the GitHub repository:
cargo install --git https://github.com/sderosiaux/launchdeck
Or build locally:
git clone https://github.com/sderosiaux/launchdeck.git
cd launchdeck
cargo build --release
./target/release/launchdeckUsage
Print inventory without opening the TUI:
launchdeck list uses the same default visibility as the TUI and hides Apple/system services. Print the full discovered inventory with:
Features
- One service list for
launchdjobs and Homebrew services. - Runtime state from
launchctl, enriched with Homebrew metadata and parsed plist configuration. - A distinct
scheduledstate for loaded jobs that are not running now but will wake up later. - Compact schedule summaries such as
5min,1h,00:00, andSun 09:00. - Type-to-search, source/status filters, warnings-only view, Apple/system toggle, and practical sorting.
- Detail modal for status, scope, safety level, command, plist path, schedule, logs, and health warnings.
- Scrollable stdout/stderr log view from configured
StandardOutPathandStandardErrorPath. - Confirmed actions for start, stop, restart/load, enable/disable,
RunAtLoad, edit plist, and delete plist. - User LaunchAgent creation for common plist fields without hand-writing XML.
- Background refresh that keeps the selected service stable by identity, not row index.
Status Model
Launchdeck separates states that can otherwise look the same in launchctl output:
| Status | Meaning |
|---|---|
running |
launchd has an active PID for the job. |
scheduled |
job is loaded, has no active PID, and has a launchd schedule configured. |
stopped |
job is loaded, has no active PID, and has no known schedule. |
unloaded |
plist exists, but the job is not loaded into launchd. |
disabled |
launchd marks the job disabled in its domain. |
failed |
launchd or Homebrew reported a non-zero exit/error state. |
unknown |
Launchdeck could not classify the current state. |
For scheduled jobs, stop uses launchctl bootout so the job is actually unloaded and will not wake up on the next schedule.
Keybindings
Overview
| Key | Action |
|---|---|
| Type text | Start quick search |
Down / Up |
Move selection |
PageDown / PageUp |
Move by a page |
Enter |
Open service detail |
? / F1 |
Open keyboard help |
/ |
Search |
C |
Clear search |
Y |
Copy selected service name |
P |
Cycle source filter |
F |
Cycle status filter |
O |
Cycle sort mode |
A |
Toggle Apple/system services |
W |
Toggle warnings-only view |
F5 / Ctrl-r |
Refresh inventory |
L |
Open logs |
S |
Prepare start action |
X |
Prepare stop action |
R |
Prepare restart/load action |
T |
Prepare enable/disable action |
U |
Prepare RunAtLoad toggle action |
E |
Prepare edit plist action |
D |
Prepare delete plist action |
N |
Create a user LaunchAgent |
q |
Quit |
Actions show the exact command before execution. Press y/Enter to confirm or n/Esc to cancel.
Detail
| Key | Action |
|---|---|
j / Down |
Move down inside detail |
k / Up |
Move up inside detail |
PageDown / PageUp |
Move by a page |
g / G |
First / last detail row |
Enter |
Act on selected row: status, plist, RunAtLoad, stdout, or stderr |
c |
Copy selected field value |
l |
Open stdout logs |
u |
Prepare RunAtLoad toggle action |
E |
Prepare edit plist action |
D |
Prepare delete plist action |
Esc / Backspace / Left |
Back to overview |
Logs
| Key | Action |
|---|---|
j / Down |
Newer lines |
k / Up |
Older lines |
PageDown / PageUp |
Move by a page |
g / G |
Top / bottom of loaded tail |
Tab / Left / Right |
Switch stdout/stderr |
c |
Copy current log path |
Esc / Backspace |
Back to detail |
The log view opens at the end of the selected stream and keeps a scrollback window from the latest 500 lines.
Safety
Launchdeck is conservative by default:
- Homebrew services are managed through
brew services. - User-owned launchd jobs are managed through
launchctl. - Services under
/System/Libraryare inspect-only. - Admin-required services are blocked until sudo handling is implemented.
- Vendor/runtime services are blocked unless they can be classified safely.
- Destructive actions, including delete, always require confirmation.
Create Form
The create form writes user LaunchAgents only, under ~/Library/LaunchAgents.
It supports common plist fields: label, program arguments, working directory, stdout/stderr paths, environment variables, RunAtLoad, KeepAlive, StartInterval, optional bootstrap, and optional start.
Arguments and environment values accept shell-style quotes, so values like --name "hello world" are preserved correctly.
Requirements
- macOS
- Homebrew optional, for
brew servicessupport - Rust toolchain only when installing from source
Test Fixture
The repository includes a fake user agent plist for local discovery testing:
cp fixtures/com.sderosiaux.launchdeck.fake.plist ~/Library/LaunchAgents/ cargo run -- --list | rg launchdeck.fake
The fixture is not loaded or started by that command. Remove it with:
rm ~/Library/LaunchAgents/com.sderosiaux.launchdeck.fake.plistDevelopment
scripts/lint.sh cargo run cargo run -- --list
Release
Releases are built from tags:
git tag v0.1.0 git push origin v0.1.0
The release workflow builds macOS archives for Apple Silicon and Intel, publishes checksums, and updates the GitHub release assets.
Project Status
Launchdeck is early software. It is already useful for inventory, inspection, filtering, navigable logs, guarded lifecycle actions, and creating user LaunchAgents. Sudo-backed admin actions are not implemented yet.
