Deployment from our side

Deploy from GitHub to the Cohent domain

This is one full-stack Cloudflare Worker, not a static site inside app/. Keep the Cloudflare root directory blank (the repository root). package.json and the build configuration live there; the build compiles app/, the API routes, worker/index.ts, static assets, the D1 binding, and the scheduled room sweep into dist/server.

For the first production setup:

  1. Add cohent.io to the same Cloudflare account and finish its nameserver setup.
  2. Create a D1 database named cohent-production and copy its database id.
  3. Create an empty Worker named cohent. Do not attach the custom domain yet.
  4. On that Worker, add the runtime variables and encrypted secrets listed below.
  5. Open Settings → Builds, connect atakanturg/cohent, and use main as the production branch.
  6. Leave Root directory blank. Set the build command to npm run build:cloudflare and the deploy command to npm run deploy:cloudflare.
  7. Add the build-time variables listed below, save, and run the first deployment.
  8. Open https://cohent.io/api/health. The first database-backed request safely applies the checked-in migrations to the new D1 database.

The deploy script deliberately points Wrangler at the configuration generated inside dist/server; running bare wrangler deploy from the repository root will not use it. The Worker name in Cloudflare must match CLOUDFLARE_WORKER_NAME.

Build variables

These exist only while Cloudflare is compiling the repository:

CLOUDFLARE_BUILD=1
COHENT_CUSTOM_DOMAIN=cohent.io
CLOUDFLARE_D1_DATABASE_ID=<the production D1 id>
CLOUDFLARE_D1_DATABASE_NAME=cohent-production
CLOUDFLARE_WORKER_NAME=cohent
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=<the Clerk publishable key>

Runtime variables and secrets

Add these under the Worker's Settings → Variables and Secrets. Use plain variables for public configuration and Cloudflare's encrypted Secret type for credentials.

Plain runtime variables:

COHENT_PUBLIC_URL=https://cohent.io
CLERK_AUTHORIZED_PARTIES=https://cohent.io
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=<the same Clerk publishable key>
GITHUB_APP_CLIENT_ID=<GitHub App client id>
GITHUB_APP_SLUG=<the app's public URL slug>
RESEND_FROM_EMAIL=Cohent <invites@cohent.io>

Encrypted runtime secrets:

CLERK_SECRET_KEY
GITHUB_APP_CLIENT_SECRET
GITHUB_WEBHOOK_SECRET
COHENT_ENCRYPTION_KEY
RESEND_API_KEY

Do not put secret values in GitHub. NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY must be available both during the build and at runtime. The generated Worker configuration uses keep_vars, so later code deployments preserve dashboard-managed runtime values.

Create a production D1 database and set its id and name through CLOUDFLARE_D1_DATABASE_ID and CLOUDFLARE_D1_DATABASE_NAME. Set CLOUDFLARE_BUILD=1 and COHENT_CUSTOM_DOMAIN=cohent.io during the production build. The explicit build flag makes a missing domain or D1 id stop the deployment instead of generating a development configuration. The generated Worker configuration then disables both workers.dev and preview URLs and attaches only the exact custom domain. Cloudflare must already manage the cohent.io zone, and the hostname cannot have a conflicting CNAME.

Starting and observing the Worker

There is no production server process to start. A successful deploy activates the Worker automatically on cohent.io, and Cloudflare invokes worker/index.ts for each request. The scheduled room sweep is registered as a cron trigger and runs every minute automatically.

For local development, run:

npm install
npm run dev

For a manual production deploy from a trusted machine, set the production build variables in the shell, then run:

npm run build:cloudflare
npm run deploy:cloudflare

For live production logs:

npx wrangler tail cohent

Cloudflare Git integration runs the same build and deploy commands automatically after each push to main. Do not use Cloudflare Pages or choose app/ as the root directory.

Use separate Cloudflare projects, D1 databases, Clerk applications, GitHub Apps, and Resend settings for staging and production. A practical staging hostname is staging.cohent.io; do not point staging at the production database.

After a production deploy, test the custom domain directly:

  1. open the landing page on desktop and a real phone;
  2. create a fresh account with email, reset its password, and sign in with Google and Apple;
  3. connect GitHub and confirm a repository twice;
  4. email a second address and confirm only that account can accept it once;
  5. copy a team link, join with two separate test accounts, and confirm both land in the same repository project;
  6. connect a second repository, switch projects, and confirm members, agents, scope, notifications, and activity stay separate;
  7. connect two agents, create overlapping plans, and confirm Cohent coordinates them;
  8. check /api/health, then confirm an idle room continues advancing after one minute;
  9. verify https://<worker>.workers.dev and preview URLs do not serve the product.

ChatGPT sign-in is a separate OpenAI Sites front-door flow. A direct Cloudflare custom domain does not receive those trusted identity headers, so email, Google, Apple, and GitHub are the production account paths unless Cohent is also deployed through that front door. Password reset email is delivered by Clerk because Clerk owns the password and reset token. Resend remains responsible for project invitation email.

Current product architecture

The current build is:

  • a vinext full-stack application deployed as one Cloudflare Worker;
  • authenticated with Clerk email, Google, and Apple accounts;
  • ready for optional GitHub App user authorization with PKCE and expiring tokens;
  • backed by Cloudflare D1;
  • connected to a private GitHub repository;
  • protected by durable per-user/project write and presence limits;
  • equipped with reversible room archival and owner-managed membership;
  • equipped with verified webhooks, repository-derived access, encrypted GitHub tokens, prompt retention/redaction, live SSE, and remote agent controls;
  • using a clearly labeled runner contract simulator.

This is suitable for product validation, not a public multi-tenant launch.

Pilot deployment

For the first real eight-person pilot:

  1. keep the GitHub repository private;
  2. create a separate staging site and D1 database;
  3. create or invite only the intended pilot accounts and project members;
  4. install a least-privilege GitHub App on one selected repository;
  5. deploy an outbound-only runner in our controlled environment;
  6. require signed job leases, repository allowlists, isolated worktrees, and short-lived secrets;
  7. run the multiplayer, runner, migration, and rollback smoke suites;
  8. promote the exact tested commit to the owner-approved production site.

An account alone does not grant project access. Project membership or a valid recipient invitation/team link for that exact repository project is still required.

GitHub App configuration

Register one GitHub App per environment with expiring user tokens enabled and the exact callback:

https://<site-host>/api/auth/github/callback

Use least privilege: read metadata and repository contents for access projection; add pull-request/check permissions only when the real runner is enabled. Configure:

GITHUB_APP_CLIENT_ID
GITHUB_APP_CLIENT_SECRET
GITHUB_APP_SLUG
GITHUB_WEBHOOK_SECRET
COHENT_ENCRYPTION_KEY

Install the app only on selected repositories and send webhooks to /api/github/webhook. The control plane verifies X-Hub-Signature-256, deduplicates X-GitHub-Delivery, and fails closed when an installation, repository, authorization, or derived membership is revoked. Never reuse these secrets between staging and production.

Set the GitHub App callback URL to https://cohent.io/api/auth/github/callback. Because user authorization during installation is enabled, choosing repositories returns through that callback and Cohent refreshes the repository list. The app slug is the final part of its public link (for example, github.com/apps/cohent-agent means GITHUB_APP_SLUG=cohent-agent); it is a plain runtime variable, not a secret.

Cohent account configuration

Cohent keeps project data and authorization in Cloudflare D1. Clerk is used only for public account identity, Google and Apple sign-in, email sign-up, and account management. Configure one Clerk application per environment:

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
CLERK_SECRET_KEY
CLERK_AUTHORIZED_PARTIES=https://your-cohent-site.example

Enable Google, Apple, and email sign-in in the Clerk dashboard. Add https://cohent.io/sign-in/sso-callback to the production redirect URLs, and complete Clerk's Apple production setup before launch. Keep the secret key on the server. CLERK_AUTHORIZED_PARTIES must list the exact production origins that may present a Cohent session. GitHub remains a separate repository-access connection even when a person signs into their Cohent account with Google.

Invitation email configuration

Team access can send Cohent-themed invitations through Resend. Configure these on the server; never expose them to the browser:

RESEND_API_KEY
RESEND_FROM_EMAIL=Cohent <invites@your-verified-domain.example>
COHENT_PUBLIC_URL=https://your-cohent-site.example

RESEND_FROM_EMAIL should use a domain verified in Resend. When it is omitted, the development fallback is Cohent <onboarding@resend.dev>. COHENT_PUBLIC_URL pins the hostname placed in invitation links; production otherwise uses Cohent's canonical site URL. The server creates the one-project, recipient-bound, seven-day email token itself after checking the sender's project role. If delivery fails, the UI keeps that private recipient link available separately; it never replaces the reusable team share link.

Edge abuse protection

The generated Worker configuration includes Cloudflare Rate Limiting bindings. They provide a broad ceiling for API traffic and a tighter ceiling for sensitive account, bootstrap, invitation, and GitHub authorization entry points. The application also keeps durable per-user/project limits in D1, because edge counters are intentionally fast and eventually consistent rather than a billing or authorization ledger.

In Security → WAF → Rate limiting rules, add a challenge or block rule for repeated requests to /sign-in*, /sign-up*, /forgot-password*, and sensitive /api/* paths from one source. Start in log mode, review legitimate shared-office traffic, then enable the action. Keep Cloudflare's managed DDoS protection enabled and alert on 429 spikes, repeated 401/403 responses, webhook signature failures, and invitation email volume.

Beta architecture

Browser
  │ Clerk identity
  ▼
Edge control plane ── room coordinator ── D1/Postgres
  │        │                  │               │
  │        ├── GitHub App/webhooks            ├── audit/events
  │        ├── queue + signed leases          └── policy/decisions
  │        └── object storage for artifacts
  ▼
Customer or managed runner
  └── isolated worktree ── Codex/Claude/other agent ── checks ── commit

The control plane never needs inbound access to a developer laptop. Runners poll or hold an outbound authenticated connection, accept only repository- allowlisted jobs, and upload bounded evidence.

Environments

  • Development: synthetic owner, local D1, contract runner.
  • Staging: separate site, database, GitHub App installation, and runner.
  • Production: isolated database and secrets, protected source branch, owner-approved deployment, backups, monitoring, and rollback.

No environment shares invite tokens, runner credentials, webhook secrets, or databases.

Release flow

  1. Merge a reviewed pull request.
  2. Build once and record the source commit and artifact hash.
  3. Apply backward-compatible migrations in staging.
  4. Run lint, typecheck, unit, multiplayer, runner, health, and browser checks.
  5. Deploy the same artifact to production.
  6. Check /api/health, room reads, one authorized write, and runner heartbeat.
  7. Watch error rate, job lease failures, queue age, D1 latency, and webhook lag.
  8. Roll back the site version if application health degrades; use expand/ contract migrations so code rollback remains safe.

Production services we operate

  • control-plane application and room coordinator;
  • tenant and membership database;
  • GitHub App and webhook receiver;
  • job queue and lease signer;
  • managed runner pool;
  • artifact storage;
  • audit log and retention jobs;
  • email/Slack notification delivery;
  • observability, incident response, backups, and support.

Security boundary

  • Public reachability must never imply project access.
  • Every request is authenticated and authorized against project membership.
  • GitHub App permissions are repository-scoped and least privilege.
  • Runner secrets are job-scoped and expire.
  • Logs and messages never contain repository credentials.
  • Durable application limits apply per identity and project; the public beta adds complementary edge/IP limits before the application.
  • High-risk actions require append-only audit events and, eventually, policy- based multi-party approval.

Launch gates

Do not call the product production-ready until:

  • real GitHub worktree execution and SHA reporting are complete;
  • tenancy isolation tests pass;
  • invite, webhook, lease, and merge races have regression coverage;
  • backup restoration and rollback are rehearsed;
  • both durable identity/project and edge/IP abuse controls are enabled;
  • a five-to-ten-person pilot shows less rework or faster reviewed merges.
CohentPractical guides for using and understanding Cohent