p.enthalabs

proc

Target processes by port, PID, name or path.

proc is a semantic CLI tool for process management on macOS, Linux and Windows. Find what's on a port, why it's there, and stop it, in one command you'd guess on the first try.

~proc kill:3000

Ends whatever is listening on port 3000 immediately (SIGKILL). Asks first, and `--dry-run` previews.

A leading colon means a port: proc acts on whatever is listening on it.

Command

Target

:3000 Shows what's listening on port 3000: its name, PID, folder, CPU, memory and how long it has been running.

A leading colon means a port: proc acts on whatever is listening on it.

1234 Works the other way too: shows process 1234 and every port it listens on.

A number is a PID: that one process and nothing else.

node Shows each `node` process and the ports it listens on.

Anything else is a name, matched against each process's name and full command line, so `node` also finds `nodemon` and `node server.js`.

:3000,:8080,node Answers all three at once: what's on ports 3000 and 8080, and which ports the `node` processes hold.

Commas combine targets. A process matched twice is only acted on once.

node --in . Shows only the `node` processes started in this folder, and their ports.

`--in` keeps any target inside a folder and the folders below it. Most commands take it.

:3000 Traces what's on port 3000 back through its parent processes, so you see what started it: a terminal tab, a tmux session, your editor.

A leading colon means a port: proc acts on whatever is listening on it.

1234 Shows the chain of parents that led to process 1234, with how long each one has been running.

A number is a PID: that one process and nothing else.

node Traces every `node` process back to whatever started it.

Anything else is a name, matched against each process's name and full command line, so `node` also finds `nodemon` and `node server.js`.

:3000,:8080 Traces what holds ports 3000 and 8080, one chain each.

Commas combine targets. A process matched twice is only acted on once.

./server.py Finds the processes running `server.py` from this folder.

With `proc for`, the target is a file: relative, absolute or starting with `~`.

./logs/app.log Finds whatever has `app.log` open, such as a server that's still writing to it.

With `proc for`, the target is a file: relative, absolute or starting with `~`.

node Lists every process whose name or command line matches `node`.

Anything else is a name, matched against each process's name and full command line, so `node` also finds `nodemon` and `node server.js`.

node --in . The same, limited to processes started in this folder.

`--in` keeps any target inside a folder and the folders below it. Most commands take it.

. Lists everything started in this folder or below it.

With `proc in`, the target is a folder. `.` is the one you're in.

~/code/shop Lists everything started in `~/code/shop`, wherever you run it from, even after the folder has been deleted.

With `proc in`, the target is a folder. `.` is the one you're in.

no target Lists every process, busiest first.

No target: proc looks at every process.

node Lists only the processes matching `node`.

Anything else is a name, matched against each process's name and full command line, so `node` also finds `nodemon` and `node server.js`.

--status zombie Lists zombie processes: ones that have exited but haven't been cleaned up by their parent.

Flags narrow any listing. `--status` takes running, sleeping, stopped or zombie.

1234 Shows everything about process 1234: folder, path, user, parent, status, CPU, memory and uptime.

A number is a PID: that one process and nothing else.

:3000 Shows everything about whatever is listening on port 3000.

A leading colon means a port: proc acts on whatever is listening on it.

node Shows the full details of each `node` process.

Anything else is a name, matched against each process's name and full command line, so `node` also finds `nodemon` and `node server.js`.

no target Lists every listening port and the process behind it.

No target: proc looks at every listening port.

--exposed Only the ports other machines can reach, the ones worth checking.

`--exposed` keeps ports listening on 0.0.0.0 or ::, and `--local` the localhost ones.

--in . Only the ports held by processes started in this folder.

`--in` keeps any target inside a folder and the folders below it. Most commands take it.

no target Shows every process as a tree of parents and children.

No target: proc looks at every process.

node Shows each `node` process with the processes it started.

Anything else is a name, matched against each process's name and full command line, so `node` also finds `nodemon` and `node server.js`.

1234 --ancestors Goes up instead of down: from process 1234 to the first process the system started.

A number is a PID. `--ancestors` turns the tree upside down.

no target Finds processes whose parent has exited, like dev servers left behind by a closed terminal. System services are left out.

No target: proc looks at every process whose parent has gone.

--in . Only the orphans started in this folder.

`--in` keeps any target inside a folder and the folders below it. Most commands take it.

--in . --kill Ends this folder's orphans, after showing the list and asking.

`--kill` acts on what was found, and asks first like `proc kill`.

no target Finds processes running for over 5 minutes that stay busy (more than half a CPU) or blocked across two readings a second apart.

No target: proc looks at every process.

--kill Ends the stuck processes, after showing the list and asking.

`--kill` acts on what was found, and asks first like `proc kill`.

:3000 Ends whatever is listening on port 3000 immediately (SIGKILL). Asks first, and `--dry-run` previews.

A leading colon means a port: proc acts on whatever is listening on it.

1234 Ends process 1234 immediately, and nothing else.

A number is a PID: that one process and nothing else.

node Ends every `node` process, after listing them and asking.

Anything else is a name, matched against each process's name and full command line, so `node` also finds `nodemon` and `node server.js`.

:3000,:8080,node Ends all of them in one go, after one confirmation.

Commas combine targets. A process matched twice is only acted on once.

node --in . Ends only this folder's `node` processes, not your editor's or another project's.

`--in` keeps any target inside a folder and the folders below it. Most commands take it.

:3000 Asks whatever is on port 3000 to exit (SIGTERM), so it can clean up, and forces it after 10 seconds if it hasn't.

A leading colon means a port: proc acts on whatever is listening on it.

1234 Stops process 1234 the same way: politely first, by force only if needed.

A number is a PID: that one process and nothing else.

node Stops every `node` process gracefully, after asking.

Anything else is a name, matched against each process's name and full command line, so `node` also finds `nodemon` and `node server.js`.

node --in . Stops only the `node` processes started in this folder.

`--in` keeps any target inside a folder and the folders below it. Most commands take it.

:3000 --signal HUP Sends HUP instead of SIGTERM, which many servers take as “reload your config”.

A leading colon means a port. `--signal` picks the first signal sent.

:3000 Ends whatever holds port 3000, politely and then by force, and waits until the port is really free before saying so.

A leading colon means a port: proc acts on whatever is listening on it.

:3000,:8080 Frees both ports in one go.

`proc free` only takes ports. Commas combine them.

node Pauses every `node` process (SIGSTOP) without ending them, until you thaw them. macOS and Linux.

Anything else is a name, matched against each process's name and full command line, so `node` also finds `nodemon` and `node server.js`.

1234 Pauses process 1234, handy for a heavy build while you need the machine back.

A number is a PID: that one process and nothing else.

:3000 Pauses whatever is on port 3000. Connections to it hang until you thaw it.

A leading colon means a port: proc acts on whatever is listening on it.

node Resumes the `node` processes you froze (SIGCONT), right where they stopped.

Anything else is a name, matched against each process's name and full command line, so `node` also finds `nodemon` and `node server.js`.

1234 Resumes process 1234, whether `proc freeze` or Ctrl+Z paused it.

A number is a PID: that one process and nothing else.

no target Finds stuck processes and tries to recover them: wakes them (SIGCONT), then interrupts them like Ctrl+C. Nothing is ended without `--force`.

No target: proc looks at every process.

1234 Tries to recover process 1234 the same gentle way, if it's stuck.

A number is a PID: that one process and nothing else.

node --force If gentle recovery fails, ends the stuck `node` processes (SIGTERM, then SIGKILL).

Anything else is a name. `--force` allows ending it as a last resort.

no target A live table of every process, busiest first, refreshed every 2 seconds. Press q to quit.

No target: proc looks at every process.

node Watches only the `node` processes.

Anything else is a name, matched against each process's name and full command line, so `node` also finds `nodemon` and `node server.js`.

:3000 Watches whatever is on port 3000.

A leading colon means a port: proc acts on whatever is listening on it.

:3000 Waits until whatever is on port 3000 has exited, so a script can start the next server.

A leading colon means a port: proc acts on whatever is listening on it.

1234 Waits until process 1234 exits.

A number is a PID: that one process and nothing else.

node --timeout 60 Gives up after 60 seconds if the `node` processes are still running, so CI doesn't hang.

Anything else is a name. `--timeout` gives up after that many seconds and exits 1.

Video 3

A dev server won't start because port 3000 is taken. proc finds the old tmux session holding it, frees the port, then cleans up what else was left running.

One command instead of a pipeline

The same jobs, without remembering which flags `lsof` needs or piping PIDs into `kill`.

What's 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 .`

Nineteen commands, three jobs

Every command takes the same targets, and almost all take `--in` to stay inside one project, `--json` for scripts, and `--dry-run` before anything changes.

All commands and options

Made for scripts and coding agents

Every command prints one JSON document with `--json`, and exit codes always mean the same thing. An agent can read proc the way you do, without parsing tables.

- `0` success, `1` error, `2` not found, `3` permission denied, `4` invalid input

- `--dry-run` shows what would be touched, and nothing else

- The agent skill teaches Claude Code, Codex, Cursor, Gemini CLI and others when to reach for proc

``` ❯ proc on :8080 --json | jq '.process | {pid, cwd, uptime_secs}' { "pid": 177, "cwd": "/home/dev/code/shop", "uptime_secs": 35 } ```

Posts

All posts