Drive (/) is chat + live desk + files + credentials against local cased.
The deployer (/deploy) owns create / sleep / wake / delete. They share this
server and the REST proxy; they do not share chrome. Chat keys (OpenAI or
Anthropic) arrive per-request; web/node_modules has both SDKs.
One seat. Drive is pointed at exactly one computer, because a computer is
one screen, one Chromium profile, one set of logins — two jobs on one box fight
over the active tab, and computer_action clicks pixels that know nothing about
tabs. So the sidebar lists threads, never computers, and /deploy owns the
choice (the DRIVE button, stored in localStorage['case.drive.computer']).
Drive never switches computers on its own: landing on the wrong desk means
landing in someone else's sessions, so a missing pick says so and stops.
Transport: talks to cased on CASE_URL — no SSH tunnel. Compose sets
http://cased:8787/v1. /live/<id>/… proxies to cased
/v1/computers/<id>/live/…, which relays noVNC: Drive is not on the desks
network and never dials a desktop itself.
Threads persist in threads.json beside serve.mjs unless CASE_THREADS
names another file (Compose: /data/threads.json).
Files view uses computer_exec find (/api/fs) and cased GET /files
(/api/file).
Run: node web/web-ui/serve.mjs → http://127.0.0.1:4174/ and /deploy
(or docker compose up from the repo root)
Tests: npm --prefix web test runs every web-ui/test_*.mjs, each in its own
node process.