Architecture
vibe-starter is two things in one repository: a secure base application, and a registry of optional feature modules that a skill composes into the base.
The base
Cloning the repo gives you a complete, deployable, secure marketing site. The base owns:
app/— routing only (App Router). Pages, layouts, error boundaries, health check, SEO.lib/— cross-cutting concerns:env(typed, validated),security/csp,site,utils,rate-limit, and thelegalmodel.components/— the design system (components/ui), site chrome, consent UI, theme.content/legalandlegal.config.ts— the source of truth for the legal pages.
The base never assumes a database or auth. A marketing site or a waitlist needs neither.
The registry
registry/<name>/ holds optional modules. Each has a module.json manifest and a files/
directory mirrored into the app on install. Modules are copied in, shadcn-style — there is no
hidden framework and no runtime dependency on the registry.
registry/payments-stripe/
├─ module.json
├─ files/ # mirrored to the project root
└─ README.md
The installer
pnpm vibe add <module> (implemented in scripts/) does the work:
- Resolves
dependsOnand installs dependencies first. - Copies
files/into the app and records them in.vibe/installed.json. - Merges
dependencies,devDependencies, andscriptsintopackage.json. - Appends new env keys to
.env.example. - Regenerates these files from every installed module, so the app stays consistent:
lib/legal/modules.generated.ts— subprocessors, cookies, and data collected.lib/security/csp.generated.ts— extra CSP sources.lib/env.generated.ts— validated schema for module env vars.lib/db/schema/index.ts— a barrel of every module's Drizzle tables.lib/config-plugins/index.ts— composesnext.configwrappers (used byi18n, Sentry).lib/auth/plugins/index.tsandlib/auth/client-plugins/index.ts— Better Auth server and client plugins (used byteams-orgs,auth-passkeys,auth-2fa).lib/auth/social/index.ts— merges eachlib/auth/social/*.tsprovider into thesocialProvidersobject Better Auth consumes (used byauth-social).
When a module overwrites an existing file (for example an auth escape hatch replacing
middleware.ts), it must declare the path in its manifest's overwrites list, and the original is
copied to .vibe/backups/<module>/ first. The security core — next.config.ts, lib/env.ts,
lib/security/, lib/consent/, and every *.generated.ts file — can never be replaced by a
module. The lockfile records a SHA-256 hash of every installed file, so vibe doctor can tell a
locally edited file from a registry update, and vibe update refuses to overwrite local edits
without --force.
pnpm vibe remove <module> reverses the file copy, restores any backed-up originals, and
regenerates the same files, refusing to remove a module another installed module depends on.
The skills
.claude/skills/ holds four skills that operate this machinery:
vibe-starterinterviews the user and runs the installer.vibe-buildadds features by hand while enforcing the security checklist.vibe-securityaudits the result.vibe-legalkeeps the legal pages true to what is installed.
Why generated files instead of editing in place
Editing TypeScript source programmatically is fragile. Instead, each concern the modules extend (legal, CSP, env, database schema) has a generated file that the installer rewrites wholesale from the set of installed modules. This is deterministic, reversible, and easy to reason about: the generated file is always exactly the sum of what is installed.