Goal
Stand up https://playground.bitrouter.ai as a static deploy of packages/app (the Expo web target), hosted on Vercel, with BitRouter as the substrate for the playground experience.
Architecture for v1: hosted frontend → user's local Paseo daemon (same model as app.paseo.sh). No cloud daemon yet — that's a separate follow-up if/when we want zero-install playground access.
Prereqs
Step 1 — minimal rebrand patches
Just enough so the deploy doesn't look like vanilla Paseo. Theme/color polish can land in a follow-up.
Step 2 — Vercel project config
Add at repo root before first deploy:
vercel.json:
{
"rewrites": [
{ "source": "/(.*)", "destination": "/index.html" }
]
}
This catch-all rewrite is required for Expo Router's client-side routing — without it, refreshing on any deep link 404s.
Step 3 — Vercel project setup
In the Vercel dashboard: New Project → Import bitrouter/paseo.
| Setting |
Value |
| Framework Preset |
Other (do NOT pick "Expo" — that preset is for Expo Router cloud SSR, not the static export Paseo uses) |
| Root Directory |
repo root (so npm workspaces install correctly) |
| Install Command |
npm install |
| Build Command |
npm run build:web --workspace=@getpaseo/app |
| Output Directory |
packages/app/dist |
| Node version |
20.x (or whatever Paseo's package.json engines specify) |
Notes:
- The
build:web script already runs build:workspace-deps first, so @getpaseo/highlight and @getpaseo/expo-two-way-audio will build correctly without extra Vercel wiring.
- First build will take ~5-10 min (npm install across the monorepo is heavy).
Step 4 — custom domain + DNS
| Type |
Host |
Value |
TTL |
| CNAME |
playground |
cname.vercel-dns.com. |
Automatic |
Vercel auto-provisions Let's Encrypt TLS once the CNAME is verified (1-5 min).
Step 5 — verify
Follow-ups (separate issues)
These are required for the playground to be useful but are NOT blockers for shipping the static deploy. Tracking each as its own work item:
Pipeline test reference (already validated locally)
The custom-provider shape that successfully routes Paseo Claude Code sessions through local BitRouter — for the bitrouter paseo init subcommand to emit:
{
"agents": {
"providers": {
"claude-bitrouter": {
"extends": "claude",
"label": "Claude (via BitRouter)",
"env": {
"ANTHROPIC_BASE_URL": "http://127.0.0.1:8787",
"ANTHROPIC_API_KEY": "local-no-auth"
}
}
}
}
}
Confirmed end-to-end on 2026-05-27: Paseo agent → Claude Code 2.1.152 → Anthropic SDK POST /v1/messages → BitRouter request received (resolution failed) log entry. The pipe works; remaining work for a full chat response is adding an Anthropic provider to bitrouter.yaml.
Goal
Stand up
https://playground.bitrouter.aias a static deploy ofpackages/app(the Expo web target), hosted on Vercel, with BitRouter as the substrate for the playground experience.Architecture for v1: hosted frontend → user's local Paseo daemon (same model as
app.paseo.sh). No cloud daemon yet — that's a separate follow-up if/when we want zero-install playground access.Prereqs
bitrouter.aiplaygroundicon + OG image assets (final or placeholder)Step 1 — minimal rebrand patches
Just enough so the deploy doesn't look like vanilla Paseo. Theme/color polish can land in a follow-up.
packages/app/app.config.jsvariants.production.name→"BitRouter Playground"expo.slug→"bitrouter-playground"expo.scheme→"bitrouter"expo.updates.url(Paseo's EAS OTA channel — irrelevant to web)packages/app/public/_layout.tsxor equivalent)README.mdthat this is a forkStep 2 — Vercel project config
Add at repo root before first deploy:
vercel.json:{ "rewrites": [ { "source": "/(.*)", "destination": "/index.html" } ] }This catch-all rewrite is required for Expo Router's client-side routing — without it, refreshing on any deep link 404s.
Step 3 — Vercel project setup
In the Vercel dashboard: New Project → Import
bitrouter/paseo.npm installnpm run build:web --workspace=@getpaseo/apppackages/app/distpackage.jsonengines specify)Notes:
build:webscript already runsbuild:workspace-depsfirst, so@getpaseo/highlightand@getpaseo/expo-two-way-audiowill build correctly without extra Vercel wiring.Step 4 — custom domain + DNS
playground.bitrouter.ai. Note the CNAME target Vercel shows (usuallycname.vercel-dns.com.).playgroundcname.vercel-dns.com.Vercel auto-provisions Let's Encrypt TLS once the CNAME is verified (1-5 min).
Step 5 — verify
https://playground.bitrouter.ai— expect the rebranded UI to load.Follow-ups (separate issues)
These are required for the playground to be useful but are NOT blockers for shipping the static deploy. Tracking each as its own work item:
https://playground.bitrouter.aiin theirdaemon.cors.allowedOriginsandhostnameslist. Right now onlyhttps://app.paseo.shis whitelisted by default.bitrouter paseo initCLI subcommand. Lives in the BitRouter repo, not this one. Writes/merges the playground origin into~/.paseo/config.jsonand adds a custom provider that points Claude/Codex/OpenCode at BitRouter. See pipeline-test details below.brew install paseo-daemon,bitrouter paseo init, etc.) instead of a generic error.bitrouter initshim bug. The auto-generated shim at/Users/<user>/.local/share/claude/versions/<v>setsANTHROPIC_BASE_URL='http://127.0.0.1:8787/v1', but the Anthropic SDK appends/v1/messagesto the base, producing/v1/v1/messages(404s on BitRouter, no log entry). Fix: drop the/v1from the codegen template. (Discovered while validating the pipe; locally patched.)Pipeline test reference (already validated locally)
The custom-provider shape that successfully routes Paseo Claude Code sessions through local BitRouter — for the
bitrouter paseo initsubcommand to emit:{ "agents": { "providers": { "claude-bitrouter": { "extends": "claude", "label": "Claude (via BitRouter)", "env": { "ANTHROPIC_BASE_URL": "http://127.0.0.1:8787", "ANTHROPIC_API_KEY": "local-no-auth" } } } } }Confirmed end-to-end on
2026-05-27: Paseo agent → Claude Code 2.1.152 → Anthropic SDKPOST /v1/messages→ BitRouterrequest received (resolution failed)log entry. The pipe works; remaining work for a full chat response is adding an Anthropic provider tobitrouter.yaml.