portctl 0.1.1

Developer environment recovery tool -- detect, explain, and fix port conflicts
portctl-0.1.1 is not a library.

The Problem

Every developer hits this multiple times a week:

$ npm run dev
Error: listen EADDRINUSE: address already in use :::3000

Something crashed, a zombie process is holding your port. Now you're doing this:

lsof -i :3000
kill -9 <pid>     # was that PostgreSQL? oh no.

Fragile. Dangerous. Tells you nothing.


The Solution

One command. Two seconds.

$ portctl fix 3000

portctl identifies the process, confirms it's safe to kill, sends a graceful shutdown, verifies it's gone, and tells you how to restart.

$ portctl 3000

  ⚡ Port 3000 in use
  → Next.js (PID 81106)
  → running for 7m 21s
  → memory 42.9 MB
  → detected Next.js (95% confidence)
  → 🛡 safe to kill

  📂 Detected project: Next.js
  → dev command: npm run dev
  → default port: 3000

Old Way vs New Way

Scenario Old way portctl
Port 3000 in use lsof -i :3000 | awk ... | xargs kill -9 portctl fix 3000
What's on my ports? lsof -iTCP -sTCP:LISTEN (wall of text) portctl scan
Is it safe to kill? Google the process name portctl tells you automatically
How do I restart? Check package.json, guess portctl shows the restart command
Zombie processes Manually hunt each one portctl doctor -y
Which port is frontend? Check config files portctl group

Install

Homebrew

brew tap abhishekayu/tap
brew install portctl

Shell script (macOS / Linux)

curl -fsSL https://raw.githubusercontent.com/abhishekayu/portctl/main/install.sh | sh

Cargo

cargo install portctl

npm

npx portctl scan          # one-off, no install
npm install -g portctl    # permanent

From source

git clone https://github.com/abhishekayu/portctl.git
cd portctl && cargo install --path .

Demo

See everything on your ports

$ portctl scan

  ⚡ 5 active ports

  PORT    PROCESS                PID      SERVICE        MEMORY     UPTIME     USER
  ────────────────────────────────────────────────────────────────────────────────
  3000    node                   81106    Next.js        42.9 MB    7m 17s     abhishek
  3898    Code Helper (Plugin)   34290    Python         20.2 MB    3h 12m     abhishek
  5237    Code Helper (Plugin)   34073    Python         20.1 MB    3h 12m     abhishek
  5932    Code Helper (Plugin)   61773    Python         57.5 MB    58m 35s    abhishek
  42050   OneDrive Sync Serv..   36643    Unknown        14.4 MB    3d 1h      abhishek

Fix a port conflict in one command

$ portctl fix 3000

  ⚡ Port 3000 in use
  → Next.js (PID 81106)
  → detected Next.js (95% confidence)
  → 🛡 safe to kill

  🛡 SAFE  Next.js is a dev server -- safe to kill and restart
  ⚙ strategy: Graceful (SIGTERM + wait)

Fix port 3000 using Graceful (SIGTERM + wait)? [Y/n] y

  • Sending SIGTERM to PID 81106
  • Waiting up to 5s for graceful shutdown
  • Verified: PID 81106 has exited

  ✔ Killed safely  port 3000 is now free

  Restart: cd /Users/abhishek/project/web && npm run dev

Fix and auto-restart in one shot

$ portctl fix 3000 --run "npm run dev"

  ✔ Killed safely  port 3000 is now free

  🚀 Restarting: npm run dev

Error to recovery in under 3 seconds.

See ports grouped by role

$ portctl group --dev

  ⚡ 4 active ports in 2 groups

  ⚙ Frontend (2)
  ────────────────────────────────────────────────────────────────────────────
  3000    node                   81106    Next.js        42.9 MB    7m 21s     abhishek
  3898    Code Helper (Plugin)   34290    Python         20.2 MB    3h 12m     abhishek

  ⚙ Backend (2)
  ────────────────────────────────────────────────────────────────────────────
  5237    Code Helper (Plugin)   34073    Python         20.0 MB    3h 12m     abhishek
  5932    Code Helper (Plugin)   61773    Python         57.5 MB    58m 39s    abhishek

Auto-diagnose your dev environment

$ portctl doctor

  🩺 2 issues found

  1. Idle process Code Helper (PID 34290) at 0.0% CPU [auto-fixable]
     → Idle Code Helper on port 3898 -- consider killing to free resources
  2. Idle process Code Helper (PID 34073) at 0.0% CPU [auto-fixable]
     → Idle Code Helper on port 5237 -- consider killing to free resources

  ⚙ Run portctl doctor -y to auto-fix 2 issues

Commands

Command What it does
portctl scan List all listening ports with process info, service type, memory, uptime
portctl <port> Inspect a single port (shorthand for portctl info <port>)
portctl fix <port> Identify, classify, safely terminate, suggest restart
portctl fix <port> --run "cmd" Fix and auto-restart your dev server
portctl kill <port> Direct kill with safety checks and confirmation
portctl group Ports organized by role: frontend, backend, database, infra
portctl doctor Auto-diagnose stale servers, idle processes, port conflicts
portctl doctor -y Auto-fix all safe issues
portctl history View past actions with timestamps and outcomes
portctl history --stats Success rate, most killed port, most killed process
portctl project Detect project type and suggest dev commands
portctl ui Interactive TUI with arrow-key navigation

All commands support --json for scripting and CI integration.


Developer Workflows

Add to your package.json

{
  "scripts": {
    "dev": "portctl fix 3000 -y --run 'next dev'",
    "dev:clean": "portctl doctor -y && npm run dev"
  }
}

Now npm run dev always works, even if port 3000 is occupied from a previous crash.

Shell alias for instant recovery

# ~/.zshrc or ~/.bashrc
alias pf='portctl fix'
alias ps3='portctl fix 3000 -y --run "npm run dev"'
alias devclean='portctl doctor -y'

Pre-commit / CI check

# Ensure no stale dev servers before running tests
portctl doctor --json | jq '.[] | select(.auto_fixable)' && portctl doctor -y

Debug stuck servers

# What's actually holding port 8080?
portctl 8080

# See all dev ports organized by role
portctl group --dev

# Nuclear option: fix everything
portctl doctor -y

How It Works

portctl is not kill -9 with extra steps. It's a classification engine that understands your dev environment:

  1. Scan - queries the OS for all listening ports and resolves PIDs via sysinfo (no shell hacking)
  2. Classify - identifies the service: Next.js, Vite, Django, Docker, PostgreSQL, Redis, and 13+ categories
  3. Assess - runs safety checks: blocks system-critical processes, warns about databases, approves dev servers
  4. Strategy - selects the right approach: Graceful (SIGTERM + wait), Escalating (SIGTERM then SIGKILL), or Force
  5. Execute - sends signals, waits for exit, verifies the port is free, logs the action
  6. Recover - detects the project type, suggests the restart command, or auto-restarts with --run

Safety system

portctl will never blindly kill a process:

  • BLOCKED: PID 0/1, launchd, systemd, sshd, kernel_task (30+ system-critical processes)
  • WARNING: PostgreSQL, MySQL, Redis (data loss risk), Docker, Nginx (cascading effects)
  • SAFE: Next.js, Vite, Create React App, Django dev server, Flask, Node.js, Python scripts

Architecture

src/
  models/       PortInfo, ProcessInfo, DevService, ServiceKind
  platform/     macOS (lsof + libc) / Linux (/proc/net/tcp + libc) / Windows (netstat + taskkill)
  scanner/      Batch port scanning with sysinfo process resolution
  classifier/   13+ service classifiers with confidence scoring
  engine/       Fix engine: safety checks, strategy selection, SIGTERM/SIGKILL with retry
  project/      Filesystem project detection (package.json, Cargo.toml, pyproject.toml)
  docker/       Container awareness via docker ps
  grouping/     Port role classification (frontend/backend/database/infra)
  doctor/       Auto-diagnosis: stale servers, idle processes, crowded ports
  history/      Action log persisted to ~/.portctl/history.json
  plugin/       Extensible ServiceDetector trait for custom detectors
  cli/          Clap v4 commands + colored output + ratatui interactive TUI

Built in Rust. ~980KB binary. Zero runtime dependencies.


Comparison

kill-port fkill portctl
Identify what's running No Name only Full info (service, CWD, memory, uptime)
Safety assessment No No Yes (safe / warn / block)
Graceful shutdown No No Yes (SIGTERM first, escalate if needed)
Restart hints No No Yes (project-aware)
Auto-restart No No Yes (--run)
Docker awareness No No Yes
Auto-diagnosis No No Yes (doctor)
Port grouping No No Yes (by role)
Action history No No Yes
Interactive TUI No Yes Yes
Cross-platform Node.js Node.js Native binary (macOS + Linux + Windows)
Binary size ~50MB (node) ~50MB (node) ~980KB

Contributing

Contributions are welcome! portctl is open source and built by developers, for developers.

git clone https://github.com/abhishekayu/portctl.git
cd portctl
cargo build
cargo test

Ways to contribute:

  • Report bugs or request features via GitHub Issues
  • Add new service classifiers (Next.js, Vite, Django, and more)
  • Improve platform support (macOS, Linux, Windows)
  • Add new doctor diagnostics or fix strategies
  • Write or improve documentation

Please open an issue before starting major work so we can discuss the approach.

See CONTRIBUTING.md for detailed guidelines.


License

MIT -- free for personal and commercial use.