{"slug": "dead-process-mate-a-menu-bar-app-to-kill-leftover-node-dev-processes", "title": "Dead Process Mate – a menu-bar app to kill leftover Node/dev processes", "summary": "Dead Process Mate, a native macOS menu-bar app, lets developers kill leftover Node and dev processes in one click by reading the kernel directly. The app, built with Swift and requiring macOS 14+ on Apple Silicon, highlights orphaned, idle, and high-CPU processes to help AI-assisted coders manage server clutter. It is available via Homebrew or a DMG download, with ad-hoc signing and no network connections.", "body_md": "**A tiny native macOS menu-bar app that keeps an eye on your Node/dev processes,\nshows which ports they hold, and helps you kill the leftover ones in one click.**\n\nNo Electron. No `ps`\n\n/`lsof`\n\nshelling out. Just a small Swift binary reading the\nkernel directly. Lives only in the menu bar — no Dock icon.\n\nWhen you code — especially with AI assistants — dev servers pile up fast. A\n`vite`\n\nhere, a `next dev`\n\nthere, three `pnpm`\n\nwatchers, a script you `Ctrl-C`\n\n'd\nthat didn't actually die. They keep holding ports (`:3000`\n\nis “already in use”\nagain), eating RAM, and spinning the fans. Dead Process Mate makes all of that\nvisible in your menu bar and one click away from gone.\n\nIt's especially good at spotting the **dead leftovers**: a dev server whose\nparent terminal is gone (it got reparented to `launchd`\n\n), something that's been\nidle for hours, or a zombie — exactly the stuff that quietly wastes your\nmachine.\n\n**Process list**— your dev processes with friendly names (`vite dev`\n\n,`next-server`\n\n,`npm run dev`\n\n— not a wall of`node`\n\n), CPU %, memory, uptime, and the project folder each runs in. Search, sort, and group by project.**Ports view**— what's listening where, mapped to the owning process. Common dev ports (`3000`\n\n,`5173`\n\n,`8080`\n\n, …) are highlighted so the server you're looking for pops.**Health at a glance**— a colored dot per process (see the table below), and a matching indicator right in the menu bar.** One-click kill**— hover any row → ✕. Graceful`SIGTERM`\n\nfirst, auto-escalates to`SIGKILL`\n\nafter 3 s. Right-click for Force Kill and copy/reveal actions. “Kill N” in the footer clears every flagged process at once.**Notifications**— optional, throttled alerts for orphaned processes, idle servers still holding a port, memory hogs, and “too many idle Node processes piling up.” Every banner has a**Kill** button.**Launch at login**, pause monitoring, configurable thresholds, force-kill toggle.\n\nEverything is local — it never makes a network connection.\n\nEach process gets a status; the worst one bubbles up to the menu bar. Defaults\nare all editable in **Settings → Thresholds**.\n\n| Dot | Status | When |\n|---|---|---|\n| 🟢 | Healthy |\nrunning normally |\n| 🟡 | Idle / old |\nrunning ≥ 4 h, or idle (<1% CPU) for ≥ 30 min, or over the memory limit |\n| 🟠 | High CPU |\n≥ 80% CPU sustained for ≥ 15 s |\n| 🔴 | Orphaned |\nparent process is gone (reparented to `launchd` ) — a classic abandoned dev server |\n| 🔴 | Zombie |\ndefunct process (kill its parent) |\n\nPrecedence: zombie › orphaned › high-CPU › idle/old › healthy.\n\n**All healthy**→ a calm monochrome icon (choose CPU / activity pulse / gauge / stack in Settings).** Something's wrong**→ the icon tints and a** count of flagged processes**appears next to it (or a colored dot — your choice). So you can tell at a glance without opening the panel.** Paused**→ a pause glyph.\n\n**Requirements:** macOS 14+ · Apple Silicon.\n\n```\nbrew install --cask --no-quarantine bartosk97/tap/dead-process-mate\n```\n\nOn Homebrew 6+ you'll be asked to trust the tap once — run the\n`brew trust bartosk97/tap`\n\ncommand it prints, then re-run the install.\n\nGrab the `.dmg`\n\nfrom the [latest release](https://github.com/BartosK97/dead-process-mate/releases/latest),\ndrag the app to Applications, then clear the download quarantine and open it:\n\n```\nxattr -dr com.apple.quarantine /Applications/DeadProcessMate.app\nopen /Applications/DeadProcessMate.app\n```\n\nThis build is\n\nad-hoc signed, not notarized(no paid Apple account yet), so macOS quarantines the download — that's what the`--no-quarantine`\n\nflag and the`xattr`\n\ncommand handle. Everything runs locally; the app makes no network calls.\n\nNeeds the Swift toolchain from Xcode **or** the Command Line Tools\n(`xcode-select --install`\n\n) — a full Xcode install is **not** required.\n\n```\ngit clone https://github.com/BartosK97/dead-process-mate.git\ncd dead-process-mate\n\n./build.sh run       # build + package + ad-hoc sign, then launch\n# or\n./build.sh build     # just build dist/DeadProcessMate.app\n./build.sh install   # copy into /Applications and launch\n```\n\n`build.sh`\n\ncompiles with SwiftPM, assembles a `DeadProcessMate.app`\n\nbundle\n(generating the icon from `icon.png`\n\n), and **ad-hoc code-signs** it. On Apple\nSilicon a signature is mandatory just to run, and notifications need a real\nbundle identity — the script handles both.\n\nLaunch the(via`.app`\n\n`build.sh`\n\nor`open`\n\n), not the bare binary in`.build/`\n\n. Running the raw executable breaks notifications (no bundle identity).\n\nmacOS asks to allow **notifications** — click **Allow** (or enable it later in\nSystem Settings › Notifications › Dead Process Mate). If you skip it, everything\nelse still works; you just won't get banners.\n\n**Click the menu-bar icon** to open the panel.**Processes tab**— hover a row to reveal the**✕ kill** button. Click a row to expand it (PID/PPID, full command, folder, ports, copy/reveal). Right-click for a full menu (Kill, Force Kill, Copy PID/command, Reveal in Finder).**Ports tab**— see every listening port and who owns it; hover → ✕ to free it.** Footer**— ⏸ pause/resume,** Kill N**(kill everything flagged), ⚙ settings, ⏻ quit.\n\nOpen with the ⚙ in the footer (or ⌘,). Four tabs:\n\n**General**— menu-bar icon, warning indicator (count / dot / none), refresh interval (2 / 5 / 10 / 30 s), launch at login.** Thresholds**— when a process turns yellow/orange/red and when it notifies: “old after N h”, “idle after N min”, high-CPU %, high-memory, and the “too many idle” count.**Notifications**— master toggle, per-event toggles, and a repeat throttle so you're never nagged about the same thing twice within the window.**Watched**— which process names to track (`node`\n\n,`vite`\n\n,`next-server`\n\n, …), a show-all toggle, and a force-kill (SIGKILL) toggle (off by default — graceful SIGTERM first is recommended).\n\n**Processes**—`proc_listpids`\n\n+`proc_pidinfo`\n\n(`PROC_PIDTBSDINFO`\n\n/`PROC_PIDTASKINFO`\n\n) for pid/ppid/start-time/RSS/CPU,`proc_pidpath`\n\n+`KERN_PROCARGS2`\n\nfor the full command line, and`PROC_PIDVNODEPATHINFO`\n\nfor the working directory. Zombies (invisible to`proc_pidinfo`\n\n) are caught via a`sysctl(KERN_PROC)`\n\nfallback. CPU % is derived by diffing cumulative CPU time between refreshes.**Ports**— each process's socket file descriptors are read via`PROC_PIDLISTFDS`\n\n+`PROC_PIDFDSOCKETINFO`\n\n, keeping only TCP sockets in`LISTEN`\n\nstate — the same data`lsof`\n\nsurfaces, without spawning it.**UI**— SwiftUI`MenuBarExtra`\n\n(`.window`\n\nstyle),`.accessory`\n\nactivation policy so there's no Dock icon.**Notifications & launch-at-login**—`UserNotifications`\n\nand`ServiceManagement`\n\n.\n\nA full scan of ~800 processes takes **~15 ms** and runs off the main thread, so\nit's effectively free.\n\nKills are guarded against **PID reuse**: a process's start-time signature is\ncaptured and re-checked before escalating to `SIGKILL`\n\n, so a recycled PID can't\nlead to killing the wrong process. All scanning is read-only kernel\nintrospection of **your own** processes — no root, no privileged helper.\n\n```\nSources/\n  CSystemProbe/        C shim over libproc (process + listening-socket scan)\n  DeadProcessMate/\n    App/               @main app, self-test hook\n    Model/             data models, naming, preferences\n    Core/              scanner, monitor, killer, notifications, login item\n    Views/             menu-bar panel, rows, settings\nbuild.sh               build + package + ad-hoc sign (also builds the .icns)\nInfo.plist             LSUIElement bundle metadata\nicon.png               1024×1024 app-icon source\n```\n\nRun a headless scan (handy for hacking on the scanner):\n\n```\nDPM_SELFTEST=1 ./dist/DeadProcessMate.app/Contents/MacOS/DeadProcessMate\n```\n\n**No notifications?** They only work when the app runs from the`.app`\n\nbundle launched via`open`\n\n(not the bare binary), and after you approve the prompt. Re-enable in System Settings › Notifications › Dead Process Mate.**“app can't be opened” / it won't launch?** Make sure it's signed — always launch through`build.sh`\n\n/`open`\n\n, not`.build/release/DeadProcessMate`\n\n.**A process I care about isn't listed?** Add its name in Settings → Watched, or turn on “Show all processes.”\n\nIssues and PRs welcome. It's a small, single-purpose app — keep it native, keep\nit light. `swift build`\n\nto compile, `./build.sh run`\n\nto try it.\n\nMIT — see [LICENSE](/BartosK97/dead-process-mate/blob/main/LICENSE).", "url": "https://wpnews.pro/news/dead-process-mate-a-menu-bar-app-to-kill-leftover-node-dev-processes", "canonical_source": "https://github.com/BartosK97/dead-process-mate", "published_at": "2026-07-12 18:02:12+00:00", "updated_at": "2026-07-12 18:36:00.039574+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Dead Process Mate", "BartosK97", "Apple", "Homebrew", "Swift", "macOS", "Node"], "alternates": {"html": "https://wpnews.pro/news/dead-process-mate-a-menu-bar-app-to-kill-leftover-node-dev-processes", "markdown": "https://wpnews.pro/news/dead-process-mate-a-menu-bar-app-to-kill-leftover-node-dev-processes.md", "text": "https://wpnews.pro/news/dead-process-mate-a-menu-bar-app-to-kill-leftover-node-dev-processes.txt", "jsonld": "https://wpnews.pro/news/dead-process-mate-a-menu-bar-app-to-kill-leftover-node-dev-processes.jsonld"}}