kramme-cc-workflow/skills/kramme:code:performance/SKILL.md
(experimental) Measure-first performance discipline tied to Core Web Vitals (LCP, INP, CLS). Use when users or monitoring report slowness, CWV scores miss thresholds, performance requirements exist in the spec, you suspect a recent change introduced a regression, or you're building features that handle large datasets or high traffic. Enforces baseline measurement, single-bottleneck fixes, verification, and regression guards. Complements the review-time `kramme:performance-oracle` agent.
npx skillsauth add abildtoft/kramme-cc-workflow kramme:code:performanceInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Measure before optimizing. Performance work without measurement is guessing — and guessing leads to premature optimization that adds complexity without improving what matters. Profile first, identify the actual bottleneck, fix it, measure again. Optimize only what measurements prove matters.
kramme:code:optimize.| Metric | Good | Needs Improvement | Poor | | --- | --- | --- | --- | | LCP (Largest Contentful Paint) | ≤ 2.5 s | ≤ 4.0 s | > 4.0 s | | INP (Interaction to Next Paint) | ≤ 200 ms | ≤ 500 ms | > 500 ms | | CLS (Cumulative Layout Shift) | ≤ 0.1 | ≤ 0.25 | > 0.25 |
A change that regresses any metric from Good into Needs Improvement is a regression, even if the absolute number still looks fine. Full measurement commands, what each metric measures, mobile/desktop differences, and the noise floor live in references/core-web-vitals.md.
Each optimization is one pass through this loop:
1. MEASURE → Establish baseline with real data
2. IDENTIFY → Find the actual bottleneck (not assumed)
3. FIX → Address the specific bottleneck
4. VERIFY → Measure again, confirm improvement
5. GUARD → Add monitoring or tests to prevent regression
Before writing any optimization, emit a SIMPLICITY CHECK marker stating the smallest change that would clear the budget. Only expand beyond that if remeasurement proves it is not enough.
SIMPLICITY CHECK: <one-line summary of the smallest fix that would clear the budget>
If the fix you end up shipping is not the smallest version, write a second line explaining what forced the expansion. Every extra abstraction — a cache wrapper, a memoized selector, a code-split boundary — adds complexity. Only add it when a measurement demands it.
When profiling surfaces a second bottleneck outside the current slice — an N+1 query in an adjacent endpoint, a missing image dimension on a neighboring page, a useEffect that looks wrong but is not on the hot path — emit a NOTICED BUT NOT TOUCHING marker and keep going. Do not silently fix perf smells that are not on the measured bottleneck.
NOTICED BUT NOT TOUCHING: <the perf smell you saw>
Why skipping: <not on measured bottleneck / out of scope / deferred>
The reason: every "while I'm here" fix dilutes the before/after delta for the change you are measuring, and makes it impossible to attribute the gain cleanly.
Emit both markers in your response text, using the exact formats above, so a calling agent or reviewer can parse them.
Two complementary approaches — use both:
web-vitals library, Chrome User Experience Report, project APM): real user data in real conditions. Required to validate that a fix actually improved user experience, not just the synthetic number.Frontend:
// Synthetic: Lighthouse in Chrome DevTools (or CI)
// Chrome DevTools → Performance tab → Record
// RUM: web-vitals library in code
import { onCLS, onINP, onLCP } from "web-vitals";
onLCP(console.log);
onINP(console.log);
onCLS(console.log);
Backend:
// Response time logging
// Application Performance Monitoring (APM)
// Database query logging with timing
// Simple timing
console.time("db-query");
const result = await db.query(/* … */);
console.timeEnd("db-query");
Record the baseline number with units in the ticket or commit message. "Fast enough" is not a baseline.
Read references/triage.md now. It contains the frontend/backend symptom tables (symptom → likely cause → investigation), the "Where to start measuring" decision tree, and the six anti-pattern summaries. Use the symptom to pick what to profile first, and follow one branch of the tree per measurement.
Map the identified bottleneck to one of the six named anti-patterns in references/triage.md (N+1 queries, unbounded data fetching, missing image optimization, unnecessary re-renders, large bundle size, missing caching) and apply its canonical fix. Full before/after code examples live in references/anti-patterns.md.
The memoization trap. React.memo, useMemo, and useCallback everywhere is itself a perf anti-pattern: each adds bookkeeping cost and obscures render causes. Apply only when profiling shows a measured win — and document the measurement next to the memo.
Remeasure with the same tool, on the same device class, on the same network profile you used for the baseline. Then check:
If the change does not clear the budget, revert and re-identify — do not stack a second optimization on top of an unverified first one.
Lock in the fix so it cannot silently regress:
bundlesize or the bundler's built-in budget, fails CI when a route exceeds the limit.lhci autorun with score thresholds and CWV assertions in the PR pipeline.A fix without a guard is a fix that will regress the next time someone changes the code.
Set explicit budgets and enforce them in CI:
JavaScript bundle: < 200 KB gzipped (initial load)
CSS: < 50 KB gzipped
Images: < 200 KB per image (above the fold)
Fonts: < 100 KB total
API response time: < 200 ms (p95)
Time to Interactive: < 3.5 s on 4G
Lighthouse Performance score: ≥ 90
Enforce in CI:
# Bundle size check
npx bundlesize --config bundlesize.config.json
# Lighthouse CI
npx lhci autorun
Budgets are floors, not ceilings — a PR that adds 30 KB to the bundle without justifying it against the budget is a PR that should not merge. Example bundlesize.config.json, lighthouserc.json, and a custom regression test live in references/performance-checklist.md.
If these siblings are installed:
kramme:performance-oracle agent verifies measurements and bottleneck identification post-hoc. Following MEASURE/VERIFY discipline here makes that review mechanical.kramme:code:incremental: each optimization is one slice through the incremental loop. The five-step workflow fits inside a single increment; the budget becomes the increment's exit criterion.kramme:code:optimize owns repeatable harness-driven experiments across multiple variants; this skill owns one-shot review-and-fix performance passes where the bottleneck and fix are measured directly.These are the lies you will tell yourself to justify skipping the measurement or the guard. Each one has a correct response:
If you notice any of these, stop and return to step 1:
SIMPLICITY CHECK that is missing at the top of the fix.Before declaring a perf slice done, confirm every item:
NOTICED BUT NOT TOUCHING entry exists for every perf smell observed outside the measured bottleneck.If any item is unchecked, the slice is not done. Fix the gap or split the slice.
tools
Requires Linear MCP. Implements one Linear issue end to end, selects applicable code-review, convention, and PR-refactor gates, runs them to bounded convergence, verifies, and optionally opens the PR and iterates on CI and review feedback until green. Use when the user wants a single Linear issue taken from implementation through a clean Pull Request. Not for implementation-only work, SIW-tracked issues, stacked PRs, existing PR updates, or post-merge rollout.
development
Reviews PR and local changes for convention drift and overcaution against documented rules and mined peer-file practice. Use for new patterns, dependencies, abstractions, or defensive complexity that departs from established practice; every finding cites evidence. Supports --inline. Not for general code quality (use kramme:pr:code-review) or spec review (use kramme:siw:spec-audit --team).
testing
Charts huge or foggy initiatives into a local `.context` decision map and resolves one typed frontier ticket per session until the work is ready for SIW or another execution workflow. Use when the route to a destination cannot fit in one agent session or parallel workspaces need coordinated planning state. Not for clear specs, ordinary issue decomposition, implementation, or Linear-native tracking.
development
Investigates a question against primary sources and saves one cited Markdown artifact. Use for reading legwork: official docs/API facts, source-code or spec checks, standards, and first-party service behavior before planning or implementation. Not for making product or architecture decisions, implementing code, broad web search, secondary blog summaries, or uncited answers.