Monitor ports, discover local app daemons, proxy traffic, and kill processes — from the macOS menu bar or a terminal UI on any platform. Detects SSH forwards, Kubernetes port-forwards, and Cloudflare tunnels.
PortPilot inspects listening ports and local app daemons on the machine. Compared to a plain lsof wrapper, it:
- Classifies processes as System, App, or Developer Tool
- Detects tunnels — SSH forwards,
kubectl port-forward, Cloudflare tunnels - Discovers Unix sockets — local daemons like databases, dev servers, custom services
- Proxies traffic — native TCP proxy built on Apple's Network.framework
- Runs as a menu bar accessory on macOS (no Dock icon) with a terminal UI and CLI on every platform
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
brew install --cask sriinnu/tap/portpilotInstalls PortPilot.app to /Applications. Cask source: sriinnu/homebrew-tap. This installs only the menu bar app — for the CLI/TUI, build from source below.
Manual install from 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 |
Four Swift targets: PortPilot (macOS menu bar app), TerminalTUI (zero-dependency TUI engine), PortPilotTUI (the TUI app built on it), and PortManagerLib (shared port/socket/connection/cronjob discovery used by app, TUI, and CLI). Full source tree and tech stack: ARCHITECTURE.md.
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.