Feature Guide
A comprehensive walkthrough of everything LaunchPad does -- from automatic agent discovery to Touch ID security.
Agent Discovery P0
On first launch and on-demand, LaunchPad scans your system for every existing LaunchAgent plist file. It parses each plist, extracts the full configuration, and cross-references with launchctl list to determine live status.
Scan coverage
~/Library/LaunchAgents/-- your user-level agents (full read/write access for managed jobs)/Library/LaunchAgents/-- system-wide user agents (read-only in the dashboard)
What gets extracted from each plist
| Field | Plist Key |
|---|---|
| Label | Label |
| Command & arguments | ProgramArguments or Program |
| Schedule | StartInterval, StartCalendarInterval |
| Event triggers | WatchPaths, QueueDirectories, StartOnMount |
| Keep-alive config | KeepAlive (boolean or conditional) |
| Environment | EnvironmentVariables, WorkingDirectory |
| Log paths | StandardOutPath, StandardErrorPath |
| Advanced | RunAtLoad, ThrottleInterval, Nice, ProcessType |
Status detection
For each discovered agent, LaunchPad queries launchctl list to determine:
- Loaded vs. Unloaded -- whether the agent is registered with launchd
- Running vs. Idle -- whether the agent has an active process (PID)
- Last exit code -- success (0) or failure (non-zero)
Jobs not created by LaunchPad are marked as "External" with a read-only badge. You can inspect their configuration but cannot modify or delete them. LaunchPad identifies its own jobs by the presence of a <key>LaunchPadManaged</key><true/> key in the plist.
Malformed plist files are handled gracefully -- displayed with an error indicator, never crashing the scan. The full scan of 100+ plists completes in under 3 seconds.
Job Builder P0
The Job Builder is a visual form that replaces manual plist XML authoring. It collects all the configuration a LaunchAgent needs, validates inputs in real time, generates valid plist XML, and registers the job with launchctl -- all in one flow.
Form fields
| Field | Description |
|---|---|
| Label | Reverse-DNS identifier (auto-suggested from executable name, e.g., com.launchpad.backup) |
| Name | Human-readable display name |
| Command | Executable path with file picker or manual input |
| Arguments | Additional command-line arguments |
| Working Directory | CWD for execution |
| Environment Variables | Key-value editor for env vars |
| Schedule | Triple input: visual, cron, or natural language (see Schedule Engine) |
| Event Triggers | WatchPaths, QueueDirectories, StartOnMount (see Event System) |
| Log Paths | Auto-defaulted to ~/Library/Logs/LaunchPad/<label>.log/.err |
| KeepAlive | Boolean or conditional (NetworkState, SuccessfulExit, PathState, Crashed) |
| RunAtLoad | Execute immediately when loaded |
| Nice | Process priority (-20 to 20) |
| ProcessType | Standard, Background, or Adaptive |
Built-in safeguards
- Label uniqueness is validated against both the database and
launchctl list - Generated plist XML is validated with
plutil -lintbefore writing - A plist preview pane shows the exact XML before saving
- A "Test Run" button executes the command once and displays output in a modal
- Conflicting schedule types (
StartInterval+StartCalendarInterval) are prevented at the form level
On save
- Plist XML is generated and validated
- File is written to
~/Library/LaunchAgents/ - Job is registered:
launchctl bootstrap gui/<uid> <path> - Job record is created in SQLite with full configuration
Schedule Engine P0
Three interchangeable schedule input methods, all bidirectionally synced. Change one and the others update automatically.
The default input. Provides dropdowns and toggles for:
- Day-of-week multi-select: Mon-Sun presets ("Every day", "Weekdays", "Weekends")
- Hour picker: 0-23 (or 12h AM/PM toggle)
- Minute picker: 0-59 or common intervals (00, 15, 30, 45)
- Interval mode: every N seconds/minutes/hours for frequency-based schedules
A 7-day timeline strip below the form shows exactly when the job will fire next.
Standard 5-field cron expression: minute hour day-of-month month day-of-week. Below the input, LaunchPad shows:
- Human-readable description (e.g., "At 09:00, Monday through Friday")
- Next 5 scheduled run times
Invalid cron expressions are rejected with a clear error message before you can save.
Type plain English and LaunchPad parses it with chrono-node. Supported patterns include:
every 30 minutesdaily at 9amevery weekday at 9amevery Monday at noontwice dailyfirst Monday of the month at noon
The parsed interpretation is shown for confirmation before applying.
Schedule mapping
All three inputs map to launchd's native schedule keys:
- Calendar-based schedules map to
StartCalendarInterval(single dict or array of dicts) - Frequency-based schedules map to
StartInterval(integer seconds)
LaunchPad warns when a schedule would fire more than 100 times per day (potential misconfiguration) and prevents using StartCalendarInterval and StartInterval simultaneously, as launchd behavior is undefined in that case.
Event System P0
Beyond time-based schedules, launchd supports event-driven triggers. LaunchPad exposes all of them through the UI.
| Trigger | Plist Key | Description |
|---|---|---|
| WatchPaths | WatchPaths | Trigger when a file or directory changes. Supports multiple paths with file/folder picker. |
| QueueDirectories | QueueDirectories | Trigger when items appear in a directory. Job processes and removes them. |
| StartOnMount | StartOnMount | Trigger when a volume (USB drive, network share) is mounted. |
| RunAtLoad | RunAtLoad | Execute immediately when the agent is loaded (at login). |
| KeepAlive | KeepAlive | Restart the job based on conditions: always, on crash, on network change, on path state, or on successful exit. |
Event triggers are configured in a separate section from the schedule, but they can be combined. A job can have both a recurring schedule and a file watch trigger. The UI clearly indicates when multiple trigger types are active.
Path-based triggers (WatchPaths, QueueDirectories) validate that paths exist, showing a warning (not blocking) if the path is missing.
Log Viewer P0
For every managed job, LaunchPad captures and stores complete execution history: start time, end time, duration, exit code, and full stdout/stderr output.
Execution timeline
The job detail view shows a chronological timeline of every run with color-coded status badges:
- Success -- exit code 0
- Failed -- non-zero exit code
- Running -- active PID
- Signal -- terminated by signal
Each entry shows the timestamp, duration, and a one-line stderr excerpt if the exit code was non-zero. Click to expand and see full stdout and stderr in a terminal-style log viewer.
Log viewer features
- Monospace font on dark background
- ANSI color code rendering
- Text search (Cmd+F)
- Copy-to-clipboard for full log content
- Auto-scroll toggle for live tailing
- Logs exceeding 1 MB are truncated with a "Download Full Log" option
Live tail mode
For currently running jobs, the log viewer streams output in real time by polling the log file and appending new content. Toggle auto-scroll on or off depending on your needs.
Per-job statistics
| Metric | Description |
|---|---|
| Total runs | Lifetime execution count |
| Success rate | Percentage of runs with exit code 0 |
| Average duration | Mean execution time in ms |
| Last run | Timestamp of most recent execution |
| Last failure | Timestamp of most recent non-zero exit |
Organization P1
Two complementary systems for managing jobs at scale: Folders for hierarchical grouping and Tags for cross-cutting labels.
Folders
- Each job belongs to exactly one folder
- Supports nested folders up to 3 levels deep
- Default folders: "Uncategorized" (all new jobs) and "System" (external/read-only agents) -- cannot be deleted
- Folder sidebar shows a tree view with job count badges
- Drag-and-drop jobs into folders
Tags
- Each job can have multiple tags
- Tags are color-coded and user-defined
- Click a tag to filter; Shift+Click for multi-tag filtering (AND/OR toggle)
Search and filtering
- Full-text search across job label, command path, folder name, and tag names
- Status filter: running, idle, failed (last run), disabled/unloaded
- Sort options: name, last run, next run, status (failures first), date created
- Active filters are shown as removable chips above the job list
Bulk operations
Select multiple jobs via checkboxes, then apply batch actions: move to folder, add/remove tag, enable, disable, or delete. Bulk operations require a single Touch ID confirmation.
Security P1
LaunchPad uses macOS Touch ID via the Web Authentication API (WebAuthn) to protect destructive operations. This is defense-in-depth for a localhost tool -- preventing accidental modifications, not protecting against a compromised machine.
Protected operations
- Deleting a job
- Modifying a job's command or schedule
- Enabling/disabling a job (load/unload)
- Bulk operations (single confirmation for the batch)
How it works
- Server generates a WebAuthn challenge
- Browser calls
navigator.credentials.get() - macOS prompts Touch ID (or password fallback)
- Signed assertion is sent back to the server
- Server verifies and proceeds with the operation
A 5-minute session cooldown (configurable) prevents repeated prompts during active management sessions. Touch ID can be globally toggled off in Settings.
System job protection
Jobs in /Library/LaunchAgents/ and user-level agents not created by LaunchPad are always read-only. All API write endpoints enforce is_managed = true before proceeding. LaunchPad-created plists include a LaunchPadManaged key for identification.
Import & Export P1
Backup and share your LaunchPad-managed jobs.
- Export: Download a bundle of all managed job plists as a ZIP archive, or export individual job configurations as JSON
- Import: Load plist files or LaunchPad JSON exports to recreate jobs on another machine
- Migration: The export bundle includes all metadata (folder assignments, tags, notification preferences) alongside the plist files
Preferences P1
Global settings accessible from the dashboard sidebar.
| Setting | Description | Default |
|---|---|---|
| Server port | Port the dashboard binds to | 24680 |
| Polling interval | Frequency of status checks and log capture | 30 seconds |
| Log retention | How long execution logs are kept before pruning | 90 days |
| Notifications | Global toggle for macOS native failure notifications | Enabled |
| Touch ID | Require biometric confirmation for destructive ops | Enabled |
| Touch ID cooldown | Session duration before re-prompting | 5 minutes |
| Theme | Dark mode (default) or light mode | Dark |
| Auto-start | Start LaunchPad server on login | Enabled |
Notifications P1
When a managed job exits with a non-zero exit code, LaunchPad sends a macOS native notification via Notification Center within 60 seconds of the failure.
Notification content
- Title: "LaunchPad: Job Failed"
- Body: Job label, exit code, and the first 100 characters of stderr
- Action: Clicking the notification opens the dashboard to the failed job's detail view
In-app notification center
A bell icon in the dashboard header shows a chronological list of all failure events with read/unread indicators. Includes "Mark all read" and "Clear all" actions.
Per-job notification settings
- Every failure (default) -- notify on each non-zero exit
- After N consecutive failures -- suppress noise for flaky jobs
- Disabled -- no notifications for this job
Auto-Start & Menubar P1
LaunchPad installs itself as a LaunchAgent that starts on login. The menubar icon provides at-a-glance status:
- Green -- all jobs healthy
- Yellow -- warnings detected
- Red -- failures in the last 24 hours
Clicking the menubar icon shows a dropdown with: job status summary, "Open Dashboard" link, recently failed jobs, and a Quit option. The menubar polls /api/status every 60 seconds.