# Bundle Build Audit

> Audit build pipeline and bundle output (static-first with optional --with-stats enrichment). Checks configuration, composition, hygiene, and performance with optional implementation plan.

- **Type:** Skill
- **Install:** `agentstack add skill-bensheridanedwards-architectplaybook-bundle-build-audit`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [BenSheridanEdwards](https://agentstack.voostack.com/s/bensheridanedwards)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [BenSheridanEdwards](https://github.com/BenSheridanEdwards)
- **Source:** https://github.com/BenSheridanEdwards/ArchitectPlaybook/tree/main/bundle-build-audit

## Install

```sh
agentstack add skill-bensheridanedwards-architectplaybook-bundle-build-audit
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## 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.html` from `rollup-plugin-visualizer`, or `bundle-stats.json` from `webpack-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 browserslist` mentally — 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

1. **Reads the knowledge graph when present.** Soft dependency: if `graphify-out/graph.json` exists, 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.
2. **Confirms a Node.js project with a recognised build tool.** Detects the build tool from `package.json` dependencies and configuration files. If none of the supported build tools is detected, the skill stops and tells the user.
3. **Detects the meta-framework** for the diagnostic snapshot.
4. **Locates a stats artefact when `--with-stats` is 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.
5. **Writes Layer 0 — the diagnostic snapshot** to `.architect-audits/bundle-build-audit/snapshot.md` and prepends the same content to `findings.md`.
6. **Walks each check in the active layer list**, applying any `--include`, `--exclude`, and threshold overrides. Stats-required checks emit `partial` with a clear "no stats artefact" gap when running without enrichment.
7. **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 (or `null`), applied thresholds, applied filters.
8. **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

```bash
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:

- `vite` dependency → Vite.
- `next` dependency → Next.js (with App Router or Pages Router based on directory layout).
- `@remix-run/*` dependency → Remix.
- `react-scripts` dependency → Create React App.
- `webpack` dependency with a `webpack.config.*` → plain Webpack.
- `rollup` dependency with a `rollup.config.*` → plain Rollup.
- `@vercel/turbopack` or 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.html` or `dist/stats.json`.
- Next.js with `@next/bundle-analyzer`: `.next/analyze/client.html`, `.next/analyze/server.html`.
- Webpack with `webpack-bundle-analyzer`: `bundle-stats.json` at the project root, or `dist/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](https://github.com/BenSheridanEdwards)
- **Source:** [BenSheridanEdwards/ArchitectPlaybook](https://github.com/BenSheridanEdwards/ArchitectPlaybook)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-bensheridanedwards-architectplaybook-bundle-build-audit
- Seller: https://agentstack.voostack.com/s/bensheridanedwards
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
