Install
$ agentstack add skill-bensheridanedwards-architectplaybook-bundle-build-audit ✓ 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 Used
- ✓ 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
/bundle-build-audit
Audit a TypeScript frontend's build pipeline and bundle output against an opinionated baseline organised in four layers — build configuration, bundle composition and size, asset and dependency hygiene, build performance — preceded by a diagnostic snapshot. Then offer to generate an implementation plan for the gaps.
The default mental model is TypeScript and React. The skill works across Vite, Next.js (App Router and Pages Router), Remix, Create React App, plain Webpack, plain Rollup, and Turbopack. Parcel and direct esbuild app builds are out of scope.
Static-first design with optional stats enrichment
This skill is read-only and never executes the build. Two modes:
- Static (default). Read configuration files (
vite.config.*,next.config.*,webpack.config.*,rollup.config.*,tsconfig.json),package.json, lockfiles,.gitignore, and continuous-integration workflow files. Bundle-composition and size checks degrade to "configured to do X" — there are no concrete numbers. - Static plus opt-in
--with-stats. When the flag is passed and a recognisable bundle-stats artefact exists at the expected path (dist/stats.json,.next/analyze/*.html,build/bundle-stats.json,dist/stats.htmlfromrollup-plugin-visualizer, orbundle-stats.jsonfromwebpack-bundle-analyzer), the skill reads it and uses real numbers for size, composition, and per-chunk checks.
The skill never runs the build itself. Running npm run build (or equivalent) is the responsibility of the user or a separate fix-and-validate skill — keeping this audit fully read-only is what makes it safe to run in any working tree at any time.
Usage
/bundle-build-audit # default: concise Top 5 + full report saved + ask about plan
/bundle-build-audit --worktree # create an isolated Git worktree, then run the audit there
/bundle-build-audit --learn # mid-level engineer teaching mode (detailed explanations + file/line examples)
/bundle-build-audit --teach # alias for --learn
/bundle-build-audit --with-stats # static plus enrichment from existing stats artefact
/bundle-build-audit --stats-path=path/to/stats.json # override the auto-detected stats artefact location
/bundle-build-audit --threshold-initial-bundle=300kb # override default 250kb (gzipped)
/bundle-build-audit --threshold-total-bundle=1.5mb # override default 1mb (gzipped)
/bundle-build-audit --threshold-build-time=90s # override default 60s (clean build)
/bundle-build-audit --threshold-incremental-build-time=15s # override default 10s
💡 Pro tip: Add --worktree to run this audit in an isolated Git worktree.
Threshold values accept human-friendly units: kb, mb, gb for sizes (interpreted as base-2 kilobytes, etc.); s, ms, m for time. The skill never accepts --apply.
The defaults baked into the skill are the recommended baseline for a typical modern React and TypeScript application. Threshold flags exist as an escape hatch for projects with deliberately different sensibilities; the canonical path to evolving the defaults themselves is /system-self-improve.
💡 Pro tip: Run /preflight --audit=bundle-build first to detect — and optionally install — the development dependency that makes --with-stats useful (a bundle analyser matching your build tool: webpack-bundle-analyzer, @next/bundle-analyzer, rollup-plugin-visualizer, or vite-bundle-visualizer). Skip if you already know the tooling is wired up.
The opinionated baseline
A check resolves to one of four statuses:
- present — the invariant holds.
- partial — most signals resolve, with a small number of exceptions.
- missing — a structural prerequisite is absent.
- violation — the audit identified concrete configuration or output that breaks the invariant.
Layer 0 is informational only and has no status.
Layer 0 — Diagnostic snapshot (always written, no pass/fail)
- Detected build tool and version (Vite 5.x, Next.js 14 App Router, Webpack 5, Rollup 4, Turbopack).
- Detected meta-framework (Next.js, Remix, Vite-React, Create React App, plain Vite, plain Webpack).
- Entry points and discovered route count when discoverable from the framework's conventions.
- Total bundle size and per-chunk breakdown — only when a stats artefact is available; otherwise "not measured".
- Top 10 largest dependencies in the bundle — only when stats are available.
- Browserslist resolved targets (run
npx browserslistmentally — the skill reads the configuration and does not execute). - Source-map mode: none, inline, separate file, or hidden with header.
- Build cache state: enabled, configured, and the location it points at.
Layer 1 — Build configuration soundness
| Check | Expectation | Violation signal | | --- | --- | --- | | Build tool present and pinned | A build tool is installed and its version is pinned in package.json (no ^ or ~ on the build tool itself). | Build tool missing, or pinned with a caret or tilde range. | | Browserslist explicit | A browserslist field exists in package.json, or a .browserslistrc file is present. | No browserslist configuration anywhere. | | Production mode enforced | The build script invokes the framework's production-build command and the continuous-integration workflow runs it with NODE_ENV=production. | NODE_ENV not set, or the build script invokes a development command. | | Source maps configured deliberately | Production builds emit source maps in an explicitly chosen mode (hidden, separate file, or fully off). | No source-map configuration whatsoever; the build tool's default is silently in use. | | Build output ignored from git | The build output directory (dist/, .next/, build/, out/) is in .gitignore. | Build output committed or not ignored. | | Production dependencies separated | No development-only packages (build tools, type definitions, test runners, linters, formatters, Storybook) appear in dependencies. | Development packages in dependencies. | | Deterministic build | The build script does not depend on environment-specific flags or interactive input. | Scripts containing --watch, interactive prompts, non-deterministic timestamps in output filenames. |
Layer 2 — Bundle composition and size
Defaults in parentheses; every threshold overridable via flags. Checks marked stats-required report partial (with a "stats artefact not present" gap) when running without --with-stats.
| Check | Expectation | Violation signal | | --- | --- | --- | | Initial bundle size budget (stats-required) | The initial JavaScript payload (entry chunk plus shared chunks loaded on first paint) is under the threshold (default 250 kilobytes gzipped). | Initial payload exceeds the threshold. | | Total bundle size budget (stats-required) | The full client-side JavaScript payload across all chunks is under the threshold (default 1 megabyte gzipped). | Total exceeds the threshold. | | Route-level code splitting | The build splits per route or per page. | Single-bundle output, or the framework's automatic route-splitting has been turned off. | | No duplicate dependencies | Each dependency appears exactly once in the bundle; React, React-DOM, and large utilities are not bundled twice. | Multiple copies detected in stats (when available); or multiple incompatible major versions in the lockfile. | | Large-library hygiene | Large libraries are imported with named imports or per-method paths so tree-shaking can remove what isn't used. | Patterns like import _ from 'lodash', import moment from 'moment', import * as X from 'large-lib' in source. | | Dynamic imports for heavy features | Heavy non-critical features (rich-text editors, charting libraries, code mirrors, video players, PDF renderers) are loaded with React.lazy or framework-equivalent dynamic imports. | Heavy libraries imported synchronously at the top level of an entry-reachable module. | | No development-only code in production | No unguarded console.log, no React DevTools shim, no debug-only code paths reachable in production builds. | Such patterns present in source without an if (process.env.NODE_ENV !== 'production') guard, or detected in built output when stats are available. |
Layer 3 — Asset and dependency hygiene
| Check | Expectation | Violation signal | | --- | --- | --- | | Image optimisation | Images use modern formats (WebP, AVIF) where the framework supports them. The framework's image primitive is used (next/image for Next.js, ` from @unpic/react or vite-plugin-image-optimizer for Vite). | Multi-megabyte PNGs or JPEGs in public/; Next.js project not using next/image for content imagery. | | Font handling | Fonts are subset, self-hosted (or via a CDN with font-display: swap), and preloaded for above-the-fold text. | Loading entire web-font families with no font-display; sourcing fonts from a script-blocking external host. | | CSS extraction | CSS is extracted into separate files in production builds, except for above-the-fold critical CSS. | CSS-in-JS configuration that ships styles inside JS chunks unconditionally without extraction. | | Static assets cacheable | Build output produces hashed filenames (main.[hash].js) so long-cache headers can be set safely. | Filenames without content hashes. | | No vendored dependencies | No copies of third-party packages live under src/ or vendor/. | Files matching the signature of a known package present in src/. | | sideEffects field declared | package.json has a sideEffects field set to false (or an array of files known to have side effects), so tree-shaking can remove unused exports. | Field absent. | | Bundle analyser available | A bundle-analysis tool is installed and runnable. Recognised: vite-bundle-visualizer, rollup-plugin-visualizer, @next/bundle-analyzer, webpack-bundle-analyzer`. | None present. |
Layer 4 — Build performance
| Check | Expectation | Violation signal | | --- | --- | --- | | Build cache enabled | The build tool's cache is enabled (Vite's dependency cache, Next.js .next/cache, Webpack cache: { type: 'filesystem' }, Turbopack defaults). | Cache disabled or configured to a discarded location. | | TypeScript incremental mode | tsconfig.json has incremental: true, or the project uses composite project references. | Neither enabled. | | Continuous-integration cache | The continuous-integration workflow caches the package-manager store and the build cache between runs. | No cache step in .github/workflows/*.yml (or equivalent), or the cache key is not derived from the lockfile hash. | | Bundle-size budget enforced in continuous integration | A bundle-size check runs in continuous integration and fails the build when the budget is exceeded (size-limit, bundlewatch, @next/bundle-analyzer with thresholds, or equivalent). | No such step detected. | | Build-time budget (stats-required) | Reported clean-build time is under the threshold (default 60 seconds), reported incremental rebuild time is under the threshold (default 10 seconds). Soft check — partial between threshold and 1.5 times threshold, violation above. | Measurements (when available from continuous-integration logs or local cache) exceed the thresholds. |
What this skill does
- Reads the knowledge graph when present. Soft dependency: if
graphify-out/graph.jsonexists, the skill uses community structure to suggest cleavage planes for code-splitting in the implementation plan. If absent, the audit still runs in full — the only loss is some intelligence in the remediation suggestions. - Confirms a Node.js project with a recognised build tool. Detects the build tool from
package.jsondependencies and configuration files. If none of the supported build tools is detected, the skill stops and tells the user. - Detects the meta-framework for the diagnostic snapshot.
- Locates a stats artefact when
--with-statsis set. Searches the conventional paths for the detected build tool, plus any path passed via--stats-path. Records the path or the absence in the snapshot. - Writes Layer 0 — the diagnostic snapshot to
.architect-audits/bundle-build-audit/snapshot.mdand prepends the same content tofindings.md. - Walks each check in the active layer list, applying any
--include,--exclude, and threshold overrides. Stats-required checks emitpartialwith a clear "no stats artefact" gap when running without enrichment. - Writes phase 1 outputs to
.architect-audits/bundle-build-audit/:
findings.md— diagnostic snapshot followed by check results, grouped by layer.findings.json— machine-readable.snapshot.md— diagnostic snapshot on its own.metadata.json— skill version, run timestamp, Graphify revision hash (when present), build tool, framework, stats artefact path (ornull), applied thresholds, applied filters.
- Phase 2 — offers to plan the gaps. Summarises the findings in chat and asks the user a single yes-or-no question:
> "Generate an implementation plan for the bundle and build gaps? (yes/no)"
On yes, writes .architect-audits/bundle-build-audit/implementation-plan.md describing exactly which configuration entries to add, which dependencies to swap, which dynamic imports to introduce, and which continuous-integration steps to add — ordered by layer and then by severity. The plan does not modify any project files.
On no, exits cleanly.
Implementation steps
Step 1 — Confirm the prerequisites
test -f package.json || { echo "bundle-build-audit: no package.json detected. This skill currently supports Node.js frontend projects only."; exit 1; }
Detect the build tool:
vitedependency → Vite.nextdependency → Next.js (with App Router or Pages Router based on directory layout).@remix-run/*dependency → Remix.react-scriptsdependency → Create React App.webpackdependency with awebpack.config.*→ plain Webpack.rollupdependency with arollup.config.*→ plain Rollup.@vercel/turbopackor Next.js with Turbopack opted in → Turbopack.
If none match, stop and tell the user the skill currently supports the listed tools only.
Step 2 — Locate the stats artefact (if --with-stats)
For each known build tool, check the conventional path:
- Vite with
rollup-plugin-visualizer:dist/stats.htmlordist/stats.json. - Next.js with
@next/bundle-analyzer:.next/analyze/client.html,.next/analyze/server.html. - Webpack with
webpack-bundle-analyzer:bundle-stats.jsonat the project root, ordist/bundle-stats.json. - Rollup with
rollup-plugin-visualizer:dist/stats.html,dist/stats.json.
Honour --stats-path over the conventional locations.
If --with-stats is set but no artefact is found, continue running with stats-required checks degrading to partial and add a clear "no stats artefact found at " line to the snapshot. Also print to the chat and prepend to findings.md: "--with-stats was requested but no bundle-stats artefact is available. If you have not installed a bundle analyser, run /preflight --audit=bundle-build --install to install one matching your build tool. Otherwise run npm run build (or your project's equivalent with the analyser enabled) to produce the artefact, then re-run with --with-stats." Record recoveryHint: "/preflight --audit=bundle-build --install" on each stats-required check that degraded to partial in findings.json.
Step 3 — Build the diagnostic snapshot
Read configuration files and (when available) the stats artefact. Compute the items listed in Layer 0. Write snapshot.md and prepend the same content to findings.md.
Step 4 — Resolve each check
For each check in the active layer list, walk its detection logic.
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: BenSheridanEdwards
- Source: BenSheridanEdwards/ArchitectPlaybook
- License: MIT
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.