Run the desk
You need Node 22.18 or later and a Cloudflare account (for Workers AI).1
Clone and install
2
Set a local setup token
.dev.vars and set SETUP_TOKEN to any passphrase of 16 or more characters:.dev.vars
3
Sign in to Cloudflare for Workers AI
Locally, Workers AI still calls Cloudflare, so Wrangler needs a login:If your login can see more than one Cloudflare account, put the one to use in a
.env file at the repo root (it’s gitignored):.env
4
Start the dev server
SETUP_TOKEN.The dev server listens on
127.0.0.1, because Sign in with ChatGPT must return to a 127.0.0.1 loopback address. Open the desk as http://localhost:5173 all the same: browsers don’t allow passkeys on a bare IP address. The ChatGPT sign-in returns through 127.0.0.1 and lands you back on localhost..wrangler/. Delete .wrangler/state to start over with a fresh desk.
Sign in with ChatGPT locally
Locally, ChatGPT sign-in returns to the dev server by itself: in Settings → AI, choose ChatGPT sign-in (your plan), press Sign in with ChatGPT, approve, and you’re back on the desk. Replies spend your own ChatGPT plan. It’s for your own use only, per OpenAI’s terms. See Models.Try the widget
public/demo.html is a test page that pretends to be a customer site. Open it with your widget key (from Chat widget → Install):
- Pay invoice calls a request that fails with a server error, so you can see debug context reach the AI and the inbox.
- Add
&consent=requiredto try consent mode, then runJunDesk.consent(true)in the browser console.
Commands
End-to-end tests
The end-to-end suites drive a real dev server: they create the owner with a software passkey, open widget sockets, wait for real AI answers and run thejun CLI. They run on their own server and database, so your own local desk isn’t wiped.
1
Log in to ChatGPT for the AI (once)
The suites answer with real AI through your ChatGPT login:To use Workers AI instead, set
E2E_AI_PROVIDER=workers-ai when you run the tests.2
Start a separate server
JUN_STATE_DIR gives Vite its own local state folder; --persist-to points the migrations at the same one.3
Run the suites
In another terminal:
npm run test:e2e runs these suites in order: e2e-auth, e2e-chat, e2e-ai, e2e-debug, e2e-agent, e2e-visitors, e2e-polish, e2e-inbox, e2e-metrics, e2e-issues, e2e-knowledge, e2e-assignment, e2e-topics, e2e-notifications, e2e-openers, e2e-actions and e2e-widgets. You can run one on its own, for example BASE_URL=http://localhost:5174 node scripts/e2e-chat.ts.
The tests read SETUP_TOKEN from the environment or from .dev.vars. e2e-agent and e2e-visitors call httpbin.org as a stand-in for your API. Crawl tests use a public URL, because the local Worker can’t fetch its own dev server.
scripts/bench-models.ts compares Workers AI chat models on five support questions; run it against the e2e server. scripts/upgrade-check.ts checks an upgrade from an older version; see Upgrade.
Project layout
packages/ TypeScript runs directly on Node with type stripping, with no build step: use only erasable syntax (no enums or namespaces) and .ts extensions on relative imports. CLAUDE.md in the repo has the full conventions.
Contributing
Runnpm test, npm run typecheck and the end-to-end suites before you open a pull request. Outside contributions will need a contributor licence agreement (CLA); the agreement and its bot aren’t set up yet, so open an issue before starting a large change. See CONTRIBUTING.md.
How it works
The architecture behind the code.
Deploy to Cloudflare
Ship your local checkout to your account.