← All Blogs

Building a Real-Time CPU Monitor for macOS with xbar

4 July, 2025

Building a Real-Time CPU Monitor for macOS with xbar blog

Have you ever noticed your Mac's fan spinning wildly but couldn't quickly identify which process was consuming all your CPU?

As a developer who uses Visual Studio Code daily, I rely heavily on its rich ecosystem of extensions to boost my productivity. But over time, I started noticing my MacBook Air heating up, the fans spinning loudly, and my system becoming sluggish — all while I was just editing code. When I opened the Activity Monitor, I saw one or more mysterious "Code Helper (Plugin)" processes consuming 90–100% CPU, but there was no clear indication of which extension was responsible.

VS Code spawns multiple helper processes, and most of them are generically named, making it incredibly difficult to trace high CPU usage back to a specific extension. This left me guessing — was it Copilot? ESLint? Live Server? I needed a way to monitor these extensions intelligently, without sacrificing performance or productivity.

That's what led me to build a solution — a lightweight tool that monitors CPU usage in real time, maps it to the responsible extension, and alerts me before things spiral out of control. Today, I'll walk you through building a lightweight, real-time CPU monitoring tool that lives in your macOS menu bar and sends notifications when processes exceed your defined thresholds.

What We're Building

Our CPU monitor will:

  • Display CPU status directly in the menu bar

  • Alert you when any process exceeds 80% CPU usage

  • Send native macOS notifications for high CPU processes

  • Provide special handling for VS Code extensions and helpers

  • Show detailed process information (PID, name, command)

  • Indicate when all processes are running normally

Prerequisites

Before we start, you'll need:

  • macOS (this guide is macOS-specific)

  • xbar installed (formerly BitBar)

  • Basic familiarity with shell scripting

The Architecture

Our solution uses a simple but effective approach:

  1. xbar Integration: The script runs every 5 minutes (indicated by the .5m. in the filename)

  2. Process Monitoring: We use ps to capture all running processes with their CPU usage

  3. Threshold Detection: Any process using more than 80% CPU triggers an alert

  4. Native Notifications: We leverage macOS's osascript for system notifications

  5. Fallback Support: Includes support for terminal-notifier as a backup

The Complete Script

Here's the full vscode-ext-monitor.5m.sh script:

#!/bin/bash

CPU_THRESHOLD=80.0
HIGH_CPU_FOUND=0

# Menu Bar Title
echo "🖥️ CPU Monitor"

# Store process information in a temporary file to avoid subshell issues
TEMP_FILE=$(mktemp)
ps -Ao pid,%cpu,command | grep -v "ps -Ao" | grep -v grep > "$TEMP_FILE"

# Read from the temporary file
while IFS= read -r line; do
  if [ -z "$line" ]; then
    continue
  fi

  cpu=$(echo "$line" | awk '{print $2}')
  pid=$(echo "$line" | awk '{print $1}')
  command=$(echo "$line" | cut -d ' ' -f3-)

  # Skip if CPU is not a valid number or is 0.0
  if ! echo "$cpu" | grep -q '^[0-9]*\.[0-9]*$' || [ "$cpu" = "0.0" ]; then
    continue
  fi

  is_high=$(echo "$cpu > $CPU_THRESHOLD" | bc)

  if [ "$is_high" -eq 1 ]; then
    HIGH_CPU_FOUND=1
    echo "---"
    echo "⚠️ High CPU ($cpu%)"
    echo "PID: $pid"

    # Get process name from command
    process_name=$(echo "$command" | awk '{print $1}' | xargs basename 2>/dev/null || echo "Unknown")
    echo "📱 Process: $process_name"

    # Show truncated command
    echo "💻 ${command:0:60}..."

    notification_title="From CPU Monitor"

    # Special handling for different process types
    if echo "$command" | grep -q ".vscode/extensions"; then
      ext=$(echo "$command" | grep -o "/Users/[^ ]*\.vscode/extensions/[^ ]*")
      echo "🧩 VS Code Extension: $(basename "$ext")"
      notification_message="High CPU: ${cpu}% by VS Code extension $(basename "$ext")"
    elif echo "$command" | grep -q "Code Helper"; then
      echo "🔧 VS Code Helper Process"
      notification_message="High CPU: ${cpu}% by VS Code Helper"
    else
      notification_message="High CPU: ${cpu}% by $process_name"
    fi

    # Desktop notification (macOS only) - with error handling
    if command -v osascript >/dev/null 2>&1; then
      osascript -e "display notification \"$notification_message\" with title \"$notification_title\"" 2>/dev/null || {
        # Fallback: try using terminal-notifier if available
        if command -v terminal-notifier >/dev/null 2>&1; then
          terminal-notifier -title "$notification_title" -message "$notification_message" 2>/dev/null
        fi
      }
    fi
  fi
done < "$TEMP_FILE"

# Clean up temporary file
rm -f "$TEMP_FILE"

if [ "$HIGH_CPU_FOUND" -eq 0 ]; then
  echo "---"
  echo "✅ All processes under ${CPU_THRESHOLD}%"
fi

Key Technical Decisions

1. Avoiding Subshell Issues

Initially, we faced a common bash pitfall where notifications wouldn't work because the while loop was running in a subshell:

# This doesn't work for GUI operations
ps ... | while read line; do
  osascript -e "display notification ..."
done

Solution: We use a temporary file approach to avoid the subshell:

TEMP_FILE=$(mktemp)
ps -Ao pid,%cpu,command > "$TEMP_FILE"
while read line; do
  # Process data and send notifications
done < "$TEMP_FILE"
rm -f "$TEMP_FILE"

2. Robust CPU Validation

We validate CPU values to ensure we're working with actual numeric data:

if ! echo "$cpu" | grep -q '^[0-9]*\.[0-9]*$' || [ "$cpu" = "0.0" ]; then
  continue
fi

This prevents errors from malformed process data.

3. Smart Process Classification

The script intelligently categorizes processes:

  • VS Code Extensions: Detected by .vscode/extensions in the command path

  • VS Code Helpers: Identified by "Code Helper" in the command

  • General Processes: Everything else gets generic handling

4. Notification Reliability

We implement a two-tier notification system:

osascript -e "display notification ..." 2>/dev/null || {
  # Fallback to terminal-notifier if available
  if command -v terminal-notifier >/dev/null 2>&1; then
    terminal-notifier -title "..." -message "..."
  fi
}

Installation and Setup

  1. Install xbar if you haven't already:

    brew install --cask xbar
    
  2. Create the plugin directory:

    mkdir -p "$HOME/Library/Application Support/xbar/plugins"
    
  3. Save the script as vscode-ext-monitor.5m.sh in the plugins directory

  4. Make it executable:

    chmod +x "$HOME/Library/Application Support/xbar/plugins/vscode-ext-monitor.5m.sh"
    
  5. Launch xbar and refresh to see your new CPU monitor

Customization Options

Adjust the CPU Threshold

Change the threshold by modifying this line:

CPU_THRESHOLD=80.0  # Change to your preferred percentage

Modify the Update Frequency

Rename the file to change how often it runs:

Add More Process Types

Extend the classification logic:

elif echo "$command" | grep -q "chrome"; then
  echo "🌐 Chrome Process"
  notification_message="High CPU: ${cpu}% by Chrome"

Troubleshooting

Notifications Not Appearing?

  1. Check System Preferences: Ensure notifications are enabled for Terminal in System Preferences > Notifications & Focus

  2. Test manually:

    osascript -e 'display notification "Test" with title "Test"'
    
  3. Install terminal-notifier as backup:

    brew install terminal-notifier
    

Script Not Running?

  1. Verify file permissions:

    ls -la "$HOME/Library/Application Support/xbar/plugins/"
    
  2. Check xbar is running and refresh the menu

  3. Test the script manually:

    cd "$HOME/Library/Application Support/xbar/plugins/"
    ./vscode-ext-monitor.5m.sh
    

What's Next?

This CPU monitor provides a solid foundation that you can extend further:

  • Memory Monitoring: Add RAM usage alerts

  • Network Activity: Monitor processes with high network usage

  • Historical Tracking: Log high CPU events to a file

  • Kill Process Feature: Add menu options to terminate problematic processes

  • Custom Thresholds: Different thresholds for different process types

Conclusion

Building system monitoring tools doesn't require complex frameworks or heavy applications. With a simple bash script and xbar, we've created a lightweight, effective CPU monitor that:

  • Provides real-time visibility into system performance

  • Sends proactive notifications before problems escalate

  • Offers detailed process information for quick troubleshooting

  • Runs efficiently with minimal system overhead

The beauty of this approach is its simplicity and customizability. You have full control over the monitoring logic, notification behavior, and display format. Plus, since it's just a bash script, you can easily modify it to suit your specific needs.

This CPU monitor has been tested on macOS Sequoia and later. The script should work on earlier versions but may require minor adjustments for notification handling.

🚀 Come Join my Newsletter

I share tips on how to get started with freelancing, remote jobs, developer-related stuff, startup ecosystem, and lots of insider secrets with my subscribers.

Subscribe →
🧠 More Interesting Reads
Getting the Most Out of GitHub Copilot Chat in VS Code
How to turn GitHub Copilot into your personal AI programming assistant inside Visual Studio Code.
Handling Undo/Redo Functions in Rich Text Editors
Learn how to implement Undo/Redo functionality in a Rich text editor in your JS application.
Build a Chrome Extension in Next.js and Notion API
Learn to build a Chrome extension that allows you to tag and save web links to a Notion database