$npx -y skills add rianvdm/product-ai-public --skill diagnosing-mac-performanceUse when the user reports their Mac is slow, sluggish, laggy, or unresponsive — or asks what's using CPU, memory, or battery. Also triggers on "check system performance", "what's eating my CPU", "Mac is hot", "fan is loud", or any request to diagnose macOS resource usage. Covers
| 1 | # Diagnosing Mac Performance Issues |
| 2 | |
| 3 | ## When to Use |
| 4 | |
| 5 | * User says their Mac feels slow, laggy, or unresponsive |
| 6 | * User asks what's consuming CPU, memory, or battery |
| 7 | * User reports fans running loud or machine running hot |
| 8 | * Proactive check during long sessions if the user mentions sluggishness |
| 9 | |
| 10 | ## Steps |
| 11 | |
| 12 | 1. **Snapshot system state** — run these in parallel: |
| 13 | ```bash |
| 14 | # Top processes by CPU |
| 15 | ps -eo pid,pcpu,pmem,comm -r | head -25 |
| 16 | |
| 17 | # System overview (load avg, memory, swap) |
| 18 | top -l 1 -n 1 -stats pid,command,cpu | head -10 |
| 19 | |
| 20 | # Memory pressure and swap |
| 21 | sysctl vm.swapusage && memory_pressure |
| 22 | ``` |
| 23 | |
| 24 | 2. **Triage into CPU-bound vs memory-bound:** |
| 25 | - **CPU-bound:** One or more processes above 30% CPU. Identify and investigate. |
| 26 | - **Memory-bound:** Swap used > 2 GB, compressor > 4 GB, or "Pages free" under 10,000. Even if no single process is hot, the system spends CPU on compression/decompression and swap I/O. |
| 27 | - **Both:** Common. A runaway daemon often causes memory pressure too. |
| 28 | |
| 29 | 3. **For CPU hogs — identify the category:** |
| 30 | |
| 31 | | Process type | Normal range | Investigate if | Common fix | |
| 32 | |-------------|-------------|----------------|------------| |
| 33 | | WindowServer | 10-20% | >35% sustained | Usually driven by another app doing excessive redraws. Fix the other app. | |
| 34 | | contactsd / AddressBookManager | <2% | >10% | Stuck sync loop. Check error logs, disable problematic account sync (Gmail CardDAV is a known offender). | |
| 35 | | mds / mds_stores / mdworker | <5% each | >20% or many workers | Spotlight indexing. Usually transient after updates. `sudo mdutil -i off /` to pause if urgent. | |
| 36 | | kernel_task | varies | >200% | Thermal throttling. Not fixable via software — machine needs cooling. | |
| 37 | | nsurlsessiond / cloudd | <5% | >15% | iCloud sync stuck. Check System Settings > Apple ID > iCloud. | |
| 38 | | trustd | <1% | >10% | Certificate validation loop. Often clears on reboot. | |
| 39 | | Electron apps (Discord, Slack, VS Code, Windsurf) | 2-5% each | >15% | Restart the app. Electron apps leak memory over time. | |
| 40 | |
| 41 | 4. **For memory pressure — assess severity:** |
| 42 | ```bash |
| 43 | # Quick summary |
| 44 | sysctl vm.swapusage |
| 45 | # Detailed breakdown |
| 46 | memory_pressure |
| 47 | ``` |
| 48 | |
| 49 | | Indicator | Healthy | Warning | Critical | |
| 50 | |-----------|---------|---------|----------| |
| 51 | | Swap used | <500 MB | 500 MB - 2 GB | >2 GB | |
| 52 | | Compressor | <2 GB | 2-5 GB | >5 GB | |
| 53 | | Pages free | >20,000 | 5,000-20,000 | <5,000 | |
| 54 | | Free percentage | >30% | 10-30% | <10% | |
| 55 | |
| 56 | If critical: recommend quitting the heaviest apps. List them with memory percentages so the user can make an informed choice. |
| 57 | |
| 58 | 5. **For runaway system daemons — pull error logs:** |
| 59 | ```bash |
| 60 | /usr/bin/log show --predicate 'process == "<daemon_name>" AND (messageType == 16 OR messageType == 17)' --last 5m --style compact 2>&1 | head -50 |
| 61 | ``` |
| 62 | - `messageType == 16` = Error, `messageType == 17` = Fault |
| 63 | - Use `/usr/bin/log` (full path) because shell aliases can interfere |
| 64 | - Look for repeated errors in tight loops — that's the signature of a stuck daemon |
| 65 | |
| 66 | 6. **Report findings** using this structure: |
| 67 | |
| 68 | **Top resource consumers:** |
| 69 | |
| 70 | | Process | CPU % | RAM % | Status | |
| 71 | |---------|-------|-------|--------| |
| 72 | | contactsd | 124% | 0.9% | Stuck — sync loop (see below) | |
| 73 | | WindowServer | 47% | 0.7% | Elevated — driven by contactsd churn | |
| 74 | |
| 75 | **Memory pressure:** Critical — 15 GB / 16 GB used, 4.3 GB swap, 6.5 GB compressor |
| 76 | |
| 77 | **Diagnosis:** contactsd is in a sync error loop caused by [root cause]. This is stuck, not transient. |
| 78 | |
| 79 | **Recommended fixes** (least to most disruptive): |
| 80 | 1. [First option] |
| 81 | 2. [Second option] |
| 82 | 3. [Nuclear option, if applicable] |
| 83 | |
| 84 | Adapt the structure to fit — skip sections that don't apply, add detail where it matters. The key is: show the data, state the diagnosis, order the fixes. |
| 85 | |
| 86 | ## Gotcha Section |
| 87 | |
| 88 | - **`ps` syntax is different on macOS.** No `--sort` flag. Use `ps -eo pid,pcpu,pmem,comm -r` (sort by CPU) or `-m` (sort by memory). GNU-style `ps aux --sort=-%cpu` will error. |
| 89 | - **`top -l 1` is a snapshot, not live.** The CPU percentages in a single `top` snapshot can be misleading — a process caught mid-burst looks worse than it is. Use `ps -r` as the primary view; `top` for the load average and memory summary. |
| 90 | - **Killing system daemons usually just restarts them.** `killall contactsd` → launchd restarts it immediately. This is fine for breaking a stuck loop, but if the root cause isn't fixed, it'll spin right back up. |
| 91 | - **Sandbox/TCC blocks terminal access to some directories.** `~/Library/Application Support |