Skip to content

Deploy web app to playground.bitrouter.ai via Vercel #1

@SPIKESPIGEL404

Description

@SPIKESPIGEL404

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

  • Vercel account with access to push deploys
  • Namecheap DNS access for bitrouter.ai
  • playground icon + OG image assets (final or placeholder)
  • Decision on which org/repo owns the Vercel project (this repo, presumably)

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.js
    • variants.production.name"BitRouter Playground"
    • expo.slug"bitrouter-playground"
    • expo.scheme"bitrouter"
    • Drop expo.updates.url (Paseo's EAS OTA channel — irrelevant to web)
  • Swap favicon + OG image in packages/app/public/
  • Update HTML title to "BitRouter Playground" (Expo Router _layout.tsx or equivalent)
  • Add a short note to the top-level README.md that this is a fork

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

  • In Vercel: Project Settings → Domains → add playground.bitrouter.ai. Note the CNAME target Vercel shows (usually cname.vercel-dns.com.).
  • In Namecheap → Advanced DNS, add:
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

  • Open https://playground.bitrouter.ai — expect the rebranded UI to load.
  • Confirm in browser devtools that the static bundle, fonts, icons all load.
  • Expect WebSocket connection to local daemon to fail at this point — that's the next-step problem (see Follow-ups below), not a deploy bug.

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:

  • CORS / hostname allowlist on the daemon side. Local Paseo daemons need https://playground.bitrouter.ai in their daemon.cors.allowedOrigins and hostnames list. Right now only https://app.paseo.sh is whitelisted by default.
  • bitrouter paseo init CLI subcommand. Lives in the BitRouter repo, not this one. Writes/merges the playground origin into ~/.paseo/config.json and adds a custom provider that points Claude/Codex/OpenCode at BitRouter. See pipeline-test details below.
  • First-run empty-state UX. When the frontend can't reach a daemon, show install instructions (brew install paseo-daemon, bitrouter paseo init, etc.) instead of a generic error.
  • Fix bitrouter init shim bug. The auto-generated shim at /Users/<user>/.local/share/claude/versions/<v> sets ANTHROPIC_BASE_URL='http://127.0.0.1:8787/v1', but the Anthropic SDK appends /v1/messages to the base, producing /v1/v1/messages (404s on BitRouter, no log entry). Fix: drop the /v1 from 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 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions