Deployment
Deploy the public site, documentation, workspace, API service, and secure runner to Cloudflare.
LegionCode uses separate Cloudflare deployments behind one public product origin.
Deployment shape
| Public URL | Deployment |
|---|---|
legioncode.dev | Landing Pages project |
legioncode.dev/cloud/ | Cloud private-alpha access page |
legioncode.dev/docs/* | Docs static project routed at the edge |
legioncode.dev/docs/changelog/ | Changelog route in the docs project |
legioncode.dev/agents/* | Agents workspace routed through Pages |
brain.legioncode.dev | API service Worker |
api.legioncode.dev | Secure runner Worker and sandbox runtime |
The agents app is built with a /agents/ base path. OAuth callbacks should return users to the same public agents path.
Required bindings
Production requires the configured Cloudflare bindings for the API service, secure runner, artifacts, sessions, database access, and edge routing. Keep bindings environment-specific and verify them before promoting a deployment.
Set secrets with Wrangler rather than committing them:
- GitHub client secret, session secret, and GitHub token-encryption key;
- BYOK credential-encryption key and version;
- internal runtime-event secret;
- any managed provider credentials enabled for the environment.
The landing Pages project requires a D1 binding named WAITLIST_DB for Cloud access requests. Apply apps/landing/migrations/0001_waitlist.sql before enabling the waitlist form.
For private alpha, set PRIVATE_ALPHA_ACCESS_MODE=allowlist in production and list approved GitHub logins in PRIVATE_ALPHA_GITHUB_LOGINS.
Rename cutover
Changing deployment names from the former product name to the legioncode-*
targets is a coordinated infrastructure cutover. This repository change does
not provision or rename Cloudflare resources. Before switching traffic:
- Inventory and record the current Worker UUIDs and versions, Durable Object namespace IDs and classes, container application IDs, service bindings, routes, domains, DNS records, Pages project IDs and domains, R2 bucket metadata, D1/KV/Hyperdrive IDs, and required secret names. Prefer an in-place Worker or Pages rename when the provider preserves those identities; fetch the resources after each rename and stop if any dependency identity is not preserved.
- R2 buckets do not have a rename operation. Create the
legioncode-artifactsbucket only after recording the old bucket, copy objects without deleting the source, and verify every key, size, checksum, and custom metadata before directing reads to the new binding. Retain the old bucket for rollback. - If a Worker, Pages project, container, route, or Durable Object namespace
cannot preserve its identity in place, provision a destination only with an
explicit migration plan. Migrate Durable Object namespaces and state
explicitly, including
RUN_ENGINE_RUNTIME,RUN_ADMISSION_LIMITER,AGENT_RUNTIME, andSandbox; preserve the existing migration tags and record source and destination IDs. Never fall back to an empty namespace. - Recreate or transfer secrets and encrypted credentials, service bindings, OAuth callbacks, CORS origins, and deployment variables. Verify every dependency against the recorded inventory before traffic moves. Preserve the existing D1, KV, and Hyperdrive IDs rather than creating empty replacements.
- Switch traffic in one coordinated window after health checks pass for the landing, docs, Web, Brain, and secure runtime paths. Keep rollback records for every binding and route change.
Before step 5, execute this explicit freeze and drain sequence. Launch flags do not stop in-flight executions, scheduled retention, or transcript settlement writes by themselves:
- GET the Brain Worker schedules, record the exact response, then PUT an
explicit empty schedule array (
[]). Verify the readback is empty and wait for trigger propagation. Restore the captured schedule only after the final R2 delta check. - Set Brain
LAUNCH_EMERGENCY_SHUTOFF_MODE=block_runs, then query canonical lifecycle state until active runs, pending captures, checkouts, and admission leases are drained. Do not use sampled logs or container health as drain proof. - Set Secure API to
LAUNCH_EMERGENCY_SHUTOFF_MODE=block_session_and_execute. Let authorized cancellation and event settlement finish. Include both canonical and legacy chat history POST routes in the writer drain; authenticated history GET and replay remain available. - Set Secure API to
block_allonly after settlement is quiet. Verify both append routes return typed 503 responses while authorized cancellation and replay still work. The scheduled retention handler must return before any repository or R2 access whenblock_runsis active. - While all writers remain frozen, list every R2 object through the paginated API, stream and record its byte hash, and copy while preserving HTTP and custom metadata. Re-list for a final delta before switching bindings. Keep the old bucket and stop on any identity, metadata, hash, or drain mismatch.
During the cutover, run exactly one migration worker against the shared Postgres database. The old and new migration targets must never run at the same time, even though the runner uses a Postgres advisory lock. The lock protects statements; it does not coordinate an operational deployment or state and artifact copying.
Deploy order
-
Apply pending Postgres migrations from an isolated remote-development session. This entrypoint has no public
fetchroute:bash1cd apps/brain2corepack pnpm exec wrangler dev \3 --config wrangler.migrations.jsonc \4 --remote \5 --test-scheduledIn a second terminal, invoke the local scheduled-test endpoint:
bash1curl --fail-with-body "http://localhost:8787/__scheduled"Inspect the migration worker log for the exact
appliedandskippedmigration IDs, then stop the remote-development session. The migration runner uses one PostgreSQL transaction plus an advisory lock; a failed statement is rolled back and must block deployment. -
Deploy the secure runner and verify its bindings.
-
Deploy the API service and verify auth, database access, and service bindings.
-
Build and deploy the agents app with all three required
VITE_*endpoints. -
Build and deploy docs.
-
Build and deploy landing last so public routes point at healthy upstreams.
Deploy builds fail fast
The agents deploy build requires VITE_BRAIN_BASE_URL,
VITE_MUSCLE_BASE_URL, and VITE_MUSCLE_WS_URL. Do not replace that check
with production defaults in source.
Verify
Check the landing page, Cloud page, waitlist submission, docs, changelog, agents shell, OAuth session endpoint, and runtime fingerprint endpoints. Then load one agents asset through legioncode.dev/agents/assets/... to verify prefix routing.
Confirm production CORS allows the public origin and that the API service sends authenticated users to https://legioncode.dev/agents.