Guide
Install & run
The bot is two Cloudflare Workers, a handful of storage bindings, and one GitHub webhook. Expect about 20 minutes end to end.
Before you start
Prerequisites
-
Node.js 20+ and npm (wrangler comes with
npm install). - A Cloudflare account with Workers enabled. Queues require the Workers Paid plan.
- Admin access to the GitHub repository (or org) that will use the bot.
-
A GitHub personal access token with
repoandread:orgscopes — the bot reads PR context and writes comments with it. - A Z.ai API key from z.ai / open.bigmodel.cn.
-
A random webhook secret:
openssl rand -hex 20
| Binding | Resource | Purpose |
|---|---|---|
BOT_DB |
D1 database bot-db |
Durable jobs, leases, publication state |
BOT_ARTIFACTS |
R2 bucket bot-storage |
Gathered PR context and command results |
BOT_CACHE |
KV namespace | Repo configuration and PR card cache |
BOT_JOBS |
Queue bot-jobs |
Carries job IDs from main to heavy worker |
Step by step
Get the code
git clone https://github.com/AndreiDrang/zai-code-bot.git
cd zai-code-bot
npm install
Install resolves wrangler locally, so every command below works
through npx or the npm scripts.
Create the Cloudflare resources
npx wrangler login
npx wrangler d1 create bot-db
npx wrangler r2 bucket create bot-storage
npx wrangler kv namespace create BOT_CACHE
npx wrangler queues create bot-jobs
Note the IDs the commands print — you will paste them into
wrangler.toml in the next step.
Apply the D1 migrations
cd src/zai-main-worker
npx wrangler d1 migrations apply bot-db --remote
cd ../..
This creates the job, lease, and publication tables the bot's state machine relies on.
Configure both workers
Edit src/zai-main-worker/wrangler.toml and
src/zai-heavy-worker/wrangler.toml: fill in the
database_id, KV namespace id, and any
route or custom domain for the main worker's webhook URL.
Optionally set the model with a plain var (defaults to a GLM model if unset):
[vars]
ZAI_MODEL = "glm-4.7"
Add the secrets
The bot reads all credentials from
Cloudflare Secrets Store — nothing belongs in
wrangler.toml or source. Create a store, add three
secrets, then reference them from both workers:
| Secret in store | Binding(s) | Value |
|---|---|---|
ZAI_GITHUB_WEBHOOK_KEY |
GITHUB_WEBHOOK_SECRET (main) |
The webhook secret you generated |
ZAI_GITHUB_TOKEN |
GITHUB_TOKEN (both) |
GitHub PAT with repo + read:org
|
ZAI_API_KEY |
ZAI_API_KEY (heavy) |
Your Z.ai API key |
[[secrets_store_secrets]]
binding = "ZAI_API_KEY"
store_id = "<your-store-id>"
secret_name = "ZAI_API_KEY"
You can manage stores in the Cloudflare dashboard (Workers →
Secrets Store) or with wrangler secret-store.
Deploy — heavy first, then main
npm run deploy:heavy # queue consumer: must be listening first
npm run deploy:main # webhook ingress
# or simply
make deploy
Validate without touching production first with
npm run build (dry-run bundles of both workers).
Wire up the GitHub webhook
In your repository: Settings → Webhooks → Add webhook.
| Field | Value |
|---|---|
| Payload URL | Your main worker URL (route or custom domain) |
| Content type | application/json |
| Secret | Same value as ZAI_GITHUB_WEBHOOK_KEY |
| Events |
pull_request, issue_comment,
pull_request_review_comment
|
Run it
Open any pull request and comment:
/zai help # instant command list from the webhook worker
/zai review # full-context AI review, one updated comment
/zai describe # PR description written into its own body section
Development
Local development & tests
npm run dev:main # main worker with wrangler dev
npm run dev:heavy # heavy worker with wrangler dev
npm test # vitest suite with coverage
Tail live logs from either worker with
npm run tail:main / npm run tail:heavy.
Optional housekeeping — expire the gathered PR-context tier in R2:
npx wrangler r2 bucket lifecycle add bot-storage \
--id pr-context-retention --prefix "v2/prs/" --expire-days 30