ZeroStarter

Scripts

Every bun script, grouped by when you'd reach for it.

Every script lives in the root package.json; run any of them with bun run <name>. They're grouped below by when you actually reach for one.

Dev loop

ScriptWhat it does
bun run cleanRemove build artifacts and caches (.next, .turbo, dist), every node_modules, and generated typedefs
bun run devStart both apps through portless on named .localhost URLs (bunx portless list shows them; branch-prefixed in a worktree)
bun run devtoolsOpen Turborepo DevTools

PORTLESS=0 bun run dev uses fixed ports instead: web :3000, api :4000.

bun run clean deletes every node_modules and the generated typedefs, so re-run bun install afterward.

Database

bun run auth:schema runs the Better Auth CLI; each db:* script builds @packages/env first, then runs Drizzle Kit against packages/db.

ScriptWhat it does
bun run auth:schemaRegenerate the Better Auth tables in packages/db/src/schema/auth.ts from packages/auth/src/schema.ts (--check only compares)
bun run db:generateGenerate a migration from schema changes
bun run db:migrateApply pending migrations
bun run db:studioOpen Drizzle Studio to browse and edit data

See Database for the loop these belong to.

Quality

ScriptWhat it doesIn PR CI
bun run check-typesType-check every workspace, then the repo scripts and the test treeyes
bun run formatOxfmt, writing fixesno
bun run format:checkOxfmt, report onlyyes
bun run lintOxlint over the whole treeyes
bun run testBuild the shared packages, then run the whole suite from the repo-root tests/ mirroryes
bun run test:e2eRun every *.e2e.test.ts against a stack that is already runningno

A failing test or type error blocks the merge. The details worth knowing:

  • check-types runs in passes: every workspace through Turbo, then check-types:scripts (tsc over .github/scripts), then check-types:tests (one tsc run per tests/**/tsconfig.json).
  • test builds packages/* and regenerates the data-table font metrics first. The build comes first because a test reaches a shared package the way the apps do, through its published exports, which point at dist; without it a fresh checkout fails to resolve the import rather than failing an assertion. Turbo caches the build, so a repeat run costs milliseconds.

The end-to-end suite

bun run test:e2e is a golden suite: every contract response is snapshotted, and bun run test:e2e --update-snapshots accepts a deliberate change. It needs a running local-stage stack:

  • NODE_ENV=local with AGENT_SIGNIN_ENABLED=true, so the agent can sign in.
  • Both OAuth client ids set to any value, since the providers snapshot lists them.
  • E2E_API_URL and E2E_WEB_URL default to the compose ports (localhost:4000, localhost:3000), and are refused unless local, since the suite writes through the API.
  • E2E_POSTGRES_URL unlocks the flows that seed a second account.

It skips itself when no stack is named, so bun run test stays green without one. CI never names one, so nothing in CI runs this suite: run it yourself after a dependency refresh, which is what can move a library's internals under a snapshot.

Release / production

ScriptWhat it does
bun run buildBuild every app with Turbo, then print each workspace's size. The same build the pre-commit hook runs
bun run release:versionPrint the version decision for the current release window as JSON; --write moves package.json to it
bun run startServe the production build

release:version reports the last tag, the tree, what the window earned, and the larger of the two. The draft-PR workflow runs it on a push to canary whenever a release window is open, meaning main exists and canary is ahead of it; running it by hand only previews, and it needs no network. It reads the v* tags, so fetch them first: with tags present but none reachable from HEAD it stops rather than computing from v0.0.0.

The changelog, version bump, tag, and GitHub release are automated: you don't run them by hand. See Releases.

shadcn

ScriptWhat it does
bun run shadcn:updateUpdate every shadcn/ui component, then bun i

bun run shadcn:update overwrites everything under web/next/src/components/ui/, so hand-edits to those files are lost. Put durable customizations in .github/scripts/shadcn-customize.ts, which re-applies them after each sync; the shadcn-sync skill covers the workflow.

Console

ScriptWhat it does
bun run console:roles <grant|revoke|list> [email] [role]Set a user's rung on the console role ladder
  • grant takes owner, admin or member. It defaults to admin, or to owner while the install has none, which is how a fresh install gets its first way in.
  • revoke returns them to user.
  • list shows everyone with console access.

grant and revoke both record a line in Activity attributed to console:roles, since nobody is signed in when it runs.

Runs automatically

ScriptWhenWhat it does
postinstallafter bun installNormalize the catalog: dependency entries
prepareafter bun installInstall the Lefthook git hooks

Next

  • Code Quality: what lint, format, and build enforce on every commit.
  • Architecture: the two apps and the packages these scripts drive.