{"id":"01ad560a-8275-4fdd-9140-e9a931f41288","shortId":"t59SrV","kind":"skill","title":"benchmark","tagline":"Performance regression detection using the browse daemon. Establishes\nbaselines for page load times, Core Web Vitals, and resource sizes.\nCompares before/after on every PR. Tracks performance trends over time.\nUse when: \"performance\", \"benchmark\", \"page speed\", \"lighthouse\", \"web","description":"## Preamble\n\n```bash\neval \"$(~/.vibestack/bin/vibe-slug 2>/dev/null)\" 2>/dev/null || SLUG=\"unknown\"\n_LEARN_FILE=\"${VIBESTACK_HOME:-$HOME/.vibestack}/projects/${SLUG:-unknown}/learnings.jsonl\"\nif [ -f \"$_LEARN_FILE\" ]; then\n  _LEARN_COUNT=$(wc -l < \"$_LEARN_FILE\" 2>/dev/null | tr -d ' ')\n  echo \"LEARNINGS: $_LEARN_COUNT entries loaded\"\n  if [ \"$_LEARN_COUNT\" -gt 5 ] 2>/dev/null; then\n    ~/.vibestack/bin/vibe-learnings-search --limit 5 2>/dev/null || true\n  fi\nelse\n  echo \"LEARNINGS: none yet\"\nfi\n```\n\nYou are a **Performance Engineer** who has optimized apps serving millions of requests. You know that performance doesn't degrade in one big regression — it dies by a thousand paper cuts. Each PR adds 50ms here, 20KB there, and one day the app takes 8 seconds to load and nobody knows when it got slow.\n\n---\n\n## SETUP\n\n```bash\n# vibestack does not include a browse daemon.\necho \"BROWSE_NOT_AVAILABLE\"\n```\n\nIf `BROWSE_NOT_AVAILABLE`: skip all `$B` commands and use text-only fallbacks (curl, open, direct HTTP checks).\n\n## User-invocable\nWhen the user types `/benchmark`, run this skill.\n\n## Arguments\n- `/benchmark <url>` — full performance audit with baseline comparison\n- `/benchmark <url> --baseline` — capture baseline (run before making changes)\n- `/benchmark <url> --quick` — single-pass timing check (no baseline needed)\n- `/benchmark <url> --pages /,/dashboard,/api/health` — specify pages\n- `/benchmark --diff` — benchmark only pages affected by current branch\n- `/benchmark --trend` — show performance trends from historical data\n\n## Instructions\n\n### Phase 1: Setup\n\n```bash\neval \"$(~/.vibestack/bin/vibe-slug 2>/dev/null || echo \"SLUG=unknown\")\"\nmkdir -p .vibestack/benchmark-reports\nmkdir -p .vibestack/benchmark-reports/baselines\n```\n\n### Phase 2: Page Discovery\n\nSame as /canary — auto-discover from navigation or use `--pages`.\n\nIf `--diff` mode:\n```bash\ngit diff $(gh pr view --json baseRefName -q .baseRefName 2>/dev/null || gh repo view --json defaultBranchRef -q .defaultBranchRef.name 2>/dev/null || echo main)...HEAD --name-only\n```\n\n### Phase 3: Performance Data Collection\n\nFor each page, collect comprehensive performance metrics:\n\n```bash\n$B goto <page-url>\n$B perf\n```\n\nThen gather detailed metrics via JavaScript:\n\n```bash\n$B eval \"JSON.stringify(performance.getEntriesByType('navigation')[0])\"\n```\n\nExtract key metrics:\n- **TTFB** (Time to First Byte): `responseStart - requestStart`\n- **FCP** (First Contentful Paint): from PerformanceObserver or `paint` entries\n- **LCP** (Largest Contentful Paint): from PerformanceObserver\n- **DOM Interactive**: `domInteractive - navigationStart`\n- **DOM Complete**: `domComplete - navigationStart`\n- **Full Load**: `loadEventEnd - navigationStart`\n\nResource analysis:\n```bash\n$B eval \"JSON.stringify(performance.getEntriesByType('resource').map(r => ({name: r.name.split('/').pop().split('?')[0], type: r.initiatorType, size: r.transferSize, duration: Math.round(r.duration)})).sort((a,b) => b.duration - a.duration).slice(0,15))\"\n```\n\nBundle size check:\n```bash\n$B eval \"JSON.stringify(performance.getEntriesByType('resource').filter(r => r.initiatorType === 'script').map(r => ({name: r.name.split('/').pop().split('?')[0], size: r.transferSize})))\"\n$B eval \"JSON.stringify(performance.getEntriesByType('resource').filter(r => r.initiatorType === 'css').map(r => ({name: r.name.split('/').pop().split('?')[0], size: r.transferSize})))\"\n```\n\nNetwork summary:\n```bash\n$B eval \"(() => { const r = performance.getEntriesByType('resource'); return JSON.stringify({total_requests: r.length, total_transfer: r.reduce((s,e) => s + (e.transferSize||0), 0), by_type: Object.entries(r.reduce((a,e) => { a[e.initiatorType] = (a[e.initiatorType]||0) + 1; return a; }, {})).sort((a,b) => b[1]-a[1])})})()\"\n```\n\n### Phase 4: Baseline Capture (--baseline mode)\n\nSave metrics to baseline file:\n\n```json\n{\n  \"url\": \"<url>\",\n  \"timestamp\": \"<ISO>\",\n  \"branch\": \"<branch>\",\n  \"pages\": {\n    \"/\": {\n      \"ttfb_ms\": 120,\n      \"fcp_ms\": 450,\n      \"lcp_ms\": 800,\n      \"dom_interactive_ms\": 600,\n      \"dom_complete_ms\": 1200,\n      \"full_load_ms\": 1400,\n      \"total_requests\": 42,\n      \"total_transfer_bytes\": 1250000,\n      \"js_bundle_bytes\": 450000,\n      \"css_bundle_bytes\": 85000,\n      \"largest_resources\": [\n        {\"name\": \"main.js\", \"size\": 320000, \"duration\": 180},\n        {\"name\": \"vendor.js\", \"size\": 130000, \"duration\": 90}\n      ]\n    }\n  }\n}\n```\n\nWrite to `.vibestack/benchmark-reports/baselines/baseline.json`.\n\n### Phase 5: Comparison\n\nIf baseline exists, compare current metrics against it:\n\n```\nPERFORMANCE REPORT — [url]\n══════════════════════════\nBranch: [current-branch] vs baseline ([baseline-branch])\n\nPage: /\n─────────────────────────────────────────────────────\nMetric              Baseline    Current     Delta    Status\n────────            ────────    ───────     ─────    ──────\nTTFB                120ms       135ms       +15ms    OK\nFCP                 450ms       480ms       +30ms    OK\nLCP                 800ms       1600ms      +800ms   REGRESSION\nDOM Interactive     600ms       650ms       +50ms    OK\nDOM Complete        1200ms      1350ms      +150ms   WARNING\nFull Load           1400ms      2100ms      +700ms   REGRESSION\nTotal Requests      42          58          +16      WARNING\nTransfer Size       1.2MB       1.8MB       +0.6MB   REGRESSION\nJS Bundle           450KB       720KB       +270KB   REGRESSION\nCSS Bundle          85KB        88KB        +3KB     OK\n\nREGRESSIONS DETECTED: 3\n  [1] LCP doubled (800ms → 1600ms) — likely a large new image or blocking resource\n  [2] Total transfer +50% (1.2MB → 1.8MB) — check new JS bundles\n  [3] JS bundle +60% (450KB → 720KB) — new dependency or missing tree-shaking\n```\n\n**Regression thresholds:**\n- Timing metrics: >50% increase OR >500ms absolute increase = REGRESSION\n- Timing metrics: >20% increase = WARNING\n- Bundle size: >25% increase = REGRESSION\n- Bundle size: >10% increase = WARNING\n- Request count: >30% increase = WARNING\n\n### Phase 6: Slowest Resources\n\n```\nTOP 10 SLOWEST RESOURCES\n═════════════════════════\n#   Resource                  Type      Size      Duration\n1   vendor.chunk.js          script    320KB     480ms\n2   main.js                  script    250KB     320ms\n3   hero-image.webp          img       180KB     280ms\n4   analytics.js             script    45KB      250ms    ← third-party\n5   fonts/inter-var.woff2    font      95KB      180ms\n...\n\nRECOMMENDATIONS:\n- vendor.chunk.js: Consider code-splitting — 320KB is large for initial load\n- analytics.js: Load async/defer — blocks rendering for 250ms\n- hero-image.webp: Add width/height to prevent CLS, consider lazy loading\n```\n\n### Phase 7: Performance Budget\n\nCheck against industry budgets:\n\n```\nPERFORMANCE BUDGET CHECK\n════════════════════════\nMetric              Budget      Actual      Status\n────────            ──────      ──────      ──────\nFCP                 < 1.8s      0.48s       PASS\nLCP                 < 2.5s      1.6s        PASS\nTotal JS            < 500KB     720KB       FAIL\nTotal CSS           < 100KB     88KB        PASS\nTotal Transfer      < 2MB       1.8MB       WARNING (90%)\nHTTP Requests       < 50        58          FAIL\n\nGrade: B (4/6 passing)\n```\n\n### Phase 8: Trend Analysis (--trend mode)\n\nLoad historical baseline files and show trends:\n\n```\nPERFORMANCE TRENDS (last 5 benchmarks)\n══════════════════════════════════════\nDate        FCP     LCP     Bundle    Requests    Grade\n2026-03-10  420ms   750ms   380KB     38          A\n2026-03-12  440ms   780ms   410KB     40          A\n2026-03-14  450ms   800ms   450KB     42          A\n2026-03-16  460ms   850ms   520KB     48          B\n2026-03-18  480ms   1600ms  720KB     58          B\n\nTREND: Performance degrading. LCP doubled in 8 days.\n       JS bundle growing 50KB/week. Investigate.\n```\n\n### Phase 9: Save Report\n\nWrite to `.vibestack/benchmark-reports/{date}-benchmark.md` and `.vibestack/benchmark-reports/{date}-benchmark.json`.\n\n## Important Rules\n\n- **Measure, don't guess.** Use actual performance.getEntries() data, not estimates.\n- **Baseline is essential.** Without a baseline, you can report absolute numbers but can't detect regressions. Always encourage baseline capture.\n- **Relative thresholds, not absolute.** 2000ms load time is fine for a complex dashboard, terrible for a landing page. Compare against YOUR baseline.\n- **Third-party scripts are context.** Flag them, but the user can't fix Google Analytics being slow. Focus recommendations on first-party resources.\n- **Bundle size is the leading indicator.** Load time varies with network. Bundle size is deterministic. Track it religiously.\n- **Read-only.** Produce the report. Don't modify code unless explicitly asked.","tags":["benchmark","vibestack","timurgaleev","agent-skills","ai-agents","claude-code","cursor-ide","developer-tools","kiro","mcp","prompt-engineering","slash-commands"],"capabilities":["skill","source-timurgaleev","skill-benchmark","topic-agent-skills","topic-ai-agents","topic-claude-code","topic-cursor-ide","topic-developer-tools","topic-kiro","topic-mcp","topic-prompt-engineering","topic-slash-commands"],"categories":["vibestack"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/timurgaleev/vibestack/benchmark","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add timurgaleev/vibestack","source_repo":"https://github.com/timurgaleev/vibestack","install_from":"skills.sh"}},"qualityScore":"0.457","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 15 github stars · SKILL.md body (8,724 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:06:19.503Z","embedding":null,"createdAt":"2026-05-18T19:06:19.503Z","updatedAt":"2026-05-18T19:06:19.503Z","lastSeenAt":"2026-05-18T19:06:19.503Z","tsv":"'+0.6':640 '+15':592 '+150':618 '+16':632 '+270':647 '+3':654 '+30':598 '+50':611,676 '+60':688 '+700':625 '+800':604 '-03':875,883,891,899,907 '-10':876 '-12':884 '-14':892 '-16':900 '-18':908 '/.vibestack/bin/vibe-learnings-search':87 '/.vibestack/bin/vibe-slug':42,253 '/api/health':227 '/benchmark':194,199,206,214,224,230,239 '/canary':271 '/dashboard':226 '/dev/null':44,46,70,85,91,255,294,303 '/learnings.jsonl':57 '/projects':54 '0':339,391,405,426,444,468,469,480 '0.48':815 '1':249,481,488,490,660,741 '1.2':636,677 '1.6':821 '1.8':638,679,813,837 '10':721,734 '100kb':831 '120':509 '1200':523 '1200ms':616 '120ms':590 '1250000':534 '130000':554 '1350ms':617 '135ms':591 '1400':527 '1400ms':623 '15':406 '1600ms':603,664,910 '180':550 '180kb':754 '180ms':768 '2':43,45,69,84,90,254,266,293,302,673,746 '2.5':819 '20':711 '2000ms':976 '2026':874,882,890,898,906 '20kb':136 '2100ms':624 '25':716 '250kb':749 '250ms':760,787 '280ms':755 '2mb':836 '3':311,659,685,751 '30':726 '320000':548 '320kb':744,775 '320ms':750 '38':880 '380kb':879 '4':492,756 '4/6':848 '40':888 '410kb':887 '42':530,630,896 '420ms':877 '440ms':885 '450':512 '450000':538 '450kb':645,689,895 '450ms':596,893 '45kb':759 '460ms':901 '48':904 '480ms':597,745,909 '5':83,89,561,764,866 '50':702,843 '500kb':826 '500ms':705 '50kb/week':925 '50ms':134 '520kb':903 '58':631,844,912 '6':730 '600':519 '600ms':609 '650ms':610 '7':798 '720kb':646,690,827,911 '750ms':878 '780ms':886 '8':144,851,920 '800':515 '800ms':602,663,894 '85000':542 '850ms':902 '85kb':652 '88kb':653,832 '9':928 '90':556,840 '95kb':767 'a.duration':403 'absolut':706,961,975 'actual':810,947 'add':133,789 'affect':235 'alway':968 'analysi':378,853 'analyt':1009 'analytics.js':757,781 'app':108,142 'argument':198 'ask':1049 'async/defer':783 'audit':202 'auto':273 'auto-discov':272 'avail':167,171 'b':174,323,325,334,380,401,411,429,450,486,487,847,905,913 'b.duration':402 'baselin':10,204,207,209,222,493,495,500,564,579,581,585,858,952,957,970,993 'baseline-branch':580 'baserefnam':290,292 'bash':40,156,251,283,322,333,379,410,449 'before/after':22 'benchmark':1,34,232,867 'benchmark.json':939 'benchmark.md':935 'big':122 'block':671,784 'branch':238,505,574,577,582 'brows':7,162,165,169 'budget':800,804,806,809 'bundl':407,536,540,644,651,684,687,714,719,871,923,1019,1030 'byte':347,533,537,541 'captur':208,494,971 'chang':213 'check':186,220,409,681,801,807 'cls':793 'code':773,1046 'code-split':772 'collect':314,318 'command':175 'compar':21,566,990 'comparison':205,562 'complet':370,521,615 'complex':983 'comprehens':319 'consid':771,794 'const':452 'content':352,361 'context':999 'core':15 'count':64,76,81,725 'css':437,539,650,830 'curl':182 'current':237,567,576,586 'current-branch':575 'cut':130 'd':72 'daemon':8,163 'dashboard':984 'data':246,313,949 'date':868,934,938 'day':140,921 'defaultbranchref':299 'defaultbranchref.name':301 'degrad':119,916 'delta':587 'depend':692 'detail':329 'detect':4,658,966 'determinist':1033 'die':125 'diff':231,281,285 'direct':184 'discov':274 'discoveri':268 'doesn':117 'dom':365,369,516,520,607,614 'domcomplet':371 'dominteract':367 'doubl':662,918 'durat':396,549,555,740 'e':465,475 'e.initiatortype':477,479 'e.transfersize':467 'echo':73,95,164,256,304 'els':94 'encourag':969 'engin':104 'entri':77,358 'essenti':954 'establish':9 'estim':951 'eval':41,252,335,381,412,430,451 'everi':24 'exist':565 'explicit':1048 'extract':340 'f':59 'fail':828,845 'fallback':181 'fcp':350,510,595,812,869 'fi':93,99 'file':50,61,68,501,859 'filter':416,434 'fine':980 'first':346,351,1016 'first-parti':1015 'fix':1007 'flag':1000 'focus':1012 'font':766 'fonts/inter-var.woff2':765 'full':200,373,524,621 'gather':328 'gh':286,295 'git':284 'googl':1008 'got':153 'goto':324 'grade':846,873 'grow':924 'gt':82 'guess':945 'head':306 'hero-image.webp':752,788 'histor':245,857 'home':52 'home/.vibestack':53 'http':185,841 'imag':669 'img':753 'import':940 'includ':160 'increas':703,707,712,717,722,727 'indic':1024 'industri':803 'initi':779 'instruct':247 'interact':366,517,608 'investig':926 'invoc':189 'javascript':332 'js':535,643,683,686,825,922 'json':289,298,502 'json.stringify':336,382,413,431,457 'kb':648,655 'key':341 'know':114,150 'l':66 'land':988 'larg':667,777 'largest':360,543 'last':865 'lazi':795 'lcp':359,513,601,661,818,870,917 'lead':1023 'learn':49,60,63,67,74,75,80,96 'lighthous':37 'like':665 'limit':88 'load':13,78,147,374,525,622,780,782,796,856,977,1025 'loadeventend':375 'main':305 'main.js':546,747 'make':212 'map':385,420,438 'math.round':397 'mb':637,639,641,678,680,838 'measur':942 'metric':321,330,342,498,568,584,701,710,808 'million':110 'miss':694 'mkdir':259,262 'mode':282,496,855 'modifi':1045 'ms':508,511,514,518,522,526,593,599,605,612,619,626 'name':308,387,422,440,545,551 'name-on':307 'navig':276,338 'navigationstart':368,372,376 'need':223 'network':447,1029 'new':668,682,691 'nobodi':149 'none':97 'number':962 'object.entries':472 'ok':594,600,613,656 'one':121,139 'open':183 'optim':107 'p':260,263 'page':12,35,225,229,234,267,279,317,506,583,989 'paint':353,357,362 'paper':129 'parti':763,996,1017 'pass':218,817,823,833,849 'perf':326 'perform':2,27,33,103,116,201,242,312,320,571,799,805,863,915 'performance.getentries':948 'performance.getentriesbytype':337,383,414,432,454 'performanceobserv':355,364 'phase':248,265,310,491,560,729,797,850,927 'pop':389,424,442 'pr':25,132,287 'preambl':39 'prevent':792 'produc':1040 'q':291,300 'quick':215 'r':386,417,421,435,439,453 'r.duration':398 'r.initiatortype':393,418,436 'r.length':460 'r.name.split':388,423,441 'r.reduce':463,473 'r.transfersize':395,428,446 'read':1038 'read-on':1037 'recommend':769,1013 'regress':3,123,606,627,642,649,657,698,708,718,967 'relat':972 'religi':1036 'render':785 'repo':296 'report':572,930,960,1042 'request':112,459,529,629,724,842,872 'requeststart':349 'resourc':19,377,384,415,433,455,544,672,732,736,737,1018 'responsestart':348 'return':456,482 'rule':941 'run':195,210 'save':497,929 'script':419,743,748,758,997 'second':145 'serv':109 'setup':155,250 'shake':697 'show':241,861 'singl':217 'single-pass':216 'size':20,394,408,427,445,547,553,635,715,720,739,1020,1031 'skill':197 'skill-benchmark' 'skip':172 'slice':404 'slow':154,1011 'slowest':731,735 'slug':47,55,257 'sort':399,484 'source-timurgaleev' 'specifi':228 'speed':36 'split':390,425,443,774 'status':588,811 'summari':448 'take':143 'terribl':985 'text':179 'text-on':178 'third':762,995 'third-parti':761,994 'thousand':128 'threshold':699,973 'time':14,30,219,344,700,709,978,1026 'timestamp':504 'top':733 'topic-agent-skills' 'topic-ai-agents' 'topic-claude-code' 'topic-cursor-ide' 'topic-developer-tools' 'topic-kiro' 'topic-mcp' 'topic-prompt-engineering' 'topic-slash-commands' 'total':458,461,528,531,628,674,824,829,834 'tr':71 'track':26,1034 'transfer':462,532,634,675,835 'tree':696 'tree-shak':695 'trend':28,240,243,852,854,862,864,914 'true':92 'ttfb':343,507,589 'type':193,392,471,738 'unknown':48,56,258 'unless':1047 'url':503,573 'use':5,31,177,278,946 'user':188,192,1004 'user-invoc':187 'vari':1027 'vendor.chunk.js':742,770 'vendor.js':552 'via':331 'vibestack':51,157 'vibestack/benchmark-reports':261,933,937 'vibestack/benchmark-reports/baselines':264 'vibestack/benchmark-reports/baselines/baseline.json':559 'view':288,297 'vital':17 'vs':578 'warn':620,633,713,723,728,839 'wc':65 'web':16,38 'width/height':790 'without':955 'write':557,931 'yet':98","prices":[{"id":"fc47d5bf-1a87-45be-a117-4a58f196fbd5","listingId":"01ad560a-8275-4fdd-9140-e9a931f41288","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"timurgaleev","category":"vibestack","install_from":"skills.sh"},"createdAt":"2026-05-18T19:06:19.503Z"}],"sources":[{"listingId":"01ad560a-8275-4fdd-9140-e9a931f41288","source":"github","sourceId":"timurgaleev/vibestack/benchmark","sourceUrl":"https://github.com/timurgaleev/vibestack/tree/main/skills/benchmark","isPrimary":false,"firstSeenAt":"2026-05-18T19:06:19.503Z","lastSeenAt":"2026-05-18T19:06:19.503Z"}],"details":{"listingId":"01ad560a-8275-4fdd-9140-e9a931f41288","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"timurgaleev","slug":"benchmark","github":{"repo":"timurgaleev/vibestack","stars":15,"topics":["agent-skills","ai-agents","claude-code","cursor-ide","developer-tools","kiro","mcp","prompt-engineering","slash-commands"],"license":"mit","html_url":"https://github.com/timurgaleev/vibestack","pushed_at":"2026-05-18T18:19:05Z","description":"vibestack is a portable skill pack for AI coding agents. Slash commands like /office-hours, /ship, /investigate, /tdd, /review install once and work across every agent that supports the Agent Skills open standard — Claude Code, Cursor, Kiro, and a growing list of others. ","skill_md_sha":"9c3d71de2923e4e959af5a1b10efcbc9c582f33c","skill_md_path":"skills/benchmark/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/timurgaleev/vibestack/tree/main/skills/benchmark"},"layout":"multi","source":"github","category":"vibestack","frontmatter":{"name":"benchmark","description":"Performance regression detection using the browse daemon. Establishes\nbaselines for page load times, Core Web Vitals, and resource sizes.\nCompares before/after on every PR. Tracks performance trends over time.\nUse when: \"performance\", \"benchmark\", \"page speed\", \"lighthouse\", \"web vitals\",\n\"bundle size\", \"load time\".\nVoice triggers (speech-to-text aliases): \"speed test\", \"check performance\"."},"skills_sh_url":"https://skills.sh/timurgaleev/vibestack/benchmark"},"updatedAt":"2026-05-18T19:06:19.503Z"}}