These two scripts replace most hand-editing of wrangler.toml. After forking,
you run them once and you have a live pot on your Cloudflare account. The
setup script creates wrangler.toml from wrangler.example.toml when needed,
fills the Cloudflare resource ids it can discover, and leaves tenant-specific
vars for you to review. Substrate only: nothing here touches business content.
- Node 18+ and the repo dependencies installed:
npm install - A Cloudflare account, authenticated once:
wrangler login - Either an OAuth app (Google or Telegram) for dashboard login, or the one-time
bootstrap-owner ceremony for the first local owner. OAuth uses the callback URI
https://<your-deployment>/auth/callback.
Use this before merging production-sensitive dashboard, task, auth, Hermes, or
runtime changes. It runs against the local test Wrangler config and produces
release evidence in tmp/local-smoke.
npm run migrate:local:test
npm run seed:local:test
npm run dev:local:test
# in another shell, after Wrangler prints the local URL:
npm run smoke:localThe harness uses /auth/dev-login, which is enabled only when
LOCAL_TEST_AUTH=1 in wrangler-local-test.toml. It verifies:
- local owner login and unauthenticated dashboard redirect behavior
- the authenticated dashboard route crawl, including the
/opshealth console /sendvalidation, task creation,done_when, lifecycle completion, and visible result rendering/approvalsrejection validation and real verdict approval- Hermes
/im/webhookhelp/status/task flows withIM_WEBHOOK_SECRET - dashboard refresh after a Hermes-created task
Artifacts:
tmp/local-smoke/report.jsontmp/local-smoke/home.pngtmp/local-smoke/fleet.pngtmp/local-smoke/ops-health.pngtmp/local-smoke/send-workflow.pngtmp/local-smoke/approvals-workflow.pngtmp/local-smoke/hermes-dashboard-update.pngtmp/local-smoke/failure-*.jsonwhen a workflow failstmp/local-smoke/failure-*.pngwhen a workflow fails
npm run smoke:local writes report.json and prints the same JSON report to
stdout. The report contains the page crawl, workflow results, Hermes checks,
runtime contract name, artifact directory, and report path.
Use this with the same local Wrangler server when changing signed runtime, inbox, or detach behavior:
npm run migrate:local:test
npm run seed:local:test
npm run dev:local:test
# in another shell, after Wrangler prints the local URL:
npm run conformance:runtime:localThe local seed creates a non-production agent-conformance key and a welded
sender token. The harness proves runtime-adapter/v1 over HTTP: signed attach,
replay refusal, bearer send to the runtime inbox, signed inbox peek/consume,
consume-once behavior, fleet control request signing/delivery, and signed detach.
It writes tmp/local-runtime-conformance/report.json and prints the same JSON
report to stdout. Failures write tmp/local-runtime-conformance/failure-*.json
when the process can create artifacts.
GitHub Actions runs the same local evidence gate with:
bash scripts/ci-local-evidence.shThe script applies local D1 migrations, seeds the local fixtures, starts
wrangler dev with wrangler-local-test.toml, waits for /health, runs
npm run smoke:local, and then runs npm run conformance:runtime:local.
Actions uploads tmp/local-evidence, tmp/local-smoke, and
tmp/local-runtime-conformance as the local-evidence artifact.
# 1. Use this template on GitHub → your own fork, then clone it.
npm install
wrangler login # authenticate to YOUR Cloudflare account
# 2. Provision the resources (D1, Vectorize, Queues, KV, R2) + run migrations.
# Idempotent — safe to re-run; ids are written back into wrangler.toml.
bash scripts/setup.sh
# 3. Set TENANT_SLUG + BRAND + PUBLIC_ORIGIN (+ OAUTH_PROVIDER) in wrangler.toml [vars].
# 4. First deploy (creates the Worker so secrets can attach to it).
npm run deploy
# 5. Set dashboard OAuth secrets (read silently — never echoed, never written to disk/git).
bash scripts/secrets.sh
# 6. Re-deploy to pick the secrets up, then open your deployment and log in.
npm run deployOpen your deployment and log in. The first person to log in becomes owner;
from there the in-app setup wizard walks you through seeding your org
(departments → squads → agents). You're live.
Tip: if
secret putcomplains the Worker doesn't exist yet, runnpm run deployonce first (step 4), thenbash scripts/secrets.sh. Re-deploy afterward. For an OAuth-free first owner, replace step 5 withbash scripts/secrets.sh --bootstrap-owner, re-deploy, open/auth/bootstrap, and delete the bootstrap secret after claiming the owner session.
For an additional isolated pot in the same checkout, use a slug instead of copying resource identifiers by hand:
bash scripts/setup.sh --pot acme
node scripts/deploy.mjs --config wrangler.acme.toml
bash scripts/secrets.sh --pot acme
node scripts/deploy.mjs --config wrangler.acme.tomlFor an OAuth-free first owner on a new self-hosted pot, deploy once and run:
bash scripts/secrets.sh --pot acme --bootstrap-owner
node scripts/deploy.mjs --config wrangler.acme.tomlOpen <your-pot-url>/auth/bootstrap, submit the printed token and the owner's
email, then delete BOOTSTRAP_OWNER_TOKEN with Wrangler. Until deletion, only the
claimed owner may use the secret to resume a session; the route is disabled when
dashboard OAuth is configured.
Idempotent provisioner — detects already-created resources and skips them, and
leaves any id already present in wrangler.toml untouched. It creates:
| Resource | Name / binding | Notes |
|---|---|---|
| D1 | mupot |
id written back to wrangler.toml |
| Vectorize | mupot-memory |
768 dims, cosine |
| Queue | mupot-events |
events / leads |
| Queue | mupot-events-dlq |
dead-letter |
| KV | SESSIONS |
id written back to wrangler.toml |
| KV | OAUTH_KV |
id written back to wrangler.toml |
| R2 | mupot-blobs |
blobs |
Then it applies the D1 migrations remotely (wrangler d1 migrations apply mupot --remote). Re-running after a partial failure picks up where it left off.
With --pot acme, the script instead provisions mupot-acme resources,
writes wrangler.acme.toml, and applies migrations through that config.
Prompts for each secret and pipes it straight to wrangler secret put. Values
are read silently (read -r -s) and the value lives only in a transient shell
variable — never echoed, never written to any file, never committed.
| Secret | Required | For |
|---|---|---|
OAUTH_CLIENT_ID |
yes | login |
OAUTH_CLIENT_SECRET |
yes | login |
GITHUB_TOKEN |
no | mirroring tasks to GitHub Issues |
AI_GATEWAY_TOKEN |
no | routing models via Cloudflare AI Gateway |
Re-runnable — setting a secret again overwrites it.
- No secret ever lands in
wrangler.tomlor git. Only Cloudflare resource ids (not sensitive) are written back intowrangler.toml. - Secrets are entered interactively, piped over stdin, and never appear in your shell history or the process list.
.gitignorealready excludes.dev.vars,.env, and*.token. Keep it that way — this is a public template.- Your CF keys, your OAuth app, your GitHub token. You hold every key; you can revoke at any time.