Install
$ agentstack add skill-yosefhayim-dufflebag-web-perf-ci ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Web Performance CI (Core Web Vitals)
Put a measured performance budget between a change and production. Three gates, each watching a different truth:
| Layer | Tool | Answers | Runs | | --- | --- | --- | --- | | Lab | Lighthouse CI (lhci autorun) | "Did this PR regress in a controlled test?" | every PR | | Field | Chrome UX Report (CrUX) API | "What do real users actually experience?" | after deploy / weekly | | RUM | web-vitals (optional) | "Which element/script caused it, per page?" | in the live app |
The budget numbers are the same everywhere (one SSOT): LCP ≤ 2.5s · INP ≤ 200ms · CLS ≤ 0.1, plus FCP ≤ 1.8s, TTFB ≤ 0.8s, Lighthouse performance ≥ 0.90. Field data comes from the Chrome UX Report (CrUX) API — Google is retiring CrUX data from PageSpeed Insights, so runCrux.mjs reads CrUX directly while PSI stays the lab source. New here? read TECH-GLOSSARY.md first; the model is in CONTEXT.md.
Ground rule
INP is a field-only metric — it needs a real user interacting, so Lighthouse's lab run can't produce it. In the lab gate we assert Total Blocking Time (TBT) as INP's proxy; the true INP comes from the field (PSI/CrUX) and your RUM. Never claim an INP number from a lab run.
Front door — grill first, then wire (via grill-me)
Interview the user one question at a time; recommend an answer for each, and if the repo already answers it, explore the repo instead of asking. Walk the tree in order — each answer changes what you write:
- Which surfaces do we gate? → recommend the homepage + the two highest-traffic templates (a listing + a detail page), not every route.
- How does the site run for a test? (
staticDistDira built folder ·startServerCommanda dev server · a deployed preview URL) → auto-detect frompackage.json+ host: Astro/Vite/Next static export →staticDistDir; an app server →startServerCommand; Cloudflare Pages/Vercel PR previews → preview URL. - Enforce or observe first? → recommend shipping assertions as
warnfor ~1–2 weeks to learn the baseline, then flip the Core Web Vitals toerror. - Do we have field data? (a PSI API key + enough traffic for CrUX) → recommend adding
PSI_API_KEYas a repo secret; if traffic is thin, CrUX will beNONE— lean on lab + your own RUM until it fills. - Wire RUM now? (web-vitals in the app → which sink: your
/rumendpoint, GA4, etc.) → recommend yes only if a sink exists; otherwise defer and note it. - Where do results land? (
temporary-public-storagePR link vs a self-hosted LHCI server) → recommendtemporary-public-storageto start.
Setup workflow
Run once the interview settles. Reuse the shipped templates/ and scripts/ — copy and adapt, don't hand-roll:
- Detect the stack + run mode (step 2 above). Confirm the build command and the served URL/dir.
- Write
lighthouserc.jsonat repo root fromtemplates/lighthouserc.json; set thecollectblock to the detected run mode and keep the Core Web Vitals assertions. Full option map:reference/lighthouse-ci.md. - Write the lab workflow
.github/workflows/lighthouse-ci.ymlfromtemplates/lighthouse-ci.yml(checkout → setup-node →npm ci→ build if present →npx @lhci/cli autorun). - Wire the field check (Lab + Field): copy
scripts/runCrux.mjs(the durable field source) to.github/perf/and add.github/workflows/field-check.ymlfrom the template (runs on successfuldeployment_status+ weekly cron). Add aPSI_API_KEYsecret — a Google key with both the PageSpeed Insights API and the Chrome UX Report API enabled. It readstemplates/budgets.jsonand exits non-zero when a real-user Core Web Vital ispoor; "no CrUX record" (low traffic) passes. Also copyrunPagespeed.mjsif you want an on-demand lab check via PSI. - (Optional) RUM — copy
templates/web-vitals.jsinto the app entry, pointENDPOINTat the sink,npm i web-vitals. It uses the attribution build so a bad score names its cause. Details:reference/web-vitals-rum.md. - Verify — locally:
npx @lhci/cli autorunagainst a build, andnode scripts/runPagespeed.mjs https://your-url --strategy=mobilewith a key. Show the before/after and the exact files written; get approval before committing.
Canonical lab budget (lighthouserc.json)
{
"ci": {
"collect": { "staticDistDir": "./dist", "numberOfRuns": 3 },
"assert": {
"preset": "lighthouse:recommended",
"assertions": {
"categories:performance": ["error", { "minScore": 0.9 }],
"largest-contentful-paint": ["error", { "maxNumericValue": 2500 }],
"cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }],
"total-blocking-time": ["error", { "maxNumericValue": 200 }],
"first-contentful-paint": ["warn", { "maxNumericValue": 1800 }],
"server-response-time": ["warn", { "maxNumericValue": 800 }]
}
},
"upload": { "target": "temporary-public-storage" }
}
}
Swap collect for the run mode: { "startServerCommand": "npm run start", "url": ["http://localhost:3000/"] } or { "url": ["https://preview.example.com/"] }. total-blocking-time is the lab stand-in for INP.
Field check (Chrome UX Report API)
Real-user field data comes from the CrUX API — the durable source, since PSI is dropping its CrUX (loadingExperience) data. PSI stays useful for the lab score.
# real-user Core Web Vitals (p75) — exits 1 on a "poor" vital, passes if no CrUX record
node scripts/runCrux.mjs https://example.com --form-factor=PHONE --key=$PSI_API_KEY
# lab score (+ legacy PSI field data while it lasts)
node scripts/runPagespeed.mjs https://example.com --strategy=mobile --key=$PSI_API_KEY
runCrux.mjs reads each vital's 75th percentile, falls back from the exact URL to the origin, and treats "no CrUX record" (low traffic) as a pass. Endpoints + response shapes: reference/crux-api.md (field), reference/pagespeed-insights.md (lab).
Honest scope — what we do NOT wire
mod_pagespeed/ ngx_pagespeed (PageSpeed Module) — Google archived it (~2021). Do optimization at build time (bundler, image pipeline) and at the CDN edge instead. Name it, don't install it.- Google Hosted Libraries CDN — browser cache partitioning (~2020) erased the shared-cache win; self-host/bundle is faster now (one less third-party DNS+TLS hop).
- Google Public DNS (8.8.8.8) — a client-side resolver choice, not a CI gate; the real TTFB lever is a fast CDN/DNS for your own domain.
Files
CONTEXT.md— the lab/field/RUM model and where each metric is observableTECH-GLOSSARY.md— every acronym (LCP, INP, CLS, CrUX, RUM, TTFB, …)README.md— harness setup (API key), script + template catalog, a full examplereference/lighthouse-ci.md— lighthouserc, presets, budgets,autorun, GitHub Actionreference/pagespeed-insights.md— PSI v5 endpoint (lab source; PSI field data is deprecating)reference/crux-api.md— CrUX API endpoint, request/response — the durable field sourcereference/web-vitals-rum.md— the RUM snippet, attribution, sending to analyticsscripts/runCrux.mjs— zero-dep CrUX API field checker (p75 real-user vitals) → exits 1 on a poor vitalscripts/runPagespeed.mjs— zero-dep PSI v5 checker → lab score (+ legacy field), exits 1 on breachtemplates/—lighthouserc.json,lighthouse-ci.yml,field-check.yml,budgets.json,web-vitals.js
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: YosefHayim
- Source: YosefHayim/dufflebag
- License: MIT
- Homepage: https://www.npmjs.com/package/ys-dufflebag
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.