Skip to content
AdStack Engineering Docs
Esc
navigateopen⌘Jpreview
On this page

Getting started

Clone, install, configure, and run AdStack locally, plus the commands you will use every day.

Requirements

  • Bun. The project uses Bun as package manager and runtime. Never npm, npx, yarn, or pnpm. Use bunx for global CLIs.
  • Node 22.12 or newer, only for the docs site in docs/.
  • Access to the Cloudflare account and the Railway staging database.

Install and run

bun install
bun run dev

bun run dev runs scripts/dev.ts, not a raw vite command. The dev server shares the staging database, so local development reads and writes the same rows staging does. There is no separate local database.

Environment

Secrets live in .env for the app and .dev.vars for the Workers, which is the Cloudflare convention. Nothing secret belongs on a command line or in a commit.

Two prefixes, two meanings:

Prefix Visibility Notes
VITE_ Public, in the client bundle Feature flags and public URLs
no prefix Server only Cloudflare bindings and secrets, rotatable without redeploy

Worker secrets are set per worker with wrangler secret put <NAME> --name <worker>. The full list for the app worker is documented in the comment block at the bottom of wrangler.jsonc.

Commands

Command What it does
bun run dev Dev server
bun run check typecheck + lint + check, the gate before any commit
bun run typecheck tsc --noEmit, zero errors is enforced
bun run lint Ultracite (Biome preset) in check mode
bun run test Vitest
bun run build Vite build, also regenerates routeTree.gen.ts
bun run smoke Runtime resolution checks (prompts resolve, modules load)
bun run knip Dead-code detection
Command What it does
bun run db:sql "SELECT ..." Run a query. Never use psql with a password on the command line.
bun run db:migrate Apply pending migrations from db/migrations/
bun run db:status Show which migrations have run
Command What it does
bun run check:truth Asserts registry = database = prompt files
bun run sync:prompts --diff <slug> Show the difference between a prompt file and the DB
bun run sync:prompts --apply <slug> Push the file to the database
bun run sync:prompts --pull <slug> Pull an admin UI edit back into the file
bun run infra:snapshot Regenerate .claude/project/infra.md from Cloudflare
Command Target
push to staging Cloudflare Workers Builds rebuilds adstack-staging
cd cloudflare-agents && bunx wrangler deploy --config wrangler.jsonc Agents worker, manual
cd workers && bunx wrangler deploy Pipeline worker, manual

Two gaps worth knowing

Neither the linter nor the build type-checks:

  • Ultracite is a Biome preset. It does formatting and single-file style rules. It has no cross-file knowledge, so it cannot see a function returning number where string was expected.
  • bun run build is plain vite build. Vite strips TypeScript with esbuild without checking it. A green build means the bundle assembled, nothing more.

bun run typecheck is the only thing that catches type errors, and it is enforced at zero.

Repo layout

  • components/ UI, grouped by surface (chat, images, offers, sheets, ui)
  • hooks/ React Query hooks and client state
  • lib/
    • registry.ts single source of truth for names
    • agents/registry.ts agent definitions for the chat loop
    • chat-v2/ the agentic loop
    • db/ Drizzle schema and data access
    • api/route-helpers.ts auth, ownership, credits, worker submit
  • src/
    • routes/ file-based routes, including routes/api/
    • pages/ the real screens
  • cloudflare-agents/ the LLM worker
  • workers/ the media and offer pipeline worker
  • db/migrations/ SQL migrations, the only way schema changes
  • prompts/ system.md and user.md per module
  • scripts/ dev, migrate, check-truth, sync-prompts, infra-snapshot, smoke
  • docs/ this documentation site

components/, hooks/, and lib/ live at the repo root, not under src/. src/ holds routes/ (including routes/api/) and pages/. Route files are thin wrappers; the real screens live in src/pages/app/.

Last updated on July 30, 2026

Was this page helpful?