Skip to content

Usage

macpmd provides a command-line interface for managing long-running processes on macOS.

add — Add a process

macpmd add "<command>"
macpmd add "<command>" --name <name>
macpmd add "<command>" --name <name> --sudo

Registers a new process with macpmd and starts it. The command is executed via the shell, so pipes, environment variables, and other shell features work. A launchd plist is automatically installed so the process survives reboots and recovers from crashes.

If --name is omitted, the name is auto-derived from the command.

# Name auto-derived as "server"
macpmd add "node server.js"

# Explicit name
macpmd add "python3 worker.py" --name my-worker

# With sudo
macpmd add "python3 server.py" --name my-app --sudo

# With shell features
macpmd add "cd /opt/app && ./run.sh 2>&1 | tee extra.log" --name app

The process is spawned in a new session, so it continues running after the terminal closes. The working directory and environment are captured at start time.

Option Description
--name, -n Name for the process (auto-derived if omitted)
--sudo, -s Run the process with sudo

start — Start existing processes

macpmd start <name> [<name> ...]
macpmd start --all

Starts existing stopped or errored processes. The launchd plist is reinstalled so the process resumes boot persistence and crash recovery.

# Start a stopped process
macpmd start my-app

# Start multiple processes
macpmd start my-app worker

# Start all stopped processes
macpmd start --all

stop — Stop processes

macpmd stop <name> [<name> ...]
macpmd stop --all

Sends SIGTERM to the process group. If the process does not exit within 3 seconds, SIGKILL is sent. The launchd plist is uninstalled first so launchd does not restart the process.

# Stop a single process
macpmd stop my-api

# Stop multiple processes
macpmd stop my-api worker

# Stop all processes
macpmd stop --all

restart — Restart processes

macpmd restart <name> [<name> ...]
macpmd restart --all

Stops the process (if running) and starts it again. The restart counter is incremented. The launchd plist is reinstalled with the updated state.

# Restart a single process
macpmd restart my-api

# Restart multiple processes
macpmd restart my-api worker

# Restart all processes
macpmd restart --all

delete — Remove processes

macpmd delete <name> [<name> ...]
macpmd delete --all

Stops the process (if running), uninstalls its launchd plist, deletes its log files, and removes it from macpmd's state.

# Delete a single process
macpmd delete my-api

# Delete multiple processes
macpmd delete my-api worker

# Delete all processes
macpmd delete --all

list — Show all processes

macpmd list

Displays a table of all registered processes with:

Column Description
Name Process name
Status running, stopped, or errored
PID Process ID (if running)
Uptime Time since the process was last started
Restarts Number of times the process has been restarted
Sudo Whether the process runs with sudo
launchd Whether a launchd plist is installed

Process statuses are refreshed automatically — if a process has died since the last check, its status is updated to errored. If a running process is missing its launchd plist, the launchd column is shown in red as a warning — use macpmd fix to reinstall it.

logs — View process logs

macpmd logs <name> [<name> ...]
macpmd logs --all
macpmd logs <name> --follow
macpmd logs --all --follow

All process output (stdout and stderr) is captured in ~/.local/share/macpmd/logs/<name>.log. Logs span across rotated files, so you can see the full history.

Option Description
--lines, -l Number of lines to show (default: 50, 0 for all)
--follow, -f Follow log output in real-time
--all, -a Show logs for all processes

When viewing logs for multiple processes (either by naming several or using --all), each line is prefixed with the coloured process name, docker-compose style:

my-api | [12:34:56] Server started on port 3000
worker | [12:34:57] Processing job 42

When using --follow, the last N lines are shown first (controlled by --lines), then new output is displayed in real-time. Press Ctrl+C to stop following.

Lifecycle Events

macpmd logs process lifecycle events with a [macpmd] prefix:

[macpmd] Process started at 2026-03-08 12:34:56 UTC (PID 1234)
... process output ...
[macpmd] Process exited at 2026-03-08 12:35:56 UTC with code 0
[macpmd] Process restarting at 2026-03-08 12:35:57 UTC (restart #1)
[macpmd] Process started at 2026-03-08 12:35:57 UTC (PID 1235)

Log Rotation

Log files are rotated automatically when they exceed 10 MB. Up to 3 rotated files are kept:

~/.local/share/macpmd/logs/my-app.log      # Current log
~/.local/share/macpmd/logs/my-app.log.1    # Previous
~/.local/share/macpmd/logs/my-app.log.2    # Older
~/.local/share/macpmd/logs/my-app.log.3    # Oldest

The logs command reads across all rotated files, so --lines 50 gives you the last 50 lines from the full history. Use --lines 0 to show all available log history.

info — Show process details

macpmd info <name> [<name> ...]
macpmd info --all
macpmd info <name> --json

Shows detailed information about one or more processes, including the full command and working directory.

# Show info for a single process
macpmd info my-app

# Show info for multiple processes
macpmd info my-app worker

# Show info for all processes as JSON
macpmd info --all --json
Option Description
--all, -a Show info for all processes
--json, -j Output as JSON

fix — Fix missing launchd plists

macpmd fix

Checks all running processes and reinstalls any missing launchd plists. This is useful if a plist was accidentally removed or if external interference caused a process to lose its plist.

Global Options

Option Description
--version Show version and exit
--license Show licence information and exit
--help Show help and exit

File Locations

Path Purpose
~/.local/share/macpmd/state.json Process state and configuration
~/.local/share/macpmd/logs/<name>.log Process stdout/stderr
~/Library/LaunchAgents/com.macpmd.<name>.plist launchd plist (standard processes)
/Library/LaunchDaemons/com.macpmd.<name>.plist launchd plist (sudo processes)