Skip to content

Instantly share code, notes, and snippets.

@yowmamasita
Last active January 21, 2026 07:07
Show Gist options
  • Select an option

  • Save yowmamasita/f3458e89367a82fbdee4366f456ed576 to your computer and use it in GitHub Desktop.

Select an option

Save yowmamasita/f3458e89367a82fbdee4366f456ed576 to your computer and use it in GitHub Desktop.
Claude Code CLI leaves orphaned background processes that consume CPU/memory. This launchd daemon auto-kills processes not attached to a terminal (TTY) every hour, keeping only your active sessions.

Auto-cleanup Orphaned Claude Code CLI Processes on macOS

Claude Code CLI can leave orphaned background processes that consume CPU and memory. This solution automatically kills Claude processes that are no longer attached to a terminal.

How it works

Active Claude sessions are attached to a TTY (e.g., s001, s002). Orphaned processes show ?? in the TTY column. This script kills only the orphaned ones.

Option 1: Manual alias

Add to ~/.zshrc or ~/.bashrc:

alias claude-cleanup='ps aux | grep "[c]laude" | awk "\$7 == \"??\" {print \$2}" | xargs kill -9 2>/dev/null'

Then run claude-cleanup whenever needed.

Option 2: Automatic cleanup with launchd (runs every hour)

Install

cat > ~/Library/LaunchAgents/com.user.claude-cleanup.plist << 'PLIST'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.claude-cleanup</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>-c</string>
        <string>ps aux | grep '[c]laude' | awk '$7 == "??" {print $2}' | xargs kill -9 2>/dev/null || true</string>
    </array>
    <key>StartInterval</key>
    <integer>3600</integer>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
PLIST

launchctl load ~/Library/LaunchAgents/com.user.claude-cleanup.plist

Useful commands

# Check status
launchctl list | grep claude-cleanup

# Run cleanup manually
launchctl start com.user.claude-cleanup

# Uninstall
launchctl unload ~/Library/LaunchAgents/com.user.claude-cleanup.plist
rm ~/Library/LaunchAgents/com.user.claude-cleanup.plist

# Change interval: edit StartInterval (seconds) in the plist, then unload/load

Check for orphaned processes

# Count orphaned Claude processes
ps aux | grep '[c]laude' | awk '$7 == "??" {print $2}' | wc -l

# List all Claude processes with their TTY
ps aux | grep '[c]laude' | awk '{print $2, $7, $11}'
@ZZS42
Copy link

ZZS42 commented Jan 20, 2026

💡 A Few Enhancement Tips

Great script! Here are some additional tips that might be helpful:

Customize Cleanup Interval

To change the cleanup frequency (e.g., every 10 minutes instead of hourly):

# Unload the daemon
launchctl unload ~/Library/LaunchAgents/com.user.claude-cleanup.plist

# Edit the plist file - change 3600 to your desired interval in seconds
# (600 = 10 min, 1800 = 30 min, 3600 = 1 hour)
nano ~/Library/LaunchAgents/com.user.claude-cleanup.plist

# Reload the daemon
launchctl load ~/Library/LaunchAgents/com.user.claude-cleanup.plist

# Verify the daemon is running
launchctl list | grep claude

Quick Cleanup Function

Add this to your ~/.zshrc or ~/.bashrc for a quick manual cleanup command:

claude-cleanup() {
    local pids=$(ps -eo pid,ppid,tty,comm,args | awk '$4 == "claude" && $3 == "??" && $2 == 1 && !/Claude\.app/ {print $1}')
    if [[ -n "$pids" ]]; then
        echo "$pids" | xargs kill -9 2>/dev/null
        echo "Cleaned up orphaned Claude CLI processes: $pids"
    else
        echo "No orphaned Claude CLI processes found"
    fi
}

Then run source ~/.zshrc and use claude-cleanup anytime.

⚠️ Important: This improved version includes args in the ps output and adds !/Claude\.app/ to exclude Claude Desktop app. Without this filter, the script will accidentally kill Claude.app!

Protect Long-Running Tasks with tmux

If you run long tasks with Claude and want to prevent accidental termination:

# Install tmux
brew install tmux

# Start a named session
tmux new -s claude

# Run Claude inside tmux
claude

# Detach (keeps running): Ctrl+B, then D
# Reattach later: tmux attach -t claude

Processes inside tmux have a proper TTY (e.g., pts/0), so they won't be flagged as orphaned.

Hope this helps! 🙌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment