Self-hosting
Deploying the site
How pooled.run is deployed on Vercel, and how to deploy your own copy there or on any static host.
The site is static: HTML, JavaScript modules, fonts and images from the repository root, plus these docs at /docs. pooled.run runs on Vercel, but any static host works if it applies two rewrites.
Deploy your own copy
Section titled “Deploy your own copy”- Fork Nehanth/pooled and import the fork as a new Vercel project.
- Keep the root directory as the repo root. Framework preset: Other.
vercel.jsonsets the install and build commands and the output folder. - Deploy. Open
https://<your-project>.vercel.app/room. - Add your domain in the Vercel project settings, if you have one.
- Optional: give rooms a TURN relay for work networks. Set
TURN_KEY_IDandTURN_KEY_API_TOKEN(a Cloudflare TURN key) in the project’s environment variables and redeploy.api/turn.mjsthen hands out short-lived credentials. See The site’s relay.
The swarmllm.ai and www.pooled.run redirects in vercel.json only match those hosts; delete them if you like.
Build the docs and assemble the site, then serve dist/:
npm ci --prefix docs-sitenpm --prefix docs-site run build && node docs-site/build-vercel.mjsOr skip the docs and serve the repository root. Either way, add:
- Rewrites:
/roomand/r/<code>serve/p2p.html(the URL stays the same). - Headers:
X-Content-Type-Options: nosniffandReferrer-Policy: strict-origin-when-cross-originon everything. - Caching:
engine/,room/,harness/androom.jsmust revalidate on every load (Cache-Control: public, max-age=0, must-revalidate), so every device in a room runs the same code. Fonts under/site/fonts/can be cached for a year (immutable). - The preview relay:
/harness/preview-relay.htmlneeds its own headers. Copy them fromvercel.json.
A static host has no /api/turn, so rooms get no default relay; set window.TURN_SERVERS for your own. Leave out what .vercelignore lists (tests, benchmarks, docs, cli, scripts, *.md and more). Run it locally has a Caddy example of the rewrites.
Settings for your deployment
Section titled “Settings for your deployment”Signaling servers, a TURN relay and the Code mode preview site are set in p2p.html before room.js loads. See Page globals. Anything in p2p.html is public, including a TURN password.
Code mode preview site
Section titled “Code mode preview site”Optional. With a second site, Code mode previews get their own browser process: an app stuck in while (true) {} hangs only that process, and the agent can use run_js. Without one, previews run in the room’s tab and run_js is off. pooled.run’s own preview-origin meta is still empty, so this is the case there today.
The second site must be a different registrable domain, never a subdomain (a subdomain shares the room’s process). *.vercel.app is on the Public Suffix List, so your-preview.vercel.app counts.
-
Create a second Vercel project from the same repo: Root Directory
preview-host, framework Other, “Include files outside the root directory” on. -
Check the headers:
curl -I https://<preview-site>/harness/preview-relay.htmlYou should see a
Content-Security-Policywithframe-ancestors https://pooled.run ...and noX-Frame-Options. -
If your site is not pooled.run, add your origin to
frame-ancestorsin bothvercel.jsonandpreview-host/vercel.json. -
Fill the meta in
p2p.html(one origin, orhost=originentries per page host):p2p.html <meta name="preview-origin" content="pooled.run=https://pooled-preview.vercel.app pooled-dev.vercel.app=https://pooled-preview.vercel.app"> -
Test on staging: the preview’s “sandbox” tip should say it runs on a separate site, and
while (true) {}should hang only the preview.
A plain-http origin (except loopback) or one on the page’s own site is ignored with a console warning.
How pooled.run is deployed
Section titled “How pooled.run is deployed”Vercel’s git integration deploys the repo. The site has no build step ("framework": null); only these docs are built, an Astro Starlight project in docs-site/:
"installCommand": "npm ci --prefix docs-site","buildCommand": "npm --prefix docs-site run build && node docs-site/build-vercel.mjs","outputDirectory": "dist"build-vercel.mjs copies the repo root into dist/ (minus .vercelignore) and the built docs into dist/docs/. Search is Pagefind, a static index.
| Push to | Deploys to |
|---|---|
main |
Production, pooled.run. Every merge is a release. |
| any other branch | Nothing, unless the commit message contains [preview] |
feat/engine-opt |
Like any branch; a [preview] build also goes to staging, https://pooled-dev.vercel.app |
Previews are opt-in
Section titled “Previews are opt-in”ignoreCommand in vercel.json skips a build unless it is production or the commit message contains [preview]:
"ignoreCommand": "if [ \"$VERCEL_ENV\" = production ]; then exit 1; fi; case \"$VERCEL_GIT_COMMIT_MESSAGE\" in *\"[preview]\"*) exit 1;; esac; exit 0"A preview builds at https://<project>-git-<branch>-nehanths-projects.vercel.app, and the PR gets the link as a bot comment. Vercel reads ignoreCommand from the branch being built. A pull request from a fork also needs a maintainer’s approval (Vercel’s fork protection).
Staging by hand
Section titled “Staging by hand”If the git integration is down, npm run deploy:staging (scripts/deploy-staging.sh) deploys the checkout to pooled-dev.vercel.app. A manual npx vercel deploy --prod is for emergencies only.