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
| Script | What it does |
|---|---|
bun run clean | Remove build artifacts and caches (.next, .turbo, dist), every node_modules, and generated typedefs |
bun run dev | Start both apps through portless on named .localhost URLs (bunx portless list shows them; branch-prefixed in a worktree) |
bun run devtools | Open 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.
| Script | What it does |
|---|---|
bun run auth:schema | Regenerate the Better Auth tables in packages/db/src/schema/auth.ts from packages/auth/src/schema.ts (--check only compares) |
bun run db:generate | Generate a migration from schema changes |
bun run db:migrate | Apply pending migrations |
bun run db:studio | Open Drizzle Studio to browse and edit data |
See Database for the loop these belong to.
Quality
| Script | What it does | In PR CI |
|---|---|---|
bun run check-types | Type-check every workspace, then the repo scripts and the test tree | yes |
bun run format | Oxfmt, writing fixes | no |
bun run format:check | Oxfmt, report only | yes |
bun run lint | Oxlint over the whole tree | yes |
bun run test | Build the shared packages, then run the whole suite from the repo-root tests/ mirror | yes |
bun run test:e2e | Run every *.e2e.test.ts against a stack that is already running | no |
A failing test or type error blocks the merge. The details worth knowing:
check-typesruns in passes: every workspace through Turbo, thencheck-types:scripts(tscover.github/scripts), thencheck-types:tests(onetscrun pertests/**/tsconfig.json).testbuildspackages/*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 publishedexports, which point atdist; 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=localwithAGENT_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_URLandE2E_WEB_URLdefault to the compose ports (localhost:4000,localhost:3000), and are refused unless local, since the suite writes through the API.E2E_POSTGRES_URLunlocks 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
| Script | What it does |
|---|---|
bun run build | Build every app with Turbo, then print each workspace's size. The same build the pre-commit hook runs |
bun run release:version | Print the version decision for the current release window as JSON; --write moves package.json to it |
bun run start | Serve 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
| Script | What it does |
|---|---|
bun run shadcn:update | Update 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
| Script | What it does |
|---|---|
bun run console:roles <grant|revoke|list> [email] [role] | Set a user's rung on the console role ladder |
granttakesowner,adminormember. It defaults toadmin, or toownerwhile the install has none, which is how a fresh install gets its first way in.revokereturns them touser.listshows 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
| Script | When | What it does |
|---|---|---|
postinstall | after bun install | Normalize the catalog: dependency entries |
prepare | after bun install | Install the Lefthook git hooks |
Next
- Code Quality: what
lint,format, andbuildenforce on every commit. - Architecture: the two apps and the packages these scripts drive.