Skip to main content

Development setup

This page is for working on the hosted product's public parts: the server, Nova, the web app, the edge Worker, the contracts and the specs. To build games with the engine, you do not need any of this: start with Quickstart.

What works from a public clone​

WorksDoes not work without the private parts
The server and the web app at http://localhost:3000Worker runs: the sandbox snapshot needs the private bundling CLI (npm run snapshot:pack stops with one sentence)
Accounts, the feed, the shared-game page, the play pagenpm run starter:upload, npm run android:backfill, npm run web:backfill (they export games)
Chatting with Nova (with an Anthropic API key)The iOS and Android apps and the App Clip
The edge Worker under wrangler dev: the proxy, live progress, the meterGenerated phone contracts (npm run contracts writes the web files only)
npm run typecheck, npm run lint, npm test, npm run build
npm run contracts, npm run parity, npm run db:migrate

Nova answers and starts runs locally, but without a sandbox snapshot a run fails at its sandbox step, and Nova treats it as a failure on the platform's side (she retries once, then gives up). See What is open and what is private.

Prerequisites​

  • Node 24 (engines in the root package.json) and npm.
  • A Postgres database. The server uses @neondatabase/serverless, so a Neon database or branch fits best. Use a database of your own, never one a deployment uses.
  • An Anthropic API key, for Nova.
  • Optional: a Vercel Blob token (chat pictures and uploads), and a Cloudflare account for wrangler.

The server​

npm install
cp .env.example .env.local # then fill it in (below)
npm run db:migrate # applies db/migrations to DATABASE_URL
npm run dev # next dev on :3000: the web app, the API, Nova at /eve/v1/*, the workflows

npm run dev sets NODE_OPTIONS=--network-family-autoselection-attempt-timeout=2000, which gives each address of a host two seconds to connect instead of Node's default, so database calls do not time out on slow networks.

The smallest .env.local for the web app and Nova:

VariableValue
DATABASE_URLYour database's connection string
APP_SESSION_SECRETAny long random string
INTERNAL_API_SECRETAny long random string
ANTHROPIC_API_KEYYour key; Nova needs it
PUBLIC_BASE_URLhttp://localhost:3000 (.env.example has the hosted value)
CRESCENT_EDGE_URL, REALTIME_SECRETEmpty, or a local edge (below)
CRESCENT_REQUIRE_SIGN_INoff, unless you set up Google sign-in with GOOGLE_WEB_CLIENT_ID
BLOB_READ_WRITE_TOKENOptional: picture uploads in the chat

CRESCENT_APP_URL defaults to http://localhost:3000; set it when next dev runs on another port. Every other variable in .env.example is for real runs or the hosted product, and each has a comment. Deploy lists them by step.

Locally the web app runs games on the other loopback name: open the app on http://localhost:3000 and games load from http://127.0.0.1:3000, or the other way round (src/web/play.ts).

The edge Worker​

cd edge
npm install
npm run typecheck
printf 'REALTIME_SECRET=any-local-test-secret\n' > .dev.vars # git-ignored, never commit
npx wrangler dev --local --var ORIGIN_URL:http://localhost:3000 # proxies to next dev, serves /rt/* on :8787

To send the server's events through it, set CRESCENT_EDGE_URL=http://localhost:8787 and the same REALTIME_SECRET in .env.local. A sandbox runs on the provider's network and cannot reach a Worker on your machine, so live events from a real run need a deployed edge.

To try the meter against a stand-in for Anthropic, also pass --var ANTHROPIC_UPSTREAM:http://localhost:<port> and put ANTHROPIC_API_KEY and INTERNAL_API_SECRET in .dev.vars.

After editing edge/wrangler.jsonc, run npx wrangler types without a .dev.vars present, and commit the regenerated worker-configuration.d.ts.

Contracts, specs and docs​

npm run contracts -- --check # generated web files are current
npm run parity # what each app is missing
npm --prefix docs-site run start -- --port 3100 # this site

See Three apps, one product.

Troubleshooting​

SymptomCause
Every edge page answers 503ORIGIN_URL is unset or still the placeholder
The edge answers 508ORIGIN_URL points at the Worker itself
/rt/* answers 503REALTIME_SECRET is not set on the edge
The app site association file answers 502The origin returned something that is not JSON, often a deployment-protection page
A run fails at once with "No Claude credential"No ANTHROPIC_API_KEY where the workflow runs
A run fails with "DAYTONA_SNAPSHOT is not configured"No sandbox snapshot; expected in a public clone
Making a game answers sign_in_requiredSign-in is on: set CRESCENT_REQUIRE_SIGN_IN=off locally, or sign in with Google