Dev Dashboard is a local macOS tool for developers that shows development processes listening on ports and lets you stop them from a fast, readable UI.
Sebastian Ortega
This project is licensed under the MIT License. See LICENSE.
This repository includes a prebuilt notarized macOS app for users who do not want to compile it locally:
release/Dev Dashboard.apprelease/Dev Dashboard.ziprelease/SHA256SUMS.txt
For the best user experience, download and extract release/Dev Dashboard.zip rather than opening the .app directly from a GitHub-generated source archive.
- Source code contributions are welcome through pull requests.
- Prebuilt release artifacts in
release/are maintained by Sebastian Ortega. - Contributors should not replace the bundled
.app,.zip, or checksum files unless a release update has been explicitly requested. - Official release artifacts should only be updated from a signed and notarized build.
- Detects development processes listening on TCP ports.
- Shows PID, process name, full command, ports, address, runtime, working directory, and estimated app type.
- Highlights duplicated or suspicious processes.
- Supports manual refresh, auto refresh, search, and process termination.
- Can terminate all processes associated with the same project folder when that can be inferred.
- Opens from a left click on the menu bar icon and shows a quick quit menu on right click.
- Frontend: React + Vite
- Backend: Node.js + Express
- System detection:
lsof+ps - Native menubar app: SwiftUI + AppKit (
NSStatusItem+NSPopover)
dev_dashboard/
├── client/ # React/Vite UI
│ ├── src/App.jsx
│ ├── src/main.jsx
│ └── src/styles.css
├── server/ # Local API + macOS detector
│ └── src/
│ ├── config.js
│ ├── index.js
│ └── processScanner.js
├── menubar-app/ # Native Swift app
├── release/ # Prebuilt notarized app assets
├── package.json # Root scripts and metadata
└── README.md
- macOS
- Node.js 20+ recommended
- npm 10+ recommended
- Xcode 15+ to package the menubar app as a
.app - XcodeGen (
brew install xcodegen) to regenerate the native project
npm installStarts backend and frontend with a single command:
npm run devnpm run servernpm run clientBuild and run the menu bar app:
npm run menubar:runBuild only:
npm run menubar:buildYou can also open the Swift package in Xcode:
open menubar-app/Package.swiftGenerated Xcode project:
npm run menubar:project
npm run menubar:openArchive from the command line:
npm run menubar:archiveInstall locally into /Applications:
npm run menubar:installThis generates the icons, rebuilds the .xcodeproj, creates a signed Release archive, exports a signed Dev Dashboard.app, and copies it into /Applications.
By default the installer tries to use the first available Developer ID Application identity in your Keychain. If none is available, it falls back to Apple Development.
You can override signing explicitly:
DEV_DASHBOARD_CODE_SIGN_IDENTITY="Developer ID Application: Your Name (TEAMID)" \
DEV_DASHBOARD_TEAM_ID="TEAMID" \
npm run menubar:installNotarize the exported app:
npm run menubar:notarizeThe script first looks for APPLE_NOTARYTOOL_PROFILE in Keychain. If it is not available, it falls back to APPLE_ID, APPLE_TEAM_ID, and APPLE_APP_PASSWORD.
The tool listens only on 127.0.0.1.
npm run dev: starts backend + frontend.npm run server: starts the local backend.npm run client: starts the local UI.npm run menubar:run: runs the Swift menubar app.npm run menubar:build: builds the Swift menubar app.npm run menubar:icon: generates the full PNG icon set forAppIcon.npm run menubar:project: generates the.xcodeprojwith XcodeGen.npm run menubar:open: opens the menubar Xcode project.npm run menubar:archive: creates a Release.xcarchivethrough Xcode build tools.npm run menubar:install: installs a local build of the menubar app into/Applications.npm run menubar:notarize: zips the exported.app, submits it to Apple, appliesstaple, and validates Gatekeeper.npm run build: builds the frontend.npm run start: starts the backend without watch mode.
The menubar-app/ folder contains a native Swift version that does not depend on the Node backend for process detection. It reimplements the detector using the same system commands and provides:
- always-on access from the macOS menu bar
- left-click popover plus right-click quit menu on the menu bar icon
- manual and automatic refresh
- native
Launch at Logintoggle usingSMAppService.mainApp - search by PID, port, name, or command
- frontend/backend/duplicated/suspicious badges
- process detail view with useful terminal commands
- process or project termination with confirmation
Assets and packaging:
scripts/generate-menubar-icons.swiftgeneratesAppIcon.appiconsetscripts/install-menubar-app.sharchives, signs, exports, and installs a local.appinto/Applicationsscripts/notarize-menubar-app.shnotarizes the exported.appmenubar-app/project.ymldefines the bundle id,LSUIElement, category, and asset catalog for the Xcode project
Detection relies on native macOS commands:
lsof -nP -iTCP -sTCP:LISTEN -FpcnUsed to obtain:
- PID
- short process name
- listening sockets
- detected port and address
ps -ww -o pid=,ppid=,user=,etime=,args= -p <pid-list>Used to obtain:
- full command
- user
- approximate runtime
lsof -a -d cwd -p <pid-list> -FnUsed to infer the project folder when the process exposes it.
Simple healthcheck.
Returns structured JSON with:
processessummarywarningsgeneratedAt
Body:
{
"force": false
}Attempts SIGTERM first. If the process is still alive, the UI can offer a forced shutdown.
Body:
{
"cwd": "/path/to/project",
"force": false
}Terminates all detected processes with the same working directory.
- Table with PID, process, command, ports, address, runtime, cwd, and estimated type.
- Fast filter by PID, port, name, command, or folder.
- Manual refresh.
- Auto refresh every few seconds.
- Copy command button.
- Kill process button.
- Kill project action from the detail panel.
- Confirmation before stopping processes.
SIGTERMfirst,SIGKILLonly if needed.- Explicit exclusion of ports
7000and7001so the tool does not list itself.
The real flow was tested on macOS with:
- detection of a real Vite server
- detection of a real Node backend
- termination of both through the dashboard API itself
- refresh afterward confirming that both disappeared from the list
- clean compilation of the Swift menubar app with
swift build --package-path menubar-app - real startup of the Swift menubar app as a native process
- correct generation of the Xcode project with
xcodegen - successful
.xcodeprojbuild withxcodebuild - successful signing and notarization of the exported
.app
- The web UI and backend listen only on
127.0.0.1. - Detection is performed locally with
lsofandps. - Process termination always requires explicit user action from the UI.
- No runtime telemetry or external network service is required for normal use.
- The only external service used in the release workflow is Apple notarization, and only when you explicitly run it.
- Classification is heuristic. Vite and Next are fairly reliable; other servers may remain
unknown. - Only TCP sockets in
LISTENstate are considered. Processes without an open listening port are not shown. - Some protected system processes or apps may not expose
cwd, so the folder may appear asunknown. - Process termination depends on the current user permissions. It does not attempt privilege escalation.
Launch at LoginusesSMAppService, but Apple requires a signed app. The build installed bynpm run menubar:installis useful for local use; for reliable auto-start you should archive and sign from Xcode with your Team.- If a process reuses ports or exposes multiple unusual sockets, duplicate detection may not be perfect.
- This first version is designed for macOS and is not adapted to Linux or Windows.
- The menubar app is distributed as an executable Swift package; for a fully packaged signed
.app, openingmenubar-app/Package.swiftin Xcode and archiving from there is the most practical route. - The
Launch at Logintoggle requires a properly signed app; fromswift runor unsigned builds it may fail with an invalid-signature error.
- If you see several processes with the same folder and type, treat them as potential duplicates.
- If a process does not stop with a normal shutdown, the UI offers a forced stop.
- The tool is never exposed outside localhost.
