# performance-optimization

> A Claude Code skill from Addy Osmani's agent-skills repo that enforces a measure-first performance workflow — Core Web Vitals targets (LCP ≤ 2.5s, INP ≤ 200ms, CLS ≤ 0.1), synthetic + RUM in parallel, and a refusal to optimize anything without a profile.

**Use case**: Stop guessing at performance — profile, identify the bottleneck, fix the bottleneck, verify

**Canonical URL**: https://agentcookbooks.com/skills/performance-optimization/

**Topics**: claude-code, skills, performance, code-quality

**Trigger phrases**: "this page feels slow", "improve Core Web Vitals", "fix the LCP"

**Source**: [Addy Osmani](https://github.com/addyosmani/agent-skills/tree/main/skills/performance-optimization)

**License**: MIT

---

## What it does

`performance-optimization` is the perf-discipline skill in [Addy Osmani's agent-skills](https://github.com/addyosmani/agent-skills) collection. The whole skill is built around one rule: measure before optimizing. The five-step loop — measure, identify, fix, verify, guard — is the spine, and the skill refuses to advance to "fix" without a profile that names the actual bottleneck.

Core Web Vitals are the anchor: LCP ≤ 2.5s, INP ≤ 200ms, CLS ≤ 0.1, with explicit "Needs Improvement" and "Poor" thresholds for each. Synthetic measurement (Lighthouse, DevTools Performance tab, Chrome DevTools MCP) runs alongside RUM (the `web-vitals` library, CrUX) — synthetic for CI regression detection, RUM to validate that a fix actually moved real-user numbers. The skill also catalogs the common anti-patterns it expects to find: N+1 queries with the join-fix shown inline, unbounded data fetching that needs pagination, hero images that need `<picture>` + `srcset` + `fetchpriority="high"`, React re-render storms from inline object props, and bundle bloat that needs route-level code splitting.

## When to use it

- Core Web Vitals are below threshold and you need a structured triage path
- A specific symptom exists ("page load slow", "input lag", "API endpoint slow") and you want the skill's symptom → likely-cause → investigation table
- Pre-launch audit where a perf budget is set in CI (`bundlesize`, `lhci autorun`) and you want to clear it cleanly
- After a change that *might* have regressed, where you need before/after numbers, not opinions

When *not* to reach for it:

- No measurement exists yet — the skill explicitly refuses to optimize on suspicion. Profile first, then bring the skill in.
- Pure architectural problems (microservice boundaries wrong, data model wrong) — anti-pattern fixes don't address those.
- Backend hot-path tuning where you already have an APM in place — the skill's backend section is generalist; a profiler-led approach beats it.

## Install

From [addyosmani/agent-skills](https://github.com/addyosmani/agent-skills) at `skills/performance-optimization/`. Pairs naturally with `browser-testing-with-devtools` (DevTools MCP gives the skill its measurement substrate) and the repo's `references/performance-checklist.md`.

## What a session looks like

1. **Measure (synthetic + RUM).** Lighthouse run for CI-grade numbers; `web-vitals` library calls (`onLCP`, `onINP`, `onCLS`) for real-user data. Backend hops get `console.time` / APM traces.
2. **Decision tree on the symptom.** "First page load slow" branches to bundle vs. server response vs. render-blocking. "Interaction sluggish" branches to long tasks (>50ms) vs. controlled-component re-render overhead vs. layout thrashing. The skill ships the tree as a directly-quotable artifact.
3. **Identify the bottleneck.** Symptom → likely cause table — slow LCP usually traces to large images / render-blocking resources / slow server; high CLS to images without dimensions / late-loading content / font shifts; poor INP to heavy main-thread JavaScript.
4. **Fix one anti-pattern.** Inline code shown for the canonical fix: N+1 → `include`, unbounded → pagination, hero `<img>` → `<picture>` with `srcset` + `fetchpriority="high"`, inline-object prop → stable reference + `React.memo`, large bundle → `lazy()` + `Suspense` at route boundary, missing cache → TTL'd in-memory or `Cache-Control: public, max-age=...`.
5. **Verify.** Re-run the same profile. Numbers move or the fix is wrong.
6. **Guard.** A perf budget in CI: `bundlesize` for JS, `lhci autorun` for Lighthouse, p95 SLA for API. The skill's "fix didn't ship until the budget passes" rule is what keeps the win from rotting.

The discipline that makes it work: refusing to skip step 1. Optimization without measurement is the failure mode the entire skill is built against, and the "rationalizations" table calls out "we'll optimize later" / "it's fast on my machine" by name.

## Receipts

_TODO — to be filled in from a real session. Once the skill has been pointed at a measured bottleneck, this section will capture: which step the skill caught the agent trying to skip (most likely step 1 or step 4), how the synthetic-vs-RUM split actually played out on a deployed change, and whether the perf-budget guard caught a real regression in a follow-up commit._

## Source and attribution

From [Addy Osmani's agent-skills repository](https://github.com/addyosmani/agent-skills/tree/main/skills/performance-optimization), an MIT-licensed collection of production-grade engineering skills for AI coding agents.

License: MIT.

Quote from the skill body, verbatim: *"Performance work without measurement is guessing — and guessing leads to premature optimization that adds complexity without improving what matters."* The Core Web Vitals thresholds and the rationalizations table (especially "it's fast on my machine") are the operational expression of that stance.