When I have several coding agents working in parallel, dev servers and test runners keep starting up on different ports. By the end of the day there are always a few still running.
Existing tools are either too much, or only tell you "port in use" without saying which process it is or which project it came from.
So I made LeftOpen. It sits quietly in the menu bar and shows you the listening ports, the processes behind them and the projects they probably belong to. Once you've had a look, you close the ones you no longer need.
Close the doors that were left ajar, gently.
brew install --cask songhaifan/tap/leftopenSigned with a Developer ID and notarized by Apple; opens directly on macOS Sonoma (14.0+).
Get LeftOpen.zip from GitHub Releases, unzip, and move LeftOpen.app to /Applications.
- Knows whose port it is. Walks up from the process's working directory to
.git,package.json,pyproject.toml,Cargo.tomlorgo.mod, or resolves the owning.app. Global npm packages,python -mmodules and standalone services (Redis, Postgres, Ollama…) are named too, so you rarely see a barenodeorpython. - Real icons, nothing bundled. Uses the
.appicon when there is one; otherwise the icon the project or package ships itself (Tauri/Electron app icon, the favicon declared inindex.html,public/conventions); otherwise the favicon served by the local server; otherwise a symbol. - Closable first. Ports you can close come first; apps and system services are folded away. The menu bar icon is an open or closed door, and every row shows how long the process has been running.
- Closes gently. Shows the process's other ports before you confirm, re-checks PID and start time at the moment of closing, sends
SIGTERMonly. NeverSIGKILL, never system processes. - Local vs LAN. Tells apart ports bound to
127.0.0.1from ones on0.0.0.0or a LAN address. - Nothing running in the background. Native SwiftUI
MenuBarExtra. No daemon, no Dock icon, no telemetry. - Same engine in the terminal. The app ships a
leftopenCLI with identical inference and safety rules.
Available in the terminal right after installing:
# List every listening port and its owner (or: leftopen list)
leftopen
# Explain one port
leftopen 3000
# Open http://localhost:3000 in the default browser
leftopen open 3000
# Close the process on a port (SIGTERM, asks first)
leftopen close 3000
# Structured JSON output
leftopen --jsonSample output:
LEFT OPEN
26 listening ports · 17 processes · 1 projects · 8 LAN-visible
MY PROJECTS (2)
PORT PID OWNER PROCESS AGE SCOPE
5173 76344 visdelta node 2h LOCAL
↳ ~/Documents/visdelta
5511 4999 visdelta node 27m LOCAL
↳ ~/Documents/visdelta
APPLICATIONS (16)
PORT PID OWNER PROCESS AGE SCOPE
5000 696 ControlCenter Control 3d LAN
9222 36824 Google Chrome Chrome 5h LOCAL
SERVICES (3)
PORT PID OWNER PROCESS AGE SCOPE
11434 911 Ollama ollama 1d LOCAL
LOCAL = this Mac only · LAN = may be reachable from your local network
# Swift tests
swift test
# CLI prototype tests
npm test
# Build the app locally
LEFTOPEN_OUTPUT_DIR=dist/dev Scripts/build-app.sh