Krispy AI
guides

self-host the edge

create the KV namespace, set the secrets, deploy the Worker, register the Telegram webhook.

self-host the edge Worker

the edge Worker is the whole backend: the /api/* routes and the SessionDO Durable Object, one deploy, one wrangler.toml. deploy it from services/edge.

1. KV namespace

the Worker uses one KV namespace (KRISPY_KV) for tenant config, handoff discovery, the topic↔session map, and usage counters. create it and paste the id into services/edge/wrangler.toml (replacing REPLACE_WITH_KV_ID):

bunx wrangler kv namespace create KRISPY_KV

2. secrets

the Worker never reads a .env file at runtime. set each secret in Cloudflare with wrangler secret put (from services/edge):

bunx wrangler secret put TELEGRAM_BOT_TOKEN       # BotFather token
bunx wrangler secret put TELEGRAM_CHAT_ID         # supergroup id, e.g. -1001234567890
bunx wrangler secret put TELEGRAM_WEBHOOK_SECRET  # any random string
bunx wrangler secret put TENANT_SYNC_SECRET       # optional: gates /api/tenant/config
bunx wrangler secret put KNOWLEDGE_GATEWAY_SECRET # optional: private retrieval gateway

for local iteration without deploying, wrangler dev reads these from a git-ignored .dev.vars file in services/edge.

Telegram creds, TENANT_SYNC_SECRET, and BILLING_SYNC_SECRET are secrets β€” they belong in Cloudflare, never in the repo. KV and Durable Object bindings are not secrets; they live in wrangler.toml. see security.

3. optional vars

set in wrangler.toml under [vars], or as secrets. all optional β€” code defaults apply:

vardefaultwhat it does
ALLOWED_ORIGIN*CORS allow-origin. lock to your site origin in production.
AI_MODEL@cf/meta/llama-3.3-70b-instruct-fp8-fastoverride the Workers AI model.
SYSTEM_PROMPTβ€”override the system prompt from env (KV wins if unset).
MAX_HISTORY_MSGS8sliding window β€” prior messages the AI sees.
MAX_OUTPUT_TOKENS256hard cap on reply length.
MAX_AI_TURNS10AI turns before a forced human handoff.
RESEND_API_KEYβ€”enables lead-email delivery (no key β†’ email no-ops).
LEAD_EMAIL_FROMβ€”verified-domain from-address for lead email.
KNOWLEDGE_GATEWAY_URLβ€”private retrieval gateway URL (HTTPS; loopback HTTP only locally).
KNOWLEDGE_TENANT_IDβ€”exact tenant binding required before retrieval runs.
KNOWLEDGE_SITE_IDemptyexact site binding; empty means the default site.
KNOWLEDGE_TIMEOUT_MS250bounded gateway deadline, clamped to 2000 ms.

MAX_HISTORY_MSGS / MAX_OUTPUT_TOKENS / MAX_AI_TURNS are the "turn tax" cost knobs β€” the client re-sends the whole history each turn, so these three bound per-turn cost without changing behavior on normal short chats.

The canonical handoff marker is [!HANDOFF]; a standalone terminal !HANDOFF is accepted for provider compatibility. Either marker produces a visitor acknowledgement if it is the entire model reply, so the handoff never leaves an empty bubble.

The optional knowledge gateway is called only from the Worker. It must enforce the same exact tenant/site binding and return bounded cited reference data. A timeout, scope mismatch, malformed response, or gateway error leaves the normal chat path unchanged; no provider setting is exposed through the widget.

4. deploy

cd services/edge
bunx wrangler deploy

5. register the Telegram webhook

point Telegram at your deployed Worker so owner replies reach it. the secret_token must match the TELEGRAM_WEBHOOK_SECRET you set β€” the Worker rejects any webhook call whose x-telegram-bot-api-secret-token header doesn't match.

curl "https://api.telegram.org/bot<TOKEN>/setWebhook" \
  -d "url=https://krispy-edge.YOU.workers.dev/api/telegram/webhook" \
  -d "secret_token=<TELEGRAM_WEBHOOK_SECRET>"

6. verify

curl https://krispy-edge.YOU.workers.dev/health   # β†’ {"status":"ok","service":"edge"}

then embed the widget (embed + theme the widget) with data-api pointed at your Worker, and drive the loop end to end.

On this page