Claude Code skill

Your agent can't quietly wreck this codebase.

VanillaBun is a zero-dependency Bun foundation whose architecture is enforced by tests — and the Claude Code skill that teaches an agent the one rule that keeps it enforced.

/vanillabun

This page is the template, deployed. Same one process, no build step.

Every drift is individually reasonable

An agent doesn't destroy a codebase in one commit. It does it in forty defensible ones — and the last thing it touches is the check that would have told you.

“Just this one dependency.”

Then forty, and a lockfile nobody can audit.

“This file is getting long.”

Then it's 900 lines and every change touches it.

“The cap was too strict anyway.”

The check goes green. The architecture is already gone.

Three files do the work

  1. 1
    CLAUDE.md

    The contract. Auto-loaded into every session, so the agent starts knowing the rules instead of inferring them from the code.

  2. 2
    core/architecture.test.ts

    The enforcement. Nine invariants the compiler and test runner check on every run. Prose advises; tests enforce.

  3. 3
    .claude/skills/vanillabun

    The playbook. The build loop, the canonical shapes — and the failure-mode rule below, which is the whole point.

When a guard goes red: fix the code, never the guard.

Raising a cap, widening a name exclusion, loosening an assertion, deleting a test — each one makes the build pass. Each one is drift wearing a green check. The skill tells the agent to decompose or rename instead, every time.

If a cap is genuinely wrong, that's a deliberate architecture decision for a human to make out loud — never a side effect of getting a feature to pass.

Nine guards, checked every run

Not conventions in a style guide. Assertions in bun run verify.

Zero runtime npm deps

package.json dependencies must stay {}. Vendor the browser lib, or write it in a few lines.

core/ ≤ 450 LOC

The framework cannot quietly accrete. Over budget means move it to app/, or delete it.

File ≤ 200 LOC

A God file is a design failure, not a formatting one. Over the cap means decompose.

Function ≤ 70 LOC

Measured through the TypeScript compiler API — no new dependency just to count lines.

No junk-drawer names

util, helper, manager, misc. Name the domain, or don't add the file.

No exported mutable state

Exporting a mutable binding creates a hidden global anyone can write. Caches stay module-private.

Parameterized SQL only

No template interpolation into query(), prepare() or duck(). Ever.

Contract stays in sync

Every core/ file must be documented in CLAUDE.md, or the build goes red.

Vendored libs pinned

sha256 + provenance recorded. An unexpected mismatch is a supply-chain signal.

What you're building on

  • One Bun process is the whole app — Bun.serve, bun:sqlite, Bun.password, Bun.file.
  • No build step. Client TypeScript is transpiled on demand, per request, mtime-cached.
  • SSR every page, then boosted navigation swaps <main> — direct links, no-JS and SEO still work.
  • Heavy browser libs are vendored and hash-pinned, not installed. Still zero runtime deps.
  • Ships an adversarial architecture-reviewer agent for the design judgment tests can't reach.

Start

Open the template in Claude Code and type the skill. It reads the contract, copies the canonical shape, writes the test first, and won't call it done until bun run verify is green.

/vanillabun

See it running →