Perf hunter
15 production-grade Claude Code skills that turn it into a full-stack engineering agent — design, code, test, secure, ship. Also works with OpenAI Codex CLI. MIT.
npx -y skills add ak-ship/fullstack-agent-skills --skill perf-hunterAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Find and fix the actual bottleneck — not the one you assume. Profiles before optimizing, measures before and after, refuses to "rewrite for perf" without numbers. Covers React/Vue rendering, bundle size, database query plans, N+1 patterns, memory leaks, and Node.js event-loop lag. Use when the user says "make this faster", "why is this slow", "optimize this", "the page is laggy", "the query is slow", or "this endpoint times out".
SKILL.md
8.0 KB, as published. Nobody here has run it
perf-hunter — measure, fix, measure again
When to use this skill
Trigger when something is slow and someone wants it faster. Strong signals:
- "why is this slow?", "make this faster", "this is too slow"
- "the page takes 5 seconds to load"
- "the query times out"
- "we're hitting our function memory limit"
- A flame graph, profiler output, or DevTools screenshot pasted in
Do not trigger for: code style optimizations that don't have measured impact (use refactor-master), perceived perf issues without numbers ("it feels slow") — get numbers first.
The output contract
A perf change that:
- Has a before number — measured under realistic conditions, not synthetic best-case.
- Targets the actual bottleneck — identified by profiling, not guessing.
- Has an after number — same measurement, same conditions.
- Quantifies the trade-off — what got harder to maintain, what runtime cost moved where.
- Includes a regression test — a benchmark or a budget that fails if the perf regresses.
Without those four numbers and a regression test, it's not a perf fix — it's vibes.
Workflow
1 — Define "slow"
Get specific:
- What operation? (page load, API call, query, render, build)
- How slow? (p50, p95, p99 — averages lie)
- Compared to what? (target, prior version, competitor)
- Under what load? (1 user vs 1000, cache cold vs warm, payload size)
If the user can't answer those, ask. Optimizing the wrong p50 doesn't move the p95 the users notice.
2 — Measure before
Pick the right tool for the surface:
Frontend:
- Chrome DevTools Performance panel — record a real interaction, find the long tasks
- Lighthouse for page-load metrics (LCP, INP, CLS, TBT)
- React Profiler for component render times
webpack-bundle-analyzer/rollup-plugin-visualizer/source-map-explorerfor bundle size
Backend Node:
--proffor CPU profiling, thennode --prof-process→ flame chart with0xorclinic flameclinic doctorfor high-level (event-loop lag, GC, CPU, memory)clinic bubbleproffor async I/O patterns- For HTTP:
autocannonork6for load + percentiles
Database:
EXPLAIN ANALYZEfor the slow query (Postgres) — read the actual planpg_stat_statementsextension to find the queries burning the most time across the workloadEXPLAIN FORMAT=JSON(MySQL),db.collection.explain('executionStats')(Mongo)
Record numbers. Don't proceed without them.
3 — Diagnose
Common patterns and the smell they leave:
N+1 queries — code makes one query, then loops and queries per result. Smell: many identical queries in the log, total query count ~= result count.
- Fix:
IN (...)batch,JOIN, or a DataLoader-style batcher.
Sequential awaits when parallel works — for (const id of ids) { await fetch(id) } is N round-trips. Smell: latency scales with N.
- Fix:
await Promise.all(ids.map(fetch)). Cap concurrency withp-limitif needed.
Re-renders in React — child renders even when its props haven't changed. Smell: React Profiler shows wide flame.
- Fix: lift state,
useMemofor derived values,React.memofor components, stable references for callbacks. Don't sprinkle these — find the actual culprit first.
Bundle bloat — initial JS payload is 800kB+. Smell: Lighthouse LCP poor, FCP fine.
- Fix: dynamic
import()for non-critical routes, tree-shake (look forimport * as X), check for whole libraries imported for one function (date-fns sub-imports, lodash-es).
Missing indexes — sequential scan on a 10M-row table. Smell: EXPLAIN ANALYZE shows Seq Scan + high actual time.
- Fix: targeted index. Validate with
EXPLAIN ANALYZEthat the plan changed.
Bad index usage — index exists but planner skips it. Smell: EXPLAIN shows Filter after the scan rather than Index Cond.
- Fix: usually a type mismatch in the query (
WHERE id = '123'against integer column), or stale statistics (ANALYZE).
Memory leak — RSS climbs over hours/days, never plateaus. Smell: process restarts every N days "for hygiene".
- Fix: heap snapshots before/after a workload; look for unbounded caches, retained closures, untracked subscriptions, growing
Maps indexed by request ID.
Event-loop lag — Node app's response times balloon under load even though the work is async. Smell: clinic doctor shows lag > 50ms.
- Fix: usually a sync CPU-heavy step (JSON.parse of a huge body, regex, crypto on the request thread) — move to a worker_thread or off the request path.
4 — Fix the one thing
Apply the smallest change that addresses the diagnosis. Don't pre-optimize the next thing you "noticed while you were there".
5 — Measure after
Same tool, same scenario, same load. Record the new number. Report the delta in absolute and relative terms:
Before: p95 endpoint latency 1240ms
After: p95 endpoint latency 180ms (-85%)
Trade-off: added an in-memory index that uses ~40MB heap per worker.
If the after number didn't move, revert. The fix wasn't the right one.
6 — Lock the win
Add a regression guard:
- Backend: a perf test in CI (
autocannonork6with a p95 threshold) - Frontend: bundle-size budget (
@bundle-analyzer/cli, Next.jsexperimental.bundlePagesRouterDependencies, orbundlewatch) - DB: a query that the test suite runs
EXPLAIN ANALYZEon, asserting the plan uses the new index
Without a guard, the fix decays. The next refactor will un-do it silently.
Patterns and anti-patterns
✅ Do:
- Optimize the hot path. 80% of latency typically lives in 20% of the code. Profile.
- Cache at the right layer — closest to the consumer that can tolerate the staleness. Browser, CDN, app-memory, Redis, DB materialized view.
- For DB perf: read the plan. The plan tells the truth; intuition lies.
- Save a copy of the profile/flame chart in the PR — future you will need to know what the world looked like before.
❌ Don't:
- Don't add a cache without an invalidation plan. The bugs you create with a stale cache are worse than the latency you save.
- Don't
useMemoeverything in a React component. Memoization itself costs CPU and memory. Profile first. - Don't switch from REST to GraphQL "for perf". The wire format isn't usually the bottleneck.
- Don't rewrite in Rust/Go/etc. before you've fixed the obvious things in the current stack.
- Don't optimize what runs once. A 10x speedup on a script that runs at deploy time is worth nothing.
Example invocation
User: "Our
/api/dashboardendpoint takes 4 seconds. Make it fast."
- Get numbers: p95 is 4.2s, p99 is 7s, cache cold. Target: p95 < 500ms.
- Profile: turn on Postgres
log_min_duration_statement = 100. Make one request, check the log. - Diagnose: 47 queries logged. Looks like N+1 — for each org member, the code fetches their last 5 activities individually.
- Fix: replace with one batched query joining users + activities + filtering for "last 5 per user" via a window function. Single query, ~20ms.
- Measure after: p95 down to 180ms. Trade-off: query is longer to read, added a comment explaining the window function.
- Lock: add a
EXPLAIN ANALYZEassertion in the integration test that the plan uses the(user_id, created_at DESC)index. - Report: -96% latency, single query replaces 47, regression test in place.
See also
code-auditor— to find the N+1 patterns and unbounded loops before they're slowschema-architect— when the fix is an index that the schema is missingrefactor-master— when the perf fix is structural (e.g., pulling I/O out of a hot loop)