Profile Optimizer
Turn a profile file into a ranked, evidence-backed optimisation plan.
Index file. Detailed analysis rules, optimisation patterns, and report
templates live under rules/, references/, and templates/. Load only
what the current phase needs — the body of SKILL.md is a thin orchestrator.
Inputs
The user passes one or more profile files. Accept any of:
| Format |
Extension |
Detection signal |
| React DevTools Profiler |
.json (often .reactprofile) |
Top-level keys include dataForRoots and rendererID / version |
| Chrome Performance trace |
.json / .json.gz |
Top-level traceEvents array (or NDJSON with ph, ts, cat) |
| Chrome CPU profile (legacy) |
.cpuprofile |
Top-level nodes, samples, timeDeltas |
| Chrome heap snapshot |
.heapsnapshot |
Top-level snapshot.meta.node_fields + nodes/edges/strings |
| Chrome heap timeline |
.heaptimeline |
Heap snapshot shape + samples array |
| Chrome heap profile (sampled allocations) |
.heapprofile |
Top-level head + samples (V8 sampling-allocation profile) |
If the file is gzipped, decompress with gunzip -k before parsing.
If multiple formats are passed, treat them as complementary evidence:
- React profile + Chrome trace → correlate by wall-clock timestamp (React
shows component cost, Chrome shows where the main thread actually spent
time).
- Two or three heap snapshots → diff them to find what grew (leak detection).
- Chrome trace + heap timeline of the same interaction → CPU + memory cost
of one action correlated.
See rules/input-detection.md for the precise
detection logic.
Workflow
Six phases. Do not skip a gate.
| Phase |
Name |
Rule file |
Gate |
| 0 |
Intake |
rules/input-detection.md |
Format detected, file size and validity confirmed |
| 1 |
Measurement frame |
rules/measurement-methodology.md |
Baseline metric chosen (TBT, INP, p95 commit, retained MB, etc.) and target stated |
| 2 |
Hotspot extraction |
rules/react-profile-analysis.md, rules/chrome-trace-analysis.md, or rules/heap-snapshot-analysis.md |
Top-N bottlenecks listed with concrete numbers (ms / MB / %, count) |
| 3 |
Root-cause |
rules/optimization-playbook.md |
Each hotspot mapped to a code-level cause (file path / component / API) |
| 4 |
Confidence gate |
rules/confidence-loop.md |
/confidence analysis ≥ 90% — else iterate (max 2 deep-dives) |
| 5 |
Optimisation plan |
templates/analysis-report.md |
Report written with ranked fixes, expected impact, and verification plan |
Phases 2 and 3 branch on the input format (CPU / memory) — everything else is shared.
Required reading by phase
Load on demand — do not preload.
Confidence-gated iteration
After the first pass at root-cause analysis, invoke the confidence skill in
analysis mode:
Skill(skill="confidence", args="analysis")
Apply this gate:
| Score |
Action |
| ≥ 90% |
Proceed to Phase 5 (optimisation plan). |
| 70–89% |
Run one deeper pass: re-read the profile, look at the next-deepest frame, correlate sources. |
| < 70% |
Surface the gap to the user with a question — do not propose code changes on speculation. |
After two deep-dive iterations without reaching 90%, stop and present
findings as a hypothesis with the evidence required to confirm it. This is
the /confidence iteration protocol applied to performance work — see
rules/confidence-loop.md.
Core principles
- Measure before recommending. Every fix must be tied to a number from
the profile. "This component re-renders too much" is not a finding;
"
<UserList> rendered 47 times in a 230ms commit, accounting for 38% of
that commit" is.
- Rank by impact, not by ease. A 5ms fix on a hot path beats a 50ms fix
on a cold one. Use the profile's own data to estimate ceiling impact.
- Root cause over symptom. A long task is the symptom; the work
inside it is the cause. Do not stop at "task X took 240ms" — drill into
the call stack.
- Auto-detect, do not interrogate. Read the file, infer the format,
state what you found. Ask the user only if detection genuinely fails.
- Confidence-gated honesty. If
/confidence returns < 90%, dig
deeper or admit uncertainty. Do not paper over a weak diagnosis with a
confident-sounding fix.
- One profile at a time, but correlate when given two. A React profile
plus a matching Chrome trace is far more powerful than either alone.
Anti-patterns (one-liners — full list in
rules/optimization-playbook.md)
- Recommending
useMemo/useCallback everywhere without measuring (the
React Compiler exists, and unmeasured memoisation often regresses).
- Treating a long task in
Function call as the root cause without
expanding the call stack.
- Reporting raw event counts without converting to percentage of total
blocking time or commit duration.
- Skipping the confidence gate because the first hypothesis "looks right".
- Fixing one big bottleneck and ignoring the long tail of repeated small
ones (death-by-a-thousand-cuts is the common case in real apps).
Memory-profiling quickstart
When the input is a heap snapshot / timeline / profile:
- Validate capture. A single snapshot is only good for a baseline
analysis — refuse to diagnose a leak from one. Leak diagnosis needs
≥ 2 snapshots, ideally 3 (baseline → after-action → after-cleanup).
- Run
heap-summary on the most recent snapshot for top constructors
and node-type breakdown:node --max-old-space-size=4096 \
<skill_dir>/scripts/heap-summary.mjs <snapshot.heapsnapshot>
- Run
heap-diff for the leak case to find what grew between two
snapshots:node --max-old-space-size=4096 \
<skill_dir>/scripts/heap-diff.mjs <before.heapsnapshot> <after.heapsnapshot>
- Map suspects to source. Use
rules/heap-snapshot-analysis.md
Phases 3–4 to go from constructor name → source file → retainer pattern.
The full methodology (capture protocol, how to interpret the diff, common
leak shapes) is in rules/heap-snapshot-analysis.md.
Don't preload it — only when an input is detected as a heap format.
Definition of Done
1---2name: profile-optimizer3description: Analyzes React DevTools Profiler exports, Chrome DevTools Performance traces, and Chrome heap snapshots / heap-timelines / heap-profiles. Identifies the highest-impact bottlenecks (long tasks, expensive renders, layout thrash, wasted memoisation, blocking scripts, retained memory, leaks) and proposes concrete code fixes ranked by measured impact. Auto-detects the input format (React `.json` profile, Chrome trace `.json` / `.cpuprofile`, or `.heapsnapshot` / `.heaptimeline` / `.heapprofile`). Iterates via the `/confidence` skill — if root-cause certainty is below 90%, it digs deeper before recommending a fix. Use when handed a profile file, asked "why is this slow?", "why is memory growing?", or asked to optimise a hot path with evidence. Triggers on "analyze profile", "react profiler", "chrome performance", "optimize from profile", "profile this", "why is this slow", "memory leak", "heap snapshot", "/profile-optimizer".4license: MIT5---67# Profile Optimizer89Turn a profile file into a ranked, evidence-backed optimisation plan.1011> **Index file.** Detailed analysis rules, optimisation patterns, and report12> templates live under `rules/`, `references/`, and `templates/`. Load only13> what the current phase needs — the body of `SKILL.md` is a thin orchestrator.1415---1617## Inputs1819The user passes one or more profile files. Accept any of:2021| Format | Extension | Detection signal |22| -------------------------- | ------------------------ | ----------------------------------------------------------------- |23| React DevTools Profiler | `.json` (often `.reactprofile`) | Top-level keys include `dataForRoots` and `rendererID` / `version` |24| Chrome Performance trace | `.json` / `.json.gz` | Top-level `traceEvents` array (or NDJSON with `ph`, `ts`, `cat`) |25| Chrome CPU profile (legacy)| `.cpuprofile` | Top-level `nodes`, `samples`, `timeDeltas` |26| Chrome heap snapshot | `.heapsnapshot` | Top-level `snapshot.meta.node_fields` + `nodes`/`edges`/`strings` |27| Chrome heap timeline | `.heaptimeline` | Heap snapshot shape + `samples` array |28| Chrome heap profile (sampled allocations) | `.heapprofile` | Top-level `head` + `samples` (V8 sampling-allocation profile) |2930If the file is gzipped, decompress with `gunzip -k` before parsing.3132If multiple formats are passed, treat them as complementary evidence:3334- React profile + Chrome trace → correlate by wall-clock timestamp (React35 shows component cost, Chrome shows where the main thread actually spent36 time).37- Two or three heap snapshots → diff them to find what grew (leak detection).38- Chrome trace + heap timeline of the same interaction → CPU + memory cost39 of one action correlated.4041See [`rules/input-detection.md`](./rules/input-detection.md) for the precise42detection logic.4344---4546## Workflow4748Six phases. Do not skip a gate.4950| Phase | Name | Rule file | Gate |51| ----- | ------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------ |52| 0 | Intake | [`rules/input-detection.md`](./rules/input-detection.md) | Format detected, file size and validity confirmed |53| 1 | Measurement frame | [`rules/measurement-methodology.md`](./rules/measurement-methodology.md) | Baseline metric chosen (TBT, INP, p95 commit, retained MB, etc.) and target stated |54| 2 | Hotspot extraction | [`rules/react-profile-analysis.md`](./rules/react-profile-analysis.md), [`rules/chrome-trace-analysis.md`](./rules/chrome-trace-analysis.md), or [`rules/heap-snapshot-analysis.md`](./rules/heap-snapshot-analysis.md) | Top-N bottlenecks listed with concrete numbers (ms / MB / %, count) |55| 3 | Root-cause | [`rules/optimization-playbook.md`](./rules/optimization-playbook.md) | Each hotspot mapped to a code-level cause (file path / component / API) |56| 4 | Confidence gate | [`rules/confidence-loop.md`](./rules/confidence-loop.md) | `/confidence analysis` ≥ 90% — else iterate (max 2 deep-dives) |57| 5 | Optimisation plan | [`templates/analysis-report.md`](./templates/analysis-report.md) | Report written with ranked fixes, expected impact, and verification plan |5859Phases 2 and 3 branch on the input format (CPU / memory) — everything else is shared.6061---6263## Required reading by phase6465Load on demand — do not preload.6667| Phase | Files |68| ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |69| 0 | [`rules/input-detection.md`](./rules/input-detection.md) |70| 1 | [`rules/measurement-methodology.md`](./rules/measurement-methodology.md) |71| 2 (CPU) | [`rules/react-profile-analysis.md`](./rules/react-profile-analysis.md), [`rules/chrome-trace-analysis.md`](./rules/chrome-trace-analysis.md) |72| 2 (Memory) | [`rules/heap-snapshot-analysis.md`](./rules/heap-snapshot-analysis.md) (also points to [`scripts/heap-summary.mjs`](./scripts/heap-summary.mjs) and [`scripts/heap-diff.mjs`](./scripts/heap-diff.mjs)) |73| 3 | [`rules/optimization-playbook.md`](./rules/optimization-playbook.md), [`references/react-optimization-patterns.md`](./references/react-optimization-patterns.md), [`references/chrome-optimization-patterns.md`](./references/chrome-optimization-patterns.md) |74| 4 | [`rules/confidence-loop.md`](./rules/confidence-loop.md) |75| 5 | [`templates/analysis-report.md`](./templates/analysis-report.md) |7677---7879## Confidence-gated iteration8081After the first pass at root-cause analysis, invoke the confidence skill in82`analysis` mode:8384```text85Skill(skill="confidence", args="analysis")86```8788Apply this gate:8990| Score | Action |91| ------------ | --------------------------------------------------------------------------------------------------- |92| **≥ 90%** | Proceed to Phase 5 (optimisation plan). |93| **70–89%** | Run one deeper pass: re-read the profile, look at the next-deepest frame, correlate sources. |94| **< 70%** | Surface the gap to the user with a question — do **not** propose code changes on speculation. |9596After **two** deep-dive iterations without reaching 90%, stop and present97findings as a hypothesis with the evidence required to confirm it. This is98the `/confidence` iteration protocol applied to performance work — see99[`rules/confidence-loop.md`](./rules/confidence-loop.md).100101---102103## Core principles1041051. **Measure before recommending.** Every fix must be tied to a number from106 the profile. "This component re-renders too much" is not a finding;107 "`<UserList>` rendered 47 times in a 230ms commit, accounting for 38% of108 that commit" is.1092. **Rank by impact, not by ease.** A 5ms fix on a hot path beats a 50ms fix110 on a cold one. Use the profile's own data to estimate ceiling impact.1113. **Root cause over symptom.** A long task is the symptom; the work112 inside it is the cause. Do not stop at "task X took 240ms" — drill into113 the call stack.1144. **Auto-detect, do not interrogate.** Read the file, infer the format,115 state what you found. Ask the user only if detection genuinely fails.1165. **Confidence-gated honesty.** If `/confidence` returns < 90%, dig117 deeper or admit uncertainty. Do not paper over a weak diagnosis with a118 confident-sounding fix.1196. **One profile at a time, but correlate when given two.** A React profile120 plus a matching Chrome trace is far more powerful than either alone.121122---123124## Anti-patterns (one-liners — full list in125[`rules/optimization-playbook.md`](./rules/optimization-playbook.md))126127- Recommending `useMemo`/`useCallback` everywhere without measuring (the128 React Compiler exists, and unmeasured memoisation often regresses).129- Treating a long task in `Function call` as the root cause without130 expanding the call stack.131- Reporting raw event counts without converting to percentage of total132 blocking time or commit duration.133- Skipping the confidence gate because the first hypothesis "looks right".134- Fixing one big bottleneck and ignoring the long tail of repeated small135 ones (death-by-a-thousand-cuts is the common case in real apps).136137---138139## Memory-profiling quickstart140141When the input is a heap snapshot / timeline / profile:1421431. **Validate capture.** A single snapshot is only good for a baseline144 analysis — refuse to diagnose a leak from one. Leak diagnosis needs145 ≥ 2 snapshots, ideally 3 (baseline → after-action → after-cleanup).1462. **Run `heap-summary` on the most recent snapshot** for top constructors147 and node-type breakdown:148 ```bash149 node --max-old-space-size=4096 \150 <skill_dir>/scripts/heap-summary.mjs <snapshot.heapsnapshot>151 ```1523. **Run `heap-diff` for the leak case** to find what grew between two153 snapshots:154 ```bash155 node --max-old-space-size=4096 \156 <skill_dir>/scripts/heap-diff.mjs <before.heapsnapshot> <after.heapsnapshot>157 ```1584. **Map suspects to source.** Use [`rules/heap-snapshot-analysis.md`](./rules/heap-snapshot-analysis.md)159 Phases 3–4 to go from constructor name → source file → retainer pattern.160161The full methodology (capture protocol, how to interpret the diff, common162leak shapes) is in [`rules/heap-snapshot-analysis.md`](./rules/heap-snapshot-analysis.md).163Don't preload it — only when an input is detected as a heap format.164165## Definition of Done166167- [ ] Input format detected and stated.168- [ ] Baseline metric and target chosen (Phase 1) — ms for CPU work, MB169 retained for memory work.170- [ ] Top-N hotspots listed with measured cost (ms / MB / %, count).171- [ ] Each hotspot mapped to a file/component/API/constructor with line or172 retainer references where possible.173- [ ] `/confidence analysis` reached ≥ 90% (or two deep-dives recorded174 with the remaining uncertainty surfaced to the user).175- [ ] Optimisation plan written using176 [`templates/analysis-report.md`](./templates/analysis-report.md), with177 ranked fixes, expected ms / MB saved, and a re-profile verification step.178- [ ] User has the next concrete action (apply fix N, re-profile, compare).