Skip to content

Cloudflare

Redeploy and operate Chickpea on your own Cloudflare account with the guarded deploy wrapper.

Updated View as Markdown

npm run deploy is Chickpea’s guarded Cloudflare deploy: it builds the Worker, checks the generated artifact, preserves the deployed database, applies migrations, uploads, and confirms readiness. Where the Deploy to Cloudflare button runs that same wrapper for your first deployment, this page is what you run afterwards from a clone. It covers the checks the wrapper enforces, the two deployment profiles, the bindings and the cron a deployment carries, the secrets you add after, and what updating does to state.

Prerequisites

  • A Cloudflare account on Workers Paid. The current bundle’s compressed upload exceeds the Free plan’s 3 MiB Worker limit. The coding sandbox needs Workers Paid as well.
  • A clone of the repository at the release you intend to run, with Node 24.x, minimum 24.20.0, selected with nvm install && nvm use and npm ci already done.
  • A Cloudflare credential that may list Worker secrets. The wrapper reads them before it changes anything and stops with The deploy credential must allow secret listing before Chickpea can deploy safely.

The repository’s .nvmrc selects Node 24.20.0 for Cloudflare builds. An explicit NODE_VERSION build override should match that pin. These settings choose the build tool, while the Worker runs in workerd with its existing compatibility date and flags. Node updates do not replace workerd or real Slack acceptance. See Cloudflare’s build image documentation.

Redeploy from a clone

Check out the release and install its lockfile

git checkout <release-tag>
npm ci

Run the guarded deploy

npm run deploy

For the optional coding sandbox, run npm run deploy:sandbox instead. The wrapper builds the Cloudflare artifact first. Pass --skip-build only when you have already run npm run build and want that exact artifact, and --preflight-only to run every check and deploy nothing.

Watch the progress lines

A healthy redeploy prints, in order, Preserving the deployed AUTH_DB database..., Applying reviewed Better Auth migrations to AUTH_DB..., Verified the exact fresh Better Auth schema in AUTH_DB..., then wrangler’s own output, then Waiting for the current Worker and Slack gateway version.... A first deploy provisions the database instead of preserving it.

Any check that fails prints one line naming what was missing or unsafe and exits without uploading.

Copy the new setup link

Every deploy ends with a block headed PRIVATE SETUP LINK. The URL is /admin/setup#setup=<capability> on the deployed origin and expires 24 hours after the deploy. Each deploy mints a fresh capability and rotates the stored digest, so links printed by earlier deploys stop working.

When the deploy prints no workers.dev URL, the block is headed PRIVATE SETUP PATH and carries the path and fragment alone. Open it on the origin your deployment answers on.

Verify

The wrapper verifies readiness for you. It posts to /internal/deployment/ready on the deployed origin with the version it uploaded, retries every two seconds for up to six minutes, and prints Verified current-version deployment readiness. on a 204. If it never sees one, it exits non-zero with Worker uploaded, but current-version readiness was not confirmed. The Slack gateway may still be serving older code.

A successful upload is not acceptance. Record the account, Worker name, deployed version, traffic allocation, bindings, and source commit, then confirm a signed-in Admin and a real Slack request routed through that deployment.

What the guarded deploy checks

A bare wrangler deploy runs none of the following. Deploy through the wrapper.

  • The command line. --config, -c, and --name are refused, because Chickpea has to inspect and mutate the same Worker it deploys.
  • The Slack manifest. slack-app-manifest.json must declare features.agent_view, and may not declare assistant_view alongside it.
  • Worker identity. The generated Worker name must match the name in wrangler.jsonc, and the artifact must have a real generated entry.
  • AUTH_DB identity. Exactly one D1 binding named AUTH_DB, its migrations_dir ending in migrations/better-auth, and the same database ID the live Worker is already serving. A generated ID that differs stops the deploy rather than replacing customer auth data.
  • Durable Object history. The deleted and renamed class set must be exactly the retired beta Flue and AuthGuard classes. TagStateStore, Sandbox, and ContainerProxy may never be marked deleted or renamed.
  • The scheduler. Exactly one * * * * * Cron Trigger, the TAG_STATE binding, the two schedule agent bindings, and composed heartbeat and maintenance handlers.
  • Platform settings. Workers Traces enabled, compatibility_date at or above 2026-04-01, the global_fetch_strictly_public compatibility flag, and the CF_VERSION_METADATA binding.
  • Profile match. The generated artifact’s deployment profile must be the one you asked for.

Migrations run before the upload, against the live database. They are forward only and idempotent, so a failed deploy resumes from D1’s migration ledger when you rerun the command. Never attempt a schema rollback.

Deployment profiles

Two profiles exist. CHICKPEA_DEPLOY_PROFILE selects between them, and the npm scripts set it for you.

Profile Build Deploy What it adds
core (default) npm run build npm run deploy Nothing beyond the base Worker
sandbox npm run build:sandbox npm run deploy:sandbox A SANDBOX Durable Object binding and one container application

The sandbox container is built from the repository’s Dockerfile at instance type standard-1 with max_instances 25. The overlay applies to the core config only, so a sandbox artifact is always core plus those two additions.

On a Deploy to Cloudflare deployment you have no local shell for the redeploy. Request installation in Settings → Coding sandbox, then add the non-secret build variable CHICKPEA_DEPLOY_PROFILE with value sandbox under Cloudflare dashboard → Workers & Pages → your Worker → Settings → Builds → Variables and retry the deployment. The dormant v3 Sandbox migration is present in both profiles; it is not proof the tier is installed. Only the live binding is.

What a deployment binds

Binding Kind What it holds
ASSETS Static Assets The public product images in assets/
AI Workers AI The keyless model provider
TAG_STATE Durable Object Agents, assignments, thread snapshots, claims, the thread registry, operator settings
SLACK_GATEWAY_SESSION Durable Object The shared Slack gateway’s ingress session
FLUE_CHICKPEA_SLACK_V2_AGENT Durable Object The Slack turn agent
FLUE_CHICKPEA_ROUTINE_INTENT_V2_AGENT Durable Object Schedule intent
FLUE_CHICKPEA_ROUTINE_EXECUTION_V2_AGENT Durable Object Schedule execution
AUTH_DB D1 Better Auth sessions and provider accounts
CF_VERSION_METADATA Version metadata The running Worker version, used by the readiness check
SANDBOX Durable Object The coding sandbox, on the sandbox profile only

There is no KV namespace and no R2 bucket. The public images ship inside the same deployment through Static Assets, so no second Worker and no bucket is needed.

The one-minute cron

The deployment declares one Cron Trigger, * * * * *, and it drives two handlers on every tick.

  • The schedule heartbeat admits and runs schedule occurrences that are due, then drains pause notices.
  • Work maintenance maintains the work ledger, repairs pending OAuth continuation resumes, and wakes the shared gateway session. The gateway wake runs even when the rest of maintenance fails, because it is the ingress lifeline for the shared Slack lane.

On Node

Node runs no scheduler and no coding sandbox. Both are Cloudflare only.

Set secrets after deploy

The Deploy to Cloudflare form asks for no Chickpea secret. Every active key in .dev.vars.example renders there as a required prompt, so provider keys stay commented out and are added afterwards.

npx wrangler secret put ANTHROPIC_API_KEY
npx wrangler secret put OPENAI_API_KEY
npx wrangler secret put OPENROUTER_API_KEY

The same keys can live in Settings → Keys and models instead. For a deployment-owned Composio key, set COMPOSIO_API_KEY as a secret and CHICKPEA_COMPOSIO_CONFIGURATION_MODE=deployment as a plain Worker variable. To turn telemetry off, add DO_NOT_TRACK or CHICKPEA_DISABLE_TELEMETRY as a dashboard variable; to label a non-production deployment, add CHICKPEA_TELEMETRY_ENVIRONMENT=test.

Two secrets belong to the wrapper. It mints CHICKPEA_AUTH_SECRET and the first credential encryption key (CHICKPEA_CREDENTIAL_KEY_CURRENT_ID set to key_v1, plus the matching CHICKPEA_CREDENTIAL_KEY_KEY_V1 slot) on a deployment that has none, and preserves them on every deploy after. Removing one of the credential values without the other stops the next deploy: restore both before deploying again.

The public origin

By default the deployment answers on its workers.dev URL, and on Cloudflare the request Host is the public origin. If you serve it somewhere else, set SLACK_TAG_PUBLIC_URL to that origin. It is an explicit operator pin that wins outright, and no request header can override it.

Updates and state

Updates are manual. The Deploy to Cloudflare button clones this repository rather than forking it, so a new release reaches your deployment when you redeploy it.

Cloudflare keeps app and runtime state in Durable Objects as well as auth data in D1. Backing up or restoring AUTH_DB alone does not back up or restore the whole application, and Chickpea does not currently provide a complete cross-store snapshot and restore tool. Keep credential secrets recoverable, and follow the specific release’s migration and recovery procedure. Stop if it requires a recovery capability you have not established.

Next steps

Navigation

Type to search…

↑↓ navigate↵ selectEsc close