Optional features
The platform bot
Section titled “The platform bot”Users can go through onboarding on the web. A platform bot also lets them do it on Telegram (/new, /status, /retry), link their Telegram account to their bohr account, and create each project’s bot with one tap.
-
Create a bot with @BotFather. In its settings, allow it to manage other bots (Bot API managed bots): that lets it create each project’s bot. Without it, users paste a BotFather token instead.
-
Store its token:
Terminal window npx wrangler secret put TELEGRAM_BOT_TOKEN -
Point the bot at the instance:
Terminal window curl -X POST https://<your instance>/api/admin/platform-bot \-H "Authorization: Bearer <ADMIN_TOKEN>"
Without a platform bot, Link Telegram says “This instance has no Telegram bot set up.”; project bots still work with BotFather tokens.
Sign-in with a code by email
Section titled “Sign-in with a code by email”Users can sign in with GitHub, or with a one-time code sent through Cloudflare Email Service.
-
Enable Email Sending for a domain of yours:
Terminal window npx wrangler email sending enable mail.example.com -
In
wrangler.jsonc, uncomment thesend_emailbinding and setEMAIL_FROM:"send_email": [{ "name": "EMAIL", "allowed_sender_addresses": ["login@mail.example.com"] }],"vars": { "EMAIL_FROM": "bohr <login@mail.example.com>" } -
Deploy again. Without the binding, the sign-in page only offers GitHub.
A dedicated sign-in container
Section titled “A dedicated sign-in container”Connecting a Claude subscription runs the official CLI’s claude setup-token. Without anything else, it runs in the container of one of the owner’s projects: the owner needs a project whose agent is ready, and a sleeping container has to start first.
A small dedicated container attached to the instance removes both: the connection works before any project exists and starts in seconds. It gets no secrets; the token it returns goes to the instance, never to the browser. Each user or organization signing in gets its own container, which stops 10 minutes after the last use.
It needs Workers Paid on the instance’s account and the image in that account’s registry:
-
Create an API token with Containers: Edit on the instance’s account and copy the image (the version in
runtime/claude-login/package.jsonby default; pass another image as an argument):Terminal window CLOUDFLARE_API_TOKEN=<token> CLOUDFLARE_ACCOUNT_ID=<account ID> node apps/instance/scripts/copy-login-image.mjs -
In
wrangler.jsonc, uncommentdurable_objects,migrationsandcontainersunder “Optional: a small dedicated container”, with your account ID in the image (the script prints the line), and deploy again.
Copy the new image and update its tag when you update bohr.
Your own agent image
Section titled “Your own agent image”Each project’s sandbox runs the image built from runtime/agent. On the first project of an account, the instance copies the published image (ghcr.io/bohr-io/agent:<version>) into that account’s Cloudflare registry. To use your own build:
pnpm --filter @bohr/agent builddocker build --platform linux/amd64 -f runtime/agent/Dockerfile -t ghcr.io/<you>/bohr-agent:<tag> .docker push ghcr.io/<you>/bohr-agent:<tag>npx wrangler secret put RUNTIME_IMAGE # ghcr.io/<you>/bohr-agent:<tag>The image must be public (GitHub Container Registry or Google Artifact Registry recommended; Docker Hub limits anonymous pulls). Cloudflare Containers run linux/amd64 images.