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

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](https://xbarapp.com/) 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`](http://vscode-ext-monitor.5m.sh) script:

```bash
#!/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:

```bash
# 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:

```bash
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:

```bash
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:

```bash
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:
    
    ```bash
    brew install --cask xbar
    ```
    
2. **Create the plugin directory**:
    
    ```bash
    mkdir -p "$HOME/Library/Application Support/xbar/plugins"
    ```
    
3. **Save the script** as [`vscode-ext-monitor.5m.sh`](http://vscode-ext-monitor.5m.sh) in the plugins directory
    
4. **Make it executable**:
    
    ```bash
    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:

```bash
CPU_THRESHOLD=80.0  # Change to your preferred percentage
```

### Modify the Update Frequency

Rename the file to change how often it runs:

* `.`[`1m.sh`](http://1m.sh) = Every minute
    
* `.`[`30s.sh`](http://30s.sh) = Every 30 seconds
    
* `.`[`10m.sh`](http://10m.sh) = Every 10 minutes
    

### Add More Process Types

Extend the classification logic:

```bash
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 &gt; Notifications & Focus
    
2. **Test manually**:
    
    ```bash
    osascript -e 'display notification "Test" with title "Test"'
    ```
    
3. **Install terminal-notifier as backup**:
    
    ```bash
    brew install terminal-notifier
    ```
    

### Script Not Running?

1. **Verify file permissions**:
    
    ```bash
    ls -la "$HOME/Library/Application Support/xbar/plugins/"
    ```
    
2. **Check xbar is running** and refresh the menu
    
3. **Test the script manually**:
    
    ```bash
    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.*
