Software teams rarely lose hours only to large architecture decisions. They also lose time when a local API cannot start, a CI runner waits for a process, or an unknown listener blocks port 3000. proc gives a single command grammar for those daily process tasks on macOS, Linux, and Windows. A target can be a listener on port 3000, one PID 1234, a process name such as node, or a file path such as ./server.py. Before state changes, it asks; --dry-run gives a preview.
The delivery workflow is easier to repeat when process work uses one consistent surface: inspect, trace, stop, free, freeze, watch, and wait. Instead of switching between tools, flags, and fragile pipes, teams can describe the target once, confirm the action, and move on. Version 1.14.5 is available through brew, npm, cargo, Scoop, Nix, and Docker, so adoption does not depend on a single runtime or package manager.
:3000 is a port selector. It points proc at the listener on port 3000. When paired with kill, that listener is stopped with SIGKILL; the tool asks before changing state, and --dry-run supplies a preview.1234 is a PID selector. Only PID 1234 is affected, and no other process is touched.node is a name selector. proc matches it against process names and full command lines, so nodemon and node server.js are also included. With kill, every match is listed and ended only after confirmation.:3000,:8080,node is a comma-separated target group. All listed selectors are handled together after one confirmation. If one process matches more than one selector, it is still acted on only once.node --in . narrows node targets to the current folder and its subfolders. This prevents the editor or another project from being affected. Most commands accept --in../server.py is a file selector for proc for. The path can be relative, absolute, or start with ~. It finds processes running server.py from this folder../logs/app.log is also a file selector for proc for. It finds processes that have app.log open, such as a server that continues writing to the file.on is the first habit for risky process work. When the target is :3000, it reports the process listening on port 3000, together with name, PID, folder, CPU, memory, and running time. When the target is 1234, it reports PID 1234 and every port it listens on. When the target is node, it reports each matching process and its ports. With :3000,:8080,node, it answers all three at once: what is on port 3000 and port 8080, and which ports node processes hold. With node --in ., it reports only node processes started in this folder and their ports.
why walks the parent chain. With :3000, why moves back from the listener on port 3000 and reveals the start point, such as a terminal tab, tmux session, or editor. With 1234, it lists the parent chain that produced PID 1234, plus each parent's running time. With node, it traces every matching node process to whatever started it. With :3000,:8080, it returns one parent chain for each held port.
for is used when the target is a file. ./server.py finds processes running server.py from this folder. ./logs/app.log finds processes that have app.log open, for example a server that is still writing to it. by is used for name matching. node lists every process whose name or command line matches node. node --in . restricts that list to the current folder and below. in is used for folder matching. . lists everything started in the folder you are in. ~/code/shop lists everything started in ~/code/shop, wherever you run the command, even if that folder was later deleted.
list with no target walks through every process, sorted by highest resource use first. Adding node filters to matching processes. --status zombie returns zombie processes: exited work not cleaned up by its parent. --status accepts running, sleeping, stopped, or zombie. info 1234 returns folder, path, user, parent, status, CPU, memory, and uptime for PID 1234. info :3000 returns full details for the listener on port 3000. info node returns full details for every matching process. ports lists every listening port and the process using it. --exposed narrows output to ports reachable by other machines, meaning ports listening on 0.0.0.0 or ::. --local keeps localhost ports. --in . narrows to ports held by processes started in this folder. tree prints every process as parents and children. node prints each node process and the processes it started. 1234 --ancestors reverses direction, going from PID 1234 upward to the first process the system started.
orphans finds processes whose parent has exited, such as dev servers left behind after a terminal closes. System services are omitted. With no target, it checks all parentless processes. --in . limits output to this folder. --in . --kill displays this folder's orphans, asks, and ends them. stuck locates busy long-running work. With no target, it finds processes running over 5 minutes that are currently using more than half a CPU. --kill ends the found stuck processes after display and confirmation.
kill is the direct end path. :3000 kills the listener on port 3000 with SIGKILL. 1234 kills only PID 1234. node kills all matching node processes after listing and confirmation. :3000,:8080,node kills every listed selector after one confirmation. node --in . kills only node processes located under the current folder.
stop asks the target to leave cleanly first. :3000 asks the listener on port 3000 to exit with SIGTERM, then forces it after 10 seconds if it remains. 1234 follows the same pattern for PID 1234. node gracefully stops every matching process after confirmation. node --in . stops only node processes under the current folder. :3000 --signal HUP sends HUP instead of SIGTERM, and many servers treat HUP as reload your config.
free is for ports only. :3000 politely and forcefully stops the process holding port 3000, then confirms the port is truly free. :3000,:8080 frees both ports in one operation. Commas combine ports.
freeze pauses without ending. On macOS and Linux, node sends SIGSTOP to every matching process. 1234 pauses PID 1234, useful for a heavy build while you need the machine back. :3000 pauses the listener, leaving connections hanging until thaw. thaw resumes. node resumes previously frozen node processes with SIGCONT. 1234 resumes PID 1234, regardless of whether proc freeze or Ctrl+Z paused it. unstick attempts recovery. With no target, it finds stuck processes, wakes them with SIGCONT, and interrupts them like Ctrl+C; nothing is terminated unless --force is supplied. 1234 attempts the same gentle recovery for that PID. node --force falls back to terminating stuck node processes with SIGTERM, then SIGKILL.
watch is the continuous view. With no target, it displays a busy-first table refreshed every 2 seconds; q quits. node monitors only node processes. :3000 monitors the listener on port 3000.
wait prevents scripts from moving on too early. :3000 waits until the process on port 3000 has exited, letting scripts launch the next server. 1234 waits for PID 1234. node --timeout 60 abandons the wait after 60 seconds if node processes remain, preventing CI from hanging. --timeout exits 1 when it gives up.
Every command shares the same target forms. Almost all commands support --in for project scoping, --json for machine-readable output, and --dry-run to preview changes. Listing flags, such as --status and --exposed, narrow search results. --kill applies the listed command's action to discovered processes and asks first, like proc kill. proc covers nineteen commands across three jobs.
The same jobs can be done with lsof, ps, grep, pgrep, xargs, kill, and sleep, but proc removes the need to remember lsof flags or pipe PIDs into kill.
| Task | Shell pipeline | proc command |
|---|---|---|
| What is on port 3000? | lsof -i :3000 -P -n | proc on :3000 |
| Why is it there? | lsof -i :3000, then ps -o ppid= up the chain | proc why :3000 |
| Free the port | lsof -t -i:3000 | xargs kill && sleep 1 && lsof -i:3000 | proc free :3000 |
| Wait for it to exit | while ps aux | grep node | grep -v grep; do sleep 5; done | proc wait node |
| Pause a process | kill -STOP $(pgrep node) | proc freeze node |
| Find leftovers | No standard tool | proc orphans --in . |
Install by running brew install yazeed/proc/proc; Version 1.14.5 also reaches users through npm, cargo, Scoop, Nix, and Docker.
A common delivery interruption happens when a developer cannot start a local API because port 3000 is already taken. proc can locate the old tmux session that holds it, release port 3000, and clean up the other processes left running.
The tool is aimed at scripts and coding agents. Each command emits one JSON document with --json, and exit codes are fixed: 0 success, 1 error, 2 not found, 3 permission denied, 4 invalid input. --dry-run only identifies what would be touched. The agent skill teaches Claude Code, Codex, Cursor, Gemini CLI, and others when to use proc. In the example proc on :8080 --json | jq '.process | {pid, cwd, uptime_secs}', the sample values are pid 177, cwd /home/dev/code/shop, and uptime_secs 35.
--in . when the target should be limited to the current project folder.--timeout 60 and handle the failed wait through exit code 1.--in . when several node processes may exist across folders.A leading colon means a port. The selector :3000 targets the listener on port 3000.
A bare number means a PID. The selector 1234 targets only PID 1234.
proc compares the name against process names and full command lines, so node also finds nodemon and node server.js.
Yes. Use --dry-run to preview what would be touched before any process state is changed.