https://github.com/ntd4996/porthole
macOS menu bar app: see which dev ports are running, which project owns each, and which tunnels point where.
https://github.com/ntd4996/porthole
cloudflare-tunnel developer-tools devtools macos menubar ngrok ports swift swiftui
Last synced: about 1 month ago
JSON representation
macOS menu bar app: see which dev ports are running, which project owns each, and which tunnels point where.
- Host: GitHub
- URL: https://github.com/ntd4996/porthole
- Owner: ntd4996
- License: mit
- Created: 2026-06-03T15:03:06.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-06-04T06:38:23.000Z (about 1 month ago)
- Last Synced: 2026-06-04T07:10:12.143Z (about 1 month ago)
- Topics: cloudflare-tunnel, developer-tools, devtools, macos, menubar, ngrok, ports, swift, swiftui
- Language: Swift
- Homepage: https://ntd4996.github.io/Porthole/
- Size: 2.89 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README

# Porthole
**See which dev ports are running, which project owns each one, and which tunnels point where, right from your menu bar.**
[](https://github.com/ntd4996/Porthole/actions/workflows/ci.yml)
[](https://github.com/ntd4996/Porthole/releases/latest)
[](https://github.com/ntd4996/Porthole/releases/latest)
[](LICENSE)

## What it does
When you run a dozen dev servers across projects, `lsof -i` gets old fast. Porthole keeps a live list in your menu bar:
- **Running dev ports** with the process behind each one (`vite`, `next`, `prisma`, `uvicorn`…).
- **Which project owns the port**, resolved from the process working directory (git root / `package.json` / `go.mod` / `pyproject.toml`…), grouped per project.
- **Tunnels pointing at a port**, detected from ngrok, Cloudflare Tunnel, Tailscale, and localtunnel, with the public URL one click away.
- **Quick actions** per port: open `localhost:PORT` in the browser, copy the URL, or kill the process.
- **Ignore list** to hide noisy system services (ControlCenter, rapportd, …) so you only watch real dev ports. Seeded with sensible defaults; fully editable.
## Install
### Homebrew (recommended)
```bash
brew install --cask ntd4996/tap/porthole
```
### Direct download
Grab the latest signed & notarized `.dmg` from the [releases page](https://github.com/ntd4996/Porthole/releases/latest), open it, and drag Porthole to Applications.
Porthole lives in the menu bar (no Dock icon). Click the porthole icon to open the panel.
## How it works
Porthole shells out to standard tools and parses their output, no kernel extensions, no elevated privileges:
- `lsof -nP -iTCP -sTCP:LISTEN` for listening sockets, and `lsof … -d cwd` to find each process's directory.
- The ngrok local API (`127.0.0.1:4040`), the `cloudflared` / `lt` command lines, `~/.cloudflared/config.yml`, and `tailscale serve status` for tunnels. Public URLs are best-effort (Cloudflare quick-tunnel URLs are not always available).
It is non-sandboxed (required to spawn `lsof`/`ps`) and distributed as a notarized Developer ID build.
## Build from source
```bash
git clone https://github.com/ntd4996/Porthole.git
cd Porthole
swift build
swift test
swift run porthole # run the menu bar app
./scripts/build-app.sh # produce build/Porthole.app
```
Requires macOS 14+ and a recent Swift toolchain. The detection logic lives in the `PortholeCore` target (pure, unit-tested); the SwiftUI menu bar UI lives in the `porthole` app target.
## License
[MIT](LICENSE) © Dat Nguyen