A chat whose panel runs on an open-weight model on the dev PC's own GPU (Ollama, RTX 4090) instead of a cloud API. Built to test uncensored open-weight models against the app's real harness — at $0 a turn, with nothing leaving the machine.
localhost.Local is chosen at birth, never switched into or out of. The new-chat Model dropdown offers the local seats; picking one creates the room local for life. This deletes every seam a live switch would open — a mounted game with nowhere to run, a memory half-state (read this morning, off tonight), a + menu popping in and out — and it keeps incognito what it already is: a creation-time stamp.
set_model enforces it server-side in both directions, whatever a stale client sends.| surface | on a local room | why |
|---|---|---|
| Panel (the voices) | the local model | the point |
| Floor producer | Off · Code · Local (arm v1l) | v1l runs the FP on the room's own model — same weights, no GPU swap. Default off: latency unmeasured. |
| Split run (prop + act), kits, toys | off | the device's clerks are cloud calls; a game the device cannot run does not go on the table |
| + menu (Photo · Camera · Kits · Toys) | not rendered | everything behind it is cloud-backed; the photo door also refuses server-side (the eyes are cloud) |
| @Assistant dispatch | refused with a line | web search is inherently non-local |
| Translate (Layer B) | off | the translator is a cloud call |
| Auto-title | off — plain truncation titles | owner's call: one less call, one less surprise on the GPU |
| Persona memory | auto-incognito | forced at Room.__init__, so every creation path (create · fork · resume) is covered at once |
| Cost | booked at $0 | the ledger keeps tokens + latency; the price table rows are zero |
ds_url_for(api_model) is the one seam that knows a local api id answers at localhost. Routed call sites: panel · act · prop · compose · the FP's v1l arm.model_local(id) reads the row's local flag — the MODELS row is the decision, consulted live at every gate; no second copy of the fact anywhere.qwen3-30b-2507-32k · magidonia-24b-32k) — the raw hf.co/… pulls load at their native 262k context and spill half the model to CPU.panel_turn tool correctly, so local turns use the same structured path as DeepSeek. Measured on the real megaprompt: a 15k-token kickoff prefill in ~5.4s, an in-character Chinese reply in ~2.6s.v1l FP shares the panel's Ollama slot, so its call can evict the panel's KV-cache prefix and force a re-prefill; that is why it defaults off until measured (OLLAMA_NUM_PARALLEL=2 is the knob if it bites).exam/run.py --quick against a DeepSeek control: local models follow the directives more loosely, and that gap should be a number, not a vibe.user_roll · user_deal · user_board…) are unreachable through the hidden UI but not yet server-refused for local rooms — belt without suspenders, noted.