A smart, safe, and lightning-fast cleanup script for development environments.
It identifies and kills orphaned background processes (processes where PPID=1) to reclaim memory without affecting your active development sessions (like your IDE, terminal, or Claude Code/AI agents).
Specially optimized for macOS mobile developers (Flutter/iOS/Android) and developers using modern AI tools (MCP servers).
AI-powered coding tools and mobile development toolchains spawn background processes that frequently fail to clean up after themselves. These orphaned processes silently accumulate, consuming 10-20+ GB of RAM before you even notice your machine slowing down.
Instead of manually hunting them down in Activity Monitor or rebooting, devclean safely sweeps them away in milliseconds.
Tools like Claude Code, Cursor, OpenCode, and Antigravity spawn MCP (Model Context Protocol) servers as child processes. When the parent IDE or terminal exits β especially via crash, force-quit, or closing a tab β these child processes are not terminated. They become orphaned (PPID=1) and keep running indefinitely.
Why it happens:
- macOS lacks
prctl(PR_SET_PDEATHSIG)β there's no native way to auto-kill children when the parent dies. - Node.js
child.kill()sends SIGTERM but doesn't wait for cleanup, and nestednpm execwrappers add additional layers that signals don't propagate through. - The MCP protocol specifies a graceful shutdown phase, but most host implementations don't invoke it on exit.
Real-world impact:
| Tool | Issue | Impact |
|---|---|---|
| Claude Code | MCP servers not terminated on exit | Processes accumulate across sessions |
| Claude Code | Chrome MCP spawns ~4/min without cleanup | 27 GB over ~10 hours |
| Claude Code | Subagents leak when parent terminal killed | ~45 MB per orphaned process |
| Claude Code | VS Code extension leaks worker processes | OOM killer triggered on Linux |
| Cursor | MCP child processes not cleaned up | ~3-5 GB over days |
| Cursor | MCP processes accumulate over time | Dozens of orphaned node/npm processes |
| OpenCode | MCP processes not terminated on session end | Zombie process accumulation |
| Antigravity | Language server high memory consumption | Zombie processes after quit; backend ports don't clear |
| Antigravity | MCP servers spawn per-workspace, never cleaned up | Process explosion; ~10 GB idle RAM |
Webpack-dev-server is notorious for leaving orphaned node processes after Ctrl+C. The child process cannot be killed when spawned via child_process, and if the parent exits, the dev server continues running. Similar issues affect Vite, Next.js dev server, and other frontend tooling.
| Tool | Issue | Impact |
|---|---|---|
| webpack-dev-server | Orphaned node.exe processes | Port occupied, node process lingers |
| webpack-dev-server | Child process cannot be killed | Parent exit doesn't terminate server |
| Vue/webpack | Dev server continues after Ctrl+C | Needs manual kill |
The flutter command is a shell script wrapper. When IDE sends SIGTERM on shutdown, the signal hits the shell process but doesn't propagate to the underlying Dart VM. The VM process becomes orphaned while the shell exits cleanly.
The Flutter daemon also spawns sub-processes like xcdevice observe that are never cleaned up.
| Tool | Issue | Impact |
|---|---|---|
| Flutter / Dart | Daemon orphaned when IDE closes | SIGTERM doesn't propagate through shell wrapper |
| Flutter | xcdevice observe leaked by daemon |
Orphaned sub-processes pile up |
| FVM | FVM-managed dart/flutter processes can get stuck (e.g. fvm use waiting for interactive input) |
Stuck processes accumulate at 100% CPU each |
Gradle daemons are designed to stay alive for performance. But a new daemon is spawned whenever JVM args, Java version, or Gradle version differ between builds. Multi-project setups with Kotlin can spawn 3+ Kotlin daemons, each consuming 1 GB+ of heap. The built-in 3-hour idle timeout is far too long for developer machines.
| Tool | Issue | Impact |
|---|---|---|
| Gradle Daemon | Multiple instances exhaust memory | Config mismatches spawn duplicates |
| Kotlin Daemon | Excessive memory usage | 3+ daemons Γ 1 GB+ each |
CoreSimulator processes from previous Xcode sessions linger in the background because Xcode has no idea what you still need and won't clean them up for you. They collectively consume 10-20+ GB.
logioptionsplus_agent has a well-documented memory leak that has been reported for 3+ years. The agent starts at ~100 MB but grows to multi-GB over time β in extreme cases up to 36 GB. Since launchd auto-restarts it, the only practical solution is to periodically kill the process and let it restart fresh. Logitech has not fully fixed this issue.
| Strategy | How | Safe for active work? |
|---|---|---|
Orphan detection (PPID=1) |
Only kills processes whose parent has died β the defining trait of a leaked process | Yes β active IDE/terminal children always have a living parent |
| Pattern matching | Targets known offenders via ORPHAN_PATTERNS regex array, not blanket process killing |
Yes β only matches specific tool signatures |
pgrep over ps|grep |
Uses pgrep -f to avoid self-matching and reduce false positives |
Yes |
| Frontend dev servers | Catches orphaned webpack-dev-server, vite, next.js, esbuild, turbopack processes | Yes β only PPID=1 orphans |
| Graceful termination | SIGTERM β 2s wait β SIGKILL only for unresponsive processes | Yes β gives processes time to save state |
| Deep mode separation | Heavy daemons (Gradle, Kotlin LSP, FVM, Antigravity Language Server, Logi Options+) require explicit --deep flag; xcodebuild further restricted to orphans only |
Yes β opt-in, never surprises |
| Dry-run | --dry-run previews everything without killing |
N/A β read-only |
git clone https://github.com/ImL1s/devclean.git
cd devclean
./install.shNote: Ensure
~/.local/binis in yourPATH. Add this line to your~/.zshrcor~/.bashrc:export PATH="$HOME/.local/bin:$PATH"
Safe mode ONLY targets detached, orphaned tools (PPID=1). It is designed to avoid active sessions β processes attached to a living parent (your IDE, terminal, shell) are never matched.
devcleanShuts down heavy background daemons that aren't technically orphaned but can consume GBs of RAM when idle. (Tools like Gradle will automatically restart on your next build.)
Warning: Deep mode kills non-orphaned Gradle, Kotlin LSP, Flutter daemons, FVM processes, Antigravity Language Server, Logi Options+ agent, and Ruby/Fastlane processes. If a build or compilation is actively running, it may be interrupted. Use
--dry-runfirst to preview what would be affected.
devclean --deepPreview what the script would kill without actually terminating anything. Great for auditing how much memory you could reclaim.
devclean --dry-run
devclean --deep --dry-runApplies one-time fixes to reduce resource waste: disables crash reporters in VS Code / Cursor / Antigravity / Kiro, cleans Crashpad dump files, and disables known resource-wasting background agents.
devclean --optimize
devclean --optimize --dry-runReclaims disk space by cleaning development caches and build artifacts. All cleaned items are rebuildable β your next build will re-download what it needs.
Targets: Xcode DerivedData, iOS DeviceSupport, Gradle caches, CocoaPods, Flutter pub cache, npm cache, FVM incomplete versions, Gemini browser recordings, project build/, .dart_tool/, .gradle/, node_modules/ directories.
devclean --disk
devclean --disk --dry-rundevclean --helpAdd your own tools to the cleanup list by editing the ORPHAN_PATTERNS array in the devclean script:
ORPHAN_PATTERNS=(
# AI & MCP Servers (Common)
"mcp-server|playwright-mcp"
# ... add yours here!
"my-custom-heavy-daemon"
)Then run ./install.sh again to apply the changes globally.
Pull requests are welcome! If you know of other development tools that frequently leave orphaned background processes, feel free to open a PR to add them to the default regex patterns.
This project is licensed under the MIT License.
