Monitor ports, discover local app daemons, proxy traffic, and kill processes — from the macOS menu bar or a rich terminal UI on any platform. With first-class support for SSH, Kubernetes, and Cloudflare tunnels.
Port conflicts kill developer flow. PortPilot gives you instant visibility into every listening port and every local app daemon on your machine.
Unlike basic lsof wrappers, PortPilot:
- Classifies processes as System, App, or Developer Tool — so you see what matters
- Detects tunnels — SSH forwards,
kubectl port-forward, Cloudflare tunnels with meaningful names - Discovers Unix sockets — local daemons like databases, dev servers, custom services
- Proxies traffic — native TCP proxy built on Apple's Network.framework
- Lives in your menu bar — no Dock icon, zero distraction
A glass-panel dropdown anchored to the menu bar with a unified, theme-synced design:
- Header — PortPilot branding with refresh, settings, and more actions
- Live stats — Active ports, Sockets, and Connections counts with pulsing status dot
- Integrated search — Filter by port number, PID, or process name (Cmd+F hint)
- Protocol filters — All / TCP / UDP toggle chips
- Source filters — Local / Database / OrbStack / Tunnels
- Top Activity — Top ports ranked by CPU + memory usage with See All toggle
- List View — Ports grouped by connection type (Local, Database, Kubernetes, Cloudflare, SSH)
- Tree View — Ports grouped by process name with expandable sections showing individual ports
- Schedules — Cronjobs (user + system) with schedule, command, next-run time
- Port rows — Port number, protocol badge, process name, PID, memory/CPU badges, hover kill/copy actions
- More menu — Refresh, Kill All (with confirmation), Settings, Quit
- Footer — Open PortPilot App / Tree View toggle + Sponsor link with author credit
- No Dock icon — pure menu bar accessory app
Open via menu bar → "Open PortPilot"
- Port list with filter pills (TCP/UDP/Unix, Web/Database/Dev/System/Favorites)
- CPU usage — inline CPU % badge per process, color-coded by load
- Configuration panel — connection details, process class, PID, uptime, CPU, CWD, port mapping
- Quick Proxy — start/stop TCP proxy for any port from the config panel
- Port flow visualization — ASCII diagram showing traffic path
- Logs panel — activity log with per-port filtering
- Favorites, history, custom programs, reserved ports
Fully customizable look and feel — Settings uses the same Liquid card design as the dropdown:
- 6 color themes — Classic, Graphite, Sunset, Oceanic, Noir, Retro — each with a recommended font pairing
- Theme sync — dropdown, settings panel, and main window all use the same theme-derived colors
- Custom fonts — pick any system font for UI and monospaced text, or drop
.ttf/.otffiles into theFonts/folder - Font size — adjustable from 9px to 18px, applied consistently across all views
- Settings panels — Liquid glass card design with themed sections, accent-colored icons, and sponsor link
| Theme | Character | Recommended Fonts |
|---|---|---|
| Classic | Vibrant and balanced | System Default + System Monospaced |
| Graphite | Calm and professional | SF Pro + SF Mono |
| Sunset | Warm and expressive | Avenir Next + Menlo |
| Oceanic | Deep and focused | SF Pro Rounded + SF Mono |
| Noir | Sharp and minimal | Helvetica Neue + Fira Code |
| Retro | Warm and nostalgic | American Typewriter + Courier New |
Built on Apple's Network.framework (NWListener + NWConnection):
- Forward traffic between any local ports
- Bidirectional relay with byte counting
- Start/stop from the Configuration panel
- Active proxy indicator with "Stop All"
Uses proc_pidpath to resolve executable paths and classify by heuristic:
| Type | Examples | How detected |
|---|---|---|
| System | mDNSResponder, WindowServer, launchd | /System/, /usr/libexec/, known daemons |
| Developer | node, postgres, docker, nginx, redis | Homebrew paths, known dev tools |
| App | Electron apps, .app bundles | /Applications/, .app/ in path |
| Other | Unclassified | Fallback |
Suspicious connections are flagged by matching against ~/.portpilot/blocklist.txt:
# ~/.portpilot/blocklist.txt — one domain, IP, or CIDR per line
upload.dev
52.45.119.88
192.168.1.0/24
2a06:98c1:310b
Supports:
- Exact domain/IP matching
- Domain suffix matching (
.evil.commatchescdn.evil.com) - IPv6 prefix matching
- CIDR ranges
- Blocklisted connections show 🚨 in CLI, TUI, and menu bar
A full-featured terminal interface — works on macOS, Linux, and WSL. Zero dependencies.
portpilot-tui╭─────────────────────────────────────────────────────────────────────────╮
│ PortPilot TUI Linux │
│ Ports Sockets Connections Schedules │
│─────────────────────────────────────────────────────────────────────────│
│ PORT PROTO PID CPU% MEM USER COMMAND TYPE │
│ ───────────────────────────────────────────────────────────────────── │
│ 3000 TCP 12345 0.3 45M user node Web │
│▸ 5432 TCP 789 1.2 120M postgres postgres DB │
│ 8080 TCP 4567 5.1 300M user java Web │
│ 6379 TCP 1122 0.1 8M redis redis DB │
│ 9090 TCP 3344 0.0 15M user grafana Web │
│ ░░ │
│ ░░ │
├─────────────────────────────────────────────────────────────────────────┤
│ ↑↓/jk Navigate │ Enter Kill │ / Search │ Tab Switch │ i Info │ q Quit │
│ 5 process(es) on Linux │
╰─────────────────────────────────────────────────────────────────────────╯
Keybindings:
| Key | Action |
|---|---|
↑↓ / j k |
Navigate |
Enter |
Kill process (with confirmation) |
/ |
Search / clear filter |
Tab |
Switch between Ports, Sockets, Connections, Schedules tabs |
i |
View detailed process info + connections |
r |
Refresh |
q |
Quit |
Connections tab shows all established outbound connections grouped by process with blocklist 🚨 markers.
Schedules tab shows cronjobs (user + system) with next-run calculation.
Detail View — press i on any port:
╭ Process Info ──────────────────────────────────────────╮
│ Port: 5432 │
│ Protocol: TCP │
│ PID: 789 │
│ User: postgres │
│ Command: postgres │
│ CPU: 1.2% │
│ Memory: 120M │
│ Path: /usr/lib/postgresql/15/bin/postgres │
│ Work Dir: /var/lib/postgresql/15/main │
╰────────────────────────────────────────────────────────╯
╭ Connections (3) ───────────────────────────────────────╮
│ LOCAL ADDRESS REMOTE ADDRESS STATE │
│ 127.0.0.1:5432 127.0.0.1:48210 ESTABLISHED│
│ 127.0.0.1:5432 127.0.0.1:48212 ESTABLISHED│
│ *:5432 *:* LISTEN │
╰────────────────────────────────────────────────────────╯
Esc Back │ x Kill │ X Force Kill │ q Quit
portpilot list # All listening ports (with CPU%)
portpilot list --start 3000 --end 9999 # Port range
portpilot list --proto tcp --json # JSON output (includes cpuUsage)
portpilot kill 5173 --force # Kill by port
portpilot kill :8080 # Colon prefix syntax
portpilot pid 8080 # Get PID for port
portpilot pids 3000 3001 3002 # Multiple PIDs
portpilot connections # All established connections (grouped by process)
portpilot connections --suspect # Only processes with >50 connections
portpilot connections --kill 12345 # Kill process by PID
portpilot connections --json # JSON output
portpilot schedules # User + system cronjobs
portpilot schedules --json # JSON output
portpilot interactive # TUI mode
portpilot proxy --port 1080 --host user@server # SOCKS proxyCLI table output includes CPU%, memory, and project/source info:
PORT PROTO PID CPU% MEM USER COMMAND PATH/PROJECT
3000 TCP 21082 0.0 45M user node wooosh/client
5432 TCP 63341 9.4 120M user postgres postgresql/15/main
8080 TCP 4567 5.1 300M user java my-api/server
Connections output with blocklist detection:
REMOTE PROCESS PID USER STATE COUNT
52.45.119.88:443 node 12345 user ESTABLISHED 1847 🚨
54.210.12.45:443 chrome 999 user ESTABLISHED 23
...
Schedules output:
SCHEDULE NEXT RUN USER COMMAND SOURCE
@hourly 04-03 14:00 user /usr/bin/some-script.sh user
*/5 * * * * 04-03 13:35 root /usr/bin/monitoring.sh /etc/cron.d/sys
For end users, the easiest path is the Releases page:
- Download
PortPilot-macOS-app.zip - Unzip it
- Move
PortPilot.appto/Applications
The release currently attaches:
PortPilot-macOS-app.zipportpilot-macos-cliSHA256SUMS.txt
git clone https://github.com/sriinnu/portpilot.git
cd portpilot
npm run releaseThis builds everything and installs:
PortPilot.app→/Applications/(menu bar app)portpilotCLI →/usr/local/bin/portpilot-tui→/usr/local/bin/(terminal UI)
portpilot list # CLI: list all listening ports
portpilot-tui # TUI: full interactive terminal UI1. Install Swift (if not already installed):
curl -L https://swiftlang.github.io/swiftly/swiftly-install.sh | bash
source ~/.profile # or restart your shell
swiftly install latest
swift --version # verify: should show Swift 6.xSee the official Swiftly Getting Started guide for details.
2. Build & install:
git clone https://github.com/sriinnu/portpilot.git
cd portpilot
npm run setup:linux # builds CLI + TUI and installs to /usr/local/binOr step by step:
npm run build:all:linux
sudo cp .build/release/portpilot /usr/local/bin/
sudo cp .build/release/portpilot-tui /usr/local/bin/3. Use it:
portpilot list # all listening ports with project paths
portpilot tui # launch rich terminal UI
portpilot-tui # direct launch
portpilot kill 8080 # kill by portRequires Swift for Windows:
git clone https://github.com/sriinnu/portpilot.git
cd portpilot
swift build -c release --product portpilot
copy .build\release\portpilot.exe "C:\Program Files\PortPilot\"Uses netstat + tasklist automatically:
portpilot list # all listening ports
portpilot kill 5000 --force # force kill
portpilot list --json # pipe to toolsNote: The TUI (
portpilot-tui) requires a POSIX terminal and works on macOS, Linux, and WSL. On Windows, use WSL or the CLI directly.
No config, no setup, no runtime dependencies. Platform detection is automatic — same interface everywhere.
# macOS
npm run build # Build macOS app (xcodebuild)
npm run release # Build all + install app/CLI/TUI
# Linux / WSL
npm run setup:linux # One-command: build + install CLI + TUI
npm run build:all:linux # Build CLI + TUI only
# Common
npm run build:cli # Build CLI
npm run build:tui # Build TUI
npm run install:cli # Install CLI to /usr/local/bin
npm run install:tui # Install TUI to /usr/local/bin
npm run uninstall # Remove everything
npm run clean # Remove build artifacts| Platform | GUI App | TUI | CLI | Port Discovery | Install |
|---|---|---|---|---|---|
| macOS 13+ | Menu bar + window | portpilot-tui |
portpilot |
lsof + proc_pidpath |
npm run release |
| Linux | - | portpilot-tui |
portpilot |
ss |
npm run build:all:linux |
| WSL | - | portpilot-tui |
portpilot |
ss |
npm run build:all:linux |
| Windows | - | via WSL | portpilot |
netstat + tasklist |
swift build -c release |
| Shortcut | Action |
|---|---|
Cmd+R |
Refresh ports |
Cmd+F |
Search |
Cmd+, |
Settings |
Sources/
├── PortPilot/ # macOS menu bar app (SwiftUI + AppKit)
│ ├── PortPilotApp.swift # Pure AppKit entry (no Dock icon)
│ ├── ContentView.swift # Main window layout
│ ├── PortViewModel.swift # State, filtering, tunnel detection
│ ├── MenuBarController.swift # Status item + panel management
│ ├── MenuBarDropdownView.swift # Liquid display dropdown (Top Activity, List/Tree View, Schedules)
│ ├── MenuBarPanel.swift # Floating NSPanel
│ ├── PortListPanel.swift # Port list with classification badges
│ ├── ConfigurationPanel.swift # Config + proxy controls
│ ├── MainWindowToolbar.swift # Toolbar with filter pills
│ ├── LogsPanel.swift # Activity logs
│ ├── Theme.swift # 6 color themes + Liquid display tokens
│ ├── FontManager.swift # Custom font loading
│ ├── SettingsView.swift # Liquid card settings (appearance, fonts, themes)
│ └── AppSettings.swift # UserDefaults + font/theme settings
├── TerminalTUI/ # Reusable TUI engine (zero dependencies)
│ ├── Terminal.swift # Raw mode, terminal size, cursor, alt screen
│ ├── ANSI.swift # Escape codes — 16/256/TrueColor, styles
│ ├── KeyEvent.swift # Key reading — arrows, ctrl, UTF-8, escape seqs
│ ├── Screen.swift # Double-buffered diff renderer
│ ├── Widget.swift # Widget protocol + geometry types
│ ├── Box.swift # Bordered container (4 border styles)
│ ├── Table.swift # Scrollable table with columns + selection
│ ├── StatusBar.swift # Bottom bar with keybinding hints
│ └── App.swift # TUIApp event loop + screen stack
├── PortPilotTUI/ # Terminal UI app (macOS + Linux + WSL)
│ ├── main.swift # Entry point
│ ├── PortListScreen.swift # Port/Socket/Connection/Schedule tables, search, kill
│ ├── PortDetailScreen.swift # Process info + connections
│ ├── ConnectionDetailScreen.swift # Connection remote details, kill option
│ └── CronjobDetailScreen.swift # Cronjob schedule info, next run
├── PortManagerLib/ # Shared library (all platforms)
│ ├── PortManager.swift # Port + socket + connection + cronjob discovery
│ ├── ProcessClassifier.swift # proc_pidpath classification
│ ├── TCPProxyManager.swift # Network.framework TCP proxy
│ ├── PortWatcher.swift # Port monitoring
│ ├── FavoritesManager.swift # Favorites
│ └── HistoryManager.swift # Kill history (thread-safe)
├── PortKillerCLI/ # CLI tool
│ ├── CLI.swift # Argument parsing
│ └── InteractiveMode.swift # Basic interactive mode
└── Fonts/ # Drop .ttf/.otf here for custom fonts
- Swift 5.9 + SwiftUI — native macOS UI
- AppKit — menu bar, NSWindow management
- TerminalTUI — custom zero-dependency TUI engine (ANSI rendering, key handling, widget system)
- Network.framework — TCP proxy (NWListener + NWConnection)
- CoreText — runtime font registration from custom font files
- proc_pidpath — process classification via executable path (with bounds-checked buffer)
- Thread safety — NSLock on shared caches; process execution with 10s timeout
TerminalTUI is a standalone, zero-dependency Swift library. Add it to your Package.swift:
dependencies: [
.package(url: "https://github.com/sriinnu/portpilot.git", from: "3.0.0"),
],
targets: [
.executableTarget(
name: "MyApp",
dependencies: [.product(name: "TerminalTUI", package: "portpilot")]
),
]import TerminalTUI
struct MyScreen: TUIScreen {
mutating func render(into screen: inout Screen) {
screen.put(row: 0, col: 0, text: "Hello, TUI!", style: ANSI.bold + ANSI.fg(.cyan))
}
mutating func handleKey(_ key: KeyEvent) -> ScreenAction {
key == .char("q") ? .quit : .continue
}
}
let app = TUIApp(screen: MyScreen())
app.run()MIT — see LICENSE for details.
© Srinivas Pendela 2024–2026. All rights reserved.