Arguments: [path | URL]. Wherever <arguments> appears below, substitute the text the user typed after the skill name.
/pwa-expert:pwa-audit
Adversarial PWA audit. Two modes, auto-detected from <arguments>:
- Live URL mode: if the argument starts with
http:// or https://, fetch the page with Playwright, parse the manifest, test install criteria, check security headers, test offline behavior, and measure Core Web Vitals on the landing page.
- Local code mode: otherwise, treat the argument as a path (default: current working directory). Locate the manifest file, service worker source, registration call, iOS meta tag block, and security-header configuration in the codebase. Parse and check.
Setup
Delegate this audit to the pwa-architect agent. The agent must read the relevant references from the pwa-development skill on-demand (not all upfront), targeting each section of the audit.
Reference reading order, as audit sections are reached:
- Manifest checks:
references/manifest.md, references/production-checklist.md §1.
- Install criteria and prompts:
references/install-flows.md.
- Service worker logic:
references/service-workers.md.
- Security headers:
references/security.md.
- Offline behavior:
references/service-workers.md and references/storage-persistence.md.
- Performance metrics:
references/performance.md.
- Push notifications:
references/push-notifications.md.
- Framework-specific files:
references/frameworks-tooling.md.
Mode A: Live URL
If <arguments> is a URL, use the playwright-skill tools:
- Launch a browser and navigate to the URL.
- Fetch
/manifest.webmanifest (and fall back to /manifest.json). Validate as JSON. Run the manifest checklist from production-checklist.md §1.
- Check the service worker registration: look for a
<script> registering navigator.serviceWorker.register(...), or for an existing controller via navigator.serviceWorker.controller.
- Check the install criteria from
install-flows.md: manifest valid, display not browser, SW registered with fetch handler, HTTPS, 192+512 PNG icons present.
- Check meta tags:
apple-mobile-web-app-capable, apple-mobile-web-app-status-bar-style, apple-mobile-web-app-title, apple-touch-icon, theme-color, viewport.
- Check security headers via response headers: HTTPS plus HSTS, CSP presence (warn if
'unsafe-eval' is allowed), Cross-Origin-Opener-Policy, Cross-Origin-Embedder-Policy.
- Test offline behavior: route the page through
page.context().setOffline(true), reload, and confirm a non-broken response (offline page or cached navigation).
- Measure Core Web Vitals on the landing page (LCP, CLS at least; INP requires interaction). Compare against
performance.md thresholds.
If playwright-skill is unavailable, tell the user to install it from its upstream marketplace (claude plugin marketplace add lackeyjb/playwright-skill, then claude plugin install playwright-skill@playwright-skill), and meanwhile fall back to suggesting manual checks and explain what each would verify. In that fallback path, the audit should still produce a structured report with explicit "could not verify" markers for any item that required browser automation.
Live-mode auth note: if the target URL is behind authentication, ask the user via AskUserQuestion whether to run the audit against a public route only, or whether the user can provide login steps. Never attempt to bypass auth.
Mode B: Local code
If <arguments> is a path or omitted, search the codebase:
- Find the manifest:
Glob for manifest.webmanifest, manifest.json, app/manifest.ts (Next.js 14+), src/manifest.ts. Parse and verify against production-checklist.md §1.
- Find the SW source:
Glob for sw.js, sw.ts, service-worker.js, service-worker.ts, app/sw.ts (Serwist), ngsw-config.json (Angular). Read and audit caching strategies, skipWaiting / clients.claim use, cleanup in activate, offline fallback.
- Find the SW registration:
Grep for serviceWorker.register, workbox-window, Workbox(, Serwist(, or Next.js implicit registration via @serwist/next.
- Find iOS meta tags:
Grep for apple-mobile-web-app-capable. Confirm the full block from manifest.md §"iOS meta tag block".
- Find security headers: read
next.config.* (Next.js headers function), vite.config.* plus any server plugin, nginx.conf / .htaccess if present, firebase.json hosting.headers, vercel.json headers. Check HSTS, CSP, COOP, COEP, Permissions-Policy.
- Find Web Push:
Grep for pushManager.subscribe, setVapidDetails, web-push. If found, audit the subscription flow and server-side delivery against push-notifications.md.
- Find storage usage:
Grep for localStorage., IDBDatabase, openDB(, navigator.storage. Flag anti-patterns from storage-persistence.md (for example, localStorage used for large data).
- Detect framework via
package.json and configs. Apply framework-specific checks from frameworks-tooling.md (Vite vite-plugin-pwa config, Serwist app/sw.ts, Angular ngsw-config.json structure).
If the codebase contains a build artifact directory (dist/, .next/, build/), do not audit the generated SW from there. Always work from source. Generated SW files are derivative and may be stale relative to config.
Common defects to look for
Patterns the audit should treat as Critical until proven otherwise:
- A service worker that calls
self.skipWaiting() without a coordinated client reload. Causes mid-session resource version mismatches and broken navigations.
- A
cache.addAll([...]) precache list with no version suffix or hash strategy. Caches go stale forever after first install.
- An offline fallback page that itself fetches uncached subresources. The fallback fails open in network outages.
- A manifest with
display: "standalone" but no maskable icon at 192 and 512. Android adaptive launchers fall back to a generated badge.
- A CSP that includes
'unsafe-inline' for script-src in production. Treat as Critical unless paired with a nonce or hash strategy.
- Web Push subscriptions persisted without
expirationTime handling or a server-side resubscribe path. Silent delivery failures accumulate.
Patterns to flag as Important:
- A service worker fetch handler that calls
event.respondWith(fetch(event.request)) unconditionally. Adds latency for zero caching benefit.
- A manifest
start_url lacking a tracking parameter (for example ?source=pwa). Analytics cannot distinguish installed-app sessions.
- An
apple-touch-icon smaller than 180×180 or with transparency. iOS renders a black background on the Home Screen.
Output
Write a markdown report to stdout (or a file if the user asked) with this structure:
# PWA Audit Report
**Target:** <path or URL>
**Mode:** <local | live>
**Date:** YYYY-MM-DD
## Summary
<one paragraph: overall posture, biggest risks>
## Critical findings
### C1: <short title>
- **Location:** <file:line> or <URL fragment>
- **Issue:** <one sentence>
- **Impact:** <one sentence>
- **Fix:** <concrete change with code if applicable>
- **Reference:** `references/<file>.md` §<heading>
## Important findings
(same format)
## Nice-to-have findings
(same format)
## Verified passes
(short list of categories where the implementation is correct)
Severity buckets:
- Critical: ships a defect (install will fail; Web Push will not deliver on iOS; SW will not update; CSP allows XSS; missing HTTPS).
- Important: degrades the experience (no maskable icons;
skipWaiting() without coordinated reload; no offline fallback; INP > 200ms at p75).
- Nice-to-have: polish (no Window Controls Overlay; no scope_extensions; no shortcuts beyond the minimum).
For each finding, cite the file and line in local mode, or the URL plus the manifest field or DOM selector in live mode.
Numbering convention: C1, C2, ... for Critical, I1, I2, ... for Important, N1, N2, ... for Nice-to-have. Stable IDs let the user reference findings in follow-up prompts.
Fix guidance must be concrete. Prefer a code snippet or an exact path-and-value change over a vague "consider improving this". If the fix is large, link to the relevant reference section and summarize the first concrete step.
iOS caveat
If the target is iOS-focused, prepend the report with a clear note that Safari Web Inspector cannot inspect installed Home Screen PWAs. Live-mode audit therefore covers only the in-browser experience, not the post-install standalone state.
Concrete consequence: behaviors that only manifest once the app is added to the Home Screen (standalone display, status bar styling, safe-area insets, splash screens, Web Push permission in iOS 16.4+) cannot be observed remotely. Recommend that the user run a manual install-and-launch pass on a real iOS device, ideally on the lowest supported iOS version in their target matrix.
If the user has access to a Mac plus a wired iOS device, recommend the desktop Safari "Develop" menu attached to the in-Safari tab. This is the closest available approximation to inspecting the installed app but still does not reach the installed standalone surface.
1---2name: pwa-audit3description: Checks manifest, install criteria, offline behavior, security headers and performance, locally or against a live URL, citing file and line. TRIGGER WHEN: auditing a PWA, or verifying one is installable and production-ready.4---56> Arguments: `[path | URL]`. Wherever `<arguments>` appears below, substitute the text the user typed after the skill name.78<!-- Generated by the Daodan compiler for codex. Edit the kernel, never this file. -->910# /pwa-expert:pwa-audit1112Adversarial PWA audit. Two modes, auto-detected from `<arguments>`:1314- **Live URL mode:** if the argument starts with `http://` or `https://`, fetch the page with Playwright, parse the manifest, test install criteria, check security headers, test offline behavior, and measure Core Web Vitals on the landing page.15- **Local code mode:** otherwise, treat the argument as a path (default: current working directory). Locate the manifest file, service worker source, registration call, iOS meta tag block, and security-header configuration in the codebase. Parse and check.1617## Setup1819Delegate this audit to the `pwa-architect` agent. The agent must read the relevant references from the `pwa-development` skill on-demand (not all upfront), targeting each section of the audit.2021Reference reading order, as audit sections are reached:2223- Manifest checks: `references/manifest.md`, `references/production-checklist.md` §1.24- Install criteria and prompts: `references/install-flows.md`.25- Service worker logic: `references/service-workers.md`.26- Security headers: `references/security.md`.27- Offline behavior: `references/service-workers.md` and `references/storage-persistence.md`.28- Performance metrics: `references/performance.md`.29- Push notifications: `references/push-notifications.md`.30- Framework-specific files: `references/frameworks-tooling.md`.3132## Mode A: Live URL3334If `<arguments>` is a URL, use the `playwright-skill` tools:35361. Launch a browser and navigate to the URL.372. Fetch `/manifest.webmanifest` (and fall back to `/manifest.json`). Validate as JSON. Run the manifest checklist from `production-checklist.md` §1.383. Check the service worker registration: look for a `<script>` registering `navigator.serviceWorker.register(...)`, or for an existing controller via `navigator.serviceWorker.controller`.394. Check the install criteria from `install-flows.md`: manifest valid, `display` not `browser`, SW registered with `fetch` handler, HTTPS, 192+512 PNG icons present.405. Check meta tags: `apple-mobile-web-app-capable`, `apple-mobile-web-app-status-bar-style`, `apple-mobile-web-app-title`, `apple-touch-icon`, `theme-color`, `viewport`.416. Check security headers via response headers: HTTPS plus HSTS, CSP presence (warn if `'unsafe-eval'` is allowed), `Cross-Origin-Opener-Policy`, `Cross-Origin-Embedder-Policy`.427. Test offline behavior: route the page through `page.context().setOffline(true)`, reload, and confirm a non-broken response (offline page or cached navigation).438. Measure Core Web Vitals on the landing page (LCP, CLS at least; INP requires interaction). Compare against `performance.md` thresholds.4445If `playwright-skill` is unavailable, tell the user to install it from its upstream marketplace (`claude plugin marketplace add lackeyjb/playwright-skill`, then `claude plugin install playwright-skill@playwright-skill`), and meanwhile fall back to suggesting manual checks and explain what each would verify. In that fallback path, the audit should still produce a structured report with explicit "could not verify" markers for any item that required browser automation.4647Live-mode auth note: if the target URL is behind authentication, ask the user via `AskUserQuestion` whether to run the audit against a public route only, or whether the user can provide login steps. Never attempt to bypass auth.4849## Mode B: Local code5051If `<arguments>` is a path or omitted, search the codebase:52531. Find the manifest: `Glob` for `manifest.webmanifest`, `manifest.json`, `app/manifest.ts` (Next.js 14+), `src/manifest.ts`. Parse and verify against `production-checklist.md` §1.542. Find the SW source: `Glob` for `sw.js`, `sw.ts`, `service-worker.js`, `service-worker.ts`, `app/sw.ts` (Serwist), `ngsw-config.json` (Angular). Read and audit caching strategies, `skipWaiting` / `clients.claim` use, cleanup in `activate`, offline fallback.553. Find the SW registration: `Grep` for `serviceWorker.register`, `workbox-window`, `Workbox(`, `Serwist(`, or Next.js implicit registration via `@serwist/next`.564. Find iOS meta tags: `Grep` for `apple-mobile-web-app-capable`. Confirm the full block from `manifest.md` §"iOS meta tag block".575. Find security headers: read `next.config.*` (Next.js headers function), `vite.config.*` plus any `server` plugin, `nginx.conf` / `.htaccess` if present, `firebase.json` `hosting.headers`, `vercel.json` `headers`. Check HSTS, CSP, COOP, COEP, Permissions-Policy.586. Find Web Push: `Grep` for `pushManager.subscribe`, `setVapidDetails`, `web-push`. If found, audit the subscription flow and server-side delivery against `push-notifications.md`.597. Find storage usage: `Grep` for `localStorage.`, `IDBDatabase`, `openDB(`, `navigator.storage`. Flag anti-patterns from `storage-persistence.md` (for example, `localStorage` used for large data).608. Detect framework via `package.json` and configs. Apply framework-specific checks from `frameworks-tooling.md` (Vite vite-plugin-pwa config, Serwist app/sw.ts, Angular ngsw-config.json structure).6162If the codebase contains a build artifact directory (`dist/`, `.next/`, `build/`), do not audit the generated SW from there. Always work from source. Generated SW files are derivative and may be stale relative to config.6364## Common defects to look for6566Patterns the audit should treat as Critical until proven otherwise:6768- A service worker that calls `self.skipWaiting()` without a coordinated client reload. Causes mid-session resource version mismatches and broken navigations.69- A `cache.addAll([...])` precache list with no version suffix or hash strategy. Caches go stale forever after first install.70- An offline fallback page that itself fetches uncached subresources. The fallback fails open in network outages.71- A manifest with `display: "standalone"` but no maskable icon at 192 and 512. Android adaptive launchers fall back to a generated badge.72- A CSP that includes `'unsafe-inline'` for `script-src` in production. Treat as Critical unless paired with a nonce or hash strategy.73- Web Push subscriptions persisted without `expirationTime` handling or a server-side resubscribe path. Silent delivery failures accumulate.7475Patterns to flag as Important:7677- A service worker fetch handler that calls `event.respondWith(fetch(event.request))` unconditionally. Adds latency for zero caching benefit.78- A manifest `start_url` lacking a tracking parameter (for example `?source=pwa`). Analytics cannot distinguish installed-app sessions.79- An `apple-touch-icon` smaller than 180×180 or with transparency. iOS renders a black background on the Home Screen.8081## Output8283Write a markdown report to stdout (or a file if the user asked) with this structure:8485```86# PWA Audit Report8788**Target:** <path or URL>89**Mode:** <local | live>90**Date:** YYYY-MM-DD9192## Summary9394<one paragraph: overall posture, biggest risks>9596## Critical findings9798### C1: <short title>99- **Location:** <file:line> or <URL fragment>100- **Issue:** <one sentence>101- **Impact:** <one sentence>102- **Fix:** <concrete change with code if applicable>103- **Reference:** `references/<file>.md` §<heading>104105## Important findings106107(same format)108109## Nice-to-have findings110111(same format)112113## Verified passes114115(short list of categories where the implementation is correct)116```117118Severity buckets:119120- **Critical:** ships a defect (install will fail; Web Push will not deliver on iOS; SW will not update; CSP allows XSS; missing HTTPS).121- **Important:** degrades the experience (no maskable icons; `skipWaiting()` without coordinated reload; no offline fallback; INP > 200ms at p75).122- **Nice-to-have:** polish (no Window Controls Overlay; no scope_extensions; no shortcuts beyond the minimum).123124For each finding, cite the file and line in local mode, or the URL plus the manifest field or DOM selector in live mode.125126Numbering convention: `C1, C2, ...` for Critical, `I1, I2, ...` for Important, `N1, N2, ...` for Nice-to-have. Stable IDs let the user reference findings in follow-up prompts.127128Fix guidance must be concrete. Prefer a code snippet or an exact path-and-value change over a vague "consider improving this". If the fix is large, link to the relevant reference section and summarize the first concrete step.129130## iOS caveat131132If the target is iOS-focused, prepend the report with a clear note that Safari Web Inspector cannot inspect installed Home Screen PWAs. Live-mode audit therefore covers only the in-browser experience, not the post-install standalone state.133134Concrete consequence: behaviors that only manifest once the app is added to the Home Screen (standalone display, status bar styling, safe-area insets, splash screens, Web Push permission in iOS 16.4+) cannot be observed remotely. Recommend that the user run a manual install-and-launch pass on a real iOS device, ideally on the lowest supported iOS version in their target matrix.135136If the user has access to a Mac plus a wired iOS device, recommend the desktop Safari "Develop" menu attached to the in-Safari tab. This is the closest available approximation to inspecting the installed app but still does not reach the installed standalone surface.