Chloei is a Next.js 16 chat app backed by Vercel AI Gateway. It currently exposes a curated model selector that defaults to Qwen 3.7 Max and also includes Kimi K2.6, and offers optional Tavily web search and Better Auth email/password authentication with PostgreSQL-backed users and sessions.
- CLAUDE.md — architecture reference and conventions (request flow, agent runtime, tools, storage, auth, env vars). The best starting point for understanding the codebase; also read by Claude Code.
- docs/vercel-production-launch-readiness.md — production launch checklist (security, reliability, performance, rollback).
- Node.js 24.x
- pnpm 10.32.1
- PostgreSQL 16 for local auth, sessions, and thread storage
pnpm install
cp .env.example .env.local
# Fill DATABASE_URL, BETTER_AUTH_SECRET, BETTER_AUTH_URL, and AI_GATEWAY_API_KEY.
# Start PostgreSQL locally before running migrate.
pnpm migrate
pnpm devAdd AI_GATEWAY_API_KEY to .env.local before starting the app; optionally add TAVILY_API_KEY for Tavily search and extract tools. The app runs on http://localhost:3000.
To enable auth locally, provision PostgreSQL before running pnpm migrate and add:
DATABASE_URLAUTH_DATABASE_URLif Better Auth should use a different database from app dataBETTER_AUTH_SECRETBETTER_AUTH_URL=http://localhost:3000BETTER_AUTH_TRUSTED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000when you need multiple allowed originsBETTER_AUTH_COOKIE_DOMAIN=chloei.aiwhen you need shared sessions across trusted subdomains
To mirror Vercel Development locally, install the Vercel CLI, run vercel login, approve the device-login URL, verify the project link in .vercel/project.json, then run vercel env pull .env.local --yes. The pull overwrites .env.local, so preserve any local database/auth overrides you need.
For browser smoke tests on a fresh machine, install Playwright's browser dependencies once:
pnpm exec playwright install --with-deps chromiumpnpm dev: start the Next.js dev serverpnpm migrate: run both Better Auth and app-storage migrationspnpm auth:migrate: apply Better Auth schema changes to PostgreSQLpnpm app:migrate: apply app storage schema changes to PostgreSQLpnpm build: build the production apppnpm start: run the production Next.js serverpnpm bundle:budget: check built static JavaScript chunks against bundle budgetspnpm bundle:report: report built static JavaScript chunk headroom and largest first-load routespnpm test: run regression testspnpm test:smoke: run opt-in Playwright browser smoke tests againstSMOKE_BASE_URLpnpm test:smoke:mock: run the credential-free mocked Playwright smoke test used by CIpnpm test:smoke:mock:build: build the production app, then run the credential-free mocked smoke testpnpm lint: run blocking ESLint checkspnpm lint:fix: apply autofixable ESLint changespnpm format: write Prettier formatting changespnpm format:check: verify formatting without writing changespnpm typecheck: run TypeScript checks
- Sync local secrets when needed with
vercel env pull .env.local, then remove any stale keys the app no longer uses. - Run
pnpm test,pnpm lint,pnpm typecheck, andpnpm build. - Open a pull request to
mainand wait for the requiredchecksandVercelstatuses. - Smoke test the preview deployment: sign in, confirm models load, send one prompt, and verify thread persistence.
- Merge to
mainafter the preview passes, then confirm production is aliased to chloei.ai. - Run one authenticated production smoke test: sign in, load models, send a prompt, and verify an existing thread still reopens cleanly.
.env.example documents the supported environment variables. Required variables are:
AI_GATEWAY_API_KEY: required to enable/api/modelsand/api/agentDATABASE_URL: PostgreSQL connection string for Better AuthAUTH_DATABASE_URL: optional Better Auth database override; falls back toDATABASE_URLBETTER_AUTH_SECRET: Better Auth signing secretBETTER_AUTH_URL: public app origin used by Better Auth, such ashttp://localhost:3000; on Vercel previews it can be omitted so the deployment URL is inferred automaticallyBETTER_AUTH_TRUSTED_ORIGINS: optional comma-separated list of additional allowed originsBETTER_AUTH_COOKIE_DOMAIN: optional shared parent cookie domain for cross-subdomain sessions; keep this production-only when preview deployments usevercel.apphosts
Optional feature-enabling variables:
TAVILY_API_KEY: enables Tavily search and extract callable tools for chat requestsAGENT_TELEMETRY_RECORD_IO: feature gate; defaults off unless explicitly set or synced through Edge Config
Agent request limits, timeouts, and tool-step budgets are fixed safe constants in src/lib/server/agent-runtime-config.ts (no env knobs).
src/app/(home)/page.tsx: app entry for the home screensrc/app/(auth)/sign-in/page.tsx: public sign-in screensrc/app/(auth)/sign-up/page.tsx: public sign-up screensrc/app/api/auth/[...all]/route.ts: Better Auth route handlersrc/app/api/agent/route.ts: streaming agent endpointsrc/app/api/models/route.ts: available-models endpointsrc/components/agent: chat UI, prompt form, markdown rendering, and session statesrc/lib/server: Better Auth config, PostgreSQL setup, runtime config, and model streaming
- The current model list is defined in
src/lib/shared/llm/models.ts. /,/api/agent, and/api/modelsrequire an authenticated Better Auth session.- To share logins with another Chloei app, point both apps at the same Better Auth database and secret, set
BETTER_AUTH_COOKIE_DOMAINto the shared parent domain, and include every live subdomain inBETTER_AUTH_TRUSTED_ORIGINS. - App storage does not self-initialize on live requests. Vercel deployments in this repo run
pnpm migratebeforenext build.
pnpm test:smoke runs Playwright against SMOKE_BASE_URL or starts the local dev server at http://localhost:3000. Set SMOKE_EMAIL and SMOKE_PASSWORD for an existing test account before running the live authenticated smoke test. Optional SMOKE_PROMPT and SMOKE_EXPECTED_TEXT let you tune the live prompt assertion.
pnpm test:smoke:mock runs a CI-safe authenticated chat flow with E2E_MOCK_AUTH=1, in-memory thread storage, and a deterministic mock agent response against the production Next.js server. Run pnpm build first or use pnpm test:smoke:mock:build. It does not require Better Auth credentials, PostgreSQL, or AI provider API keys.