PortWatch

Software

PortWatch

Dev ports at a glance.

All Projects

Juggling six or seven dev servers across multiple projects means port collisions, zombie processes eating memory, and the occasional “why is port 3000 already in use?” interruption. The answer was always the same: run lsof, parse the output, find the PID, kill it. Every time.

PortWatch lives in the macOS menu bar and does that loop automatically every three seconds. It resolves project names from package.json, shows live CPU and memory stats per process, and lets you open, pause, or kill any server with a single click. A JSON sidecar means other tools — Claude Code, shell scripts, tmux status bars — can read the same data without re-scanning.

0
Whitelisted Processes
node, python, ruby, go + 30 more
0
Scan Interval
lsof polling cycle
0
Active Ports
Current session avg
0
Forgotten Servers
When PortWatch runs

Process whitelist from PortWatch source. Session data from typical development workflow.

Menu Bar Popover

Every listening dev port with its project name, framework, and resource usage. Hover any row to reveal inline controls — open in browser, pause via SIGSTOP, or kill with SIGTERM.

PORTS
3000shipyard(next)
2%148M
3001@clearspend/server(node)
0%11M
3100app(next)
0%13M
5173mishtok(node)
1%37M
5174@clearspend/web(vite)
0%7M
8081blog(node)
0%12M
SESSIONS
claude · shipyard
12%1.2G
node
3%256M
idle
0%48M
portwatch
kill allquit

Hover or tap a port row to reveal process controls.

Icon

Geometric antenna motif that matches the macOS menu bar icon. Signal arcs pulse on a three-second cycle — the same interval as the port scanner.

Signal arcs animate on a 3-second scan cycle.

CLI Companion

A bash script that reads the JSON sidecar for instant results when the app is running, and falls back to direct lsof scanning when it is not.

Terminal — port-watch
$ port-watch
PROCESSPORTPID
──────────────
node300012345
node300123456
node310034567
node517345678
node517456789
node808167890

CLI output from the port-watch command.

JSON Sidecar

Every scan cycle writes atomically to ~/.port-watch/ports.json. Other tools consume the data without re-scanning — no duplicate lsof calls, no parsing overhead.

~/.port-watch/ports.json
{
"timestamp": "2026-05-05T21:38:29Z",
"ports": [
{
"port": 3000,
"process": "node",
"pid": 12345,
"projectName": "shipyard",
"serverLabel": "next",
"cpuPercent": 2.3,
"memMB": 148.5
}
]
}
Consumers
Claude Code
Reads ports.json to avoid conflicts when starting dev servers
Custom Scripts
CI/CD hooks that verify required services are running
Tmux Status Bar
Displays active port count in terminal status line

JSON sidecar and its consumers.

Built With

A Swift Package using NSStatusBar and NSPopover for the menu bar item, with SwiftUI views inside the popover. Compatible across macOS 13 through macOS 26.

SwiftAppKitSwiftUImacOSNSStatusBarNSPopoverlsofCLI
View on GitHub