From Perf Triage
Triage a runtime performance problem in a running browser/web app (100% CPU, jank, freeze, slow interaction, sluggish tab/route switch) by capturing a real CPU profile over the Chrome DevTools Protocol and diagnosing from it, not from source-reading. Use when investigating a measured slowness or CPU spike in a live web UI, or when invoked as /perf-triage. Captures over CDP so it bypasses the DevTools Performance panel, which crashes on large traces.
How this skill is triggered — by the user, by Claude, or both
Slash command
/perf-triage:perf-triageThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Diagnose a runtime perf problem from a **real profile**, fix it with **measurement discipline**, and prove the win. Source-reading produces plausible-but-wrong theories; the profile names the actual cost.
Diagnose a runtime perf problem from a real profile, fix it with measurement discipline, and prove the win. Source-reading produces plausible-but-wrong theories; the profile names the actual cost.
open -na "Google Chrome" --args --remote-debugging-port=9222 --user-data-dir="$HOME/.chrome-perf-profile" "<APP_URL>"
Confirm the port is live: curl -s http://localhost:9222/json/version.curl -s http://localhost:9222/json (look for the app URL, not /login).The login persists in that profile dir, so subsequent captures skip it.
The DevTools Performance panel and the chrome-devtools MCP stop_trace both choke on big traces (a 20s, 100%-CPU, dev build produces 200MB+; DevTools crashes rendering the flame chart). Capture over CDP Profiler to a compact .cpuprofile (JS sampling) instead — nothing renders it, so nothing crashes.
scripts/capture-cpuprofile.js. It connects to :9222, reloads to pick up recompiled code, drives the interaction over CDP itself (clicks the trigger button by text — deterministic, no reliance on user click timing), records, and saves.
node scripts/capture-cpuprofile.js --url "<APP_URL>" --trigger "<button text that triggers it>" --reset "<tab to return to first>" --seconds 22 --out baseline.cpuprofile
Tracing with transferMode: ReturnAsStream instead — the .cpuprofile has samples but not RunTask events.scripts/parse-cpuprofile.js <file>: total duration, idle %, active CPU, per-function self-time and inclusive time, and active-CPU-per-second (the spike shape / duration).rg -n "function <symbol>|const <symbol>" <pkg>/src, then read the source to confirm the mechanism.| Symptom | Measure | Goal |
|---|---|---|
| Freeze / unresponsive | longest task, total blocking time (task-time over 50ms) | no task > ~50ms |
| Sustained 100% CPU, UI still responsive | total active CPU, idle %, per-function self-time | less total work |
| Janky animation / scroll | long tasks during the interaction | fewer/shorter tasks |
Do not optimize a count (timers, renders) unless the profile shows it is the cost.
Trace the symptom to a mechanism. Common shapes:
These are real wrong-turns from triage. Expect to make some; revert fast.
| Tried | Why it failed | Correct move |
|---|---|---|
| Coalesce all notifications into one flush | Concentrated the burst into one multi-second synchronous task → hard freeze | Dedupe by id; keep one timer per unique id (work stays spread) |
| Share one cache across all consumers | Consumers had a per-instance dependency; sharing didn't apply and the gate check was itself O(N) | Verify the shared computation is truly instance-independent before sharing; a fast path that is O(N) is not fast |
| Memoize by object reference | The reference churned every event in the hot path, so the cache always missed | Confirm the key is stable in the hot path before relying on reference memoization |
| Optimize "timer/notification count" | Irrelevant to a freeze (which is about task length) | Match the metric to the symptom first |
scripts/capture-cpuprofile.js — CDP capture to .cpuprofile, drives the interaction itself.scripts/parse-cpuprofile.js — offline analysis (idle %, active CPU, self/inclusive time, spike shape).Both are generic (parameterized by URL, click targets, duration, port). Commit a copy next to the investigation when the work outlives the session.
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub iamsaumya/perf-triage --plugin perf-triage