# Tribal knowledge: the `.live/` mount (`Jamstack::Live`) — R4 (desktop slice) > Status: **IMPLEMENTED + verified** (R4 desktop) — `mrbgems/raylib/mrblib/live.rb`. > The Node WS relay + web side are **deferred** (R4b); this slice is the file-based > mount the game writes itself — no relay, no WS, no extra runtime. ## At a glance - **What:** a read-mostly `.live//` surface a file-based agent uses without speaking a socket: `status.json` (heartbeat), `game-console` (NDJSON log), and a `.agent/cmd-* → result-*.json` command protocol drained **in-frame** (P6). Plus `bin/*` helper scripts. This is the elegant desktop path (no FUSE — see the `.live` mechanism in roadmap R4): the native game has `mruby-io`/`mruby-dir`, so it writes/polls real files directly. - **Key files (planned):** `mrbgems/raylib/mrblib/live.rb` (`Jamstack::Live`); seam `raylib.rb` (`Live.start` + `Live.poll` per frame); reuses `Bridge.eval_code` (R1) and `Jamstack::JSON`/`Log` (R2). - **Gate:** same `JAMSTACK_BRIDGE=1`. Token via `JAMSTACK_LIVE` (default `dev`), root via `JAMSTACK_LIVE_ROOT` (default `.live`) → `.live/dev/`. - **Cross-refs:** `agent-bridge.md` (R1 eval, shares the queue/drain), `logging.md` (game-console), roadmap R4; principle P5 (observe vs the one write path), P7 (dev). ## The protocol (no JSON parser needed) mruby has **no JSON parser**, so the **command** files carry *raw Ruby*; the id is the filename. Only the **result** is JSON (written via `Jamstack::JSON`). ``` .live/dev/ status.json # heartbeat: connected,target,token,frame,fps,ts (throttled, atomic) state.json # flecs world snapshot (bin/snapshot writes this; atomic) game-console # Log NDJSON file sink (R2) .agent/ cmd-.rb # AGENT WRITES raw Ruby (atomic: write .tmp then rename) result-.json # GAME WRITES the {id,ok,result,stdout,error,backtrace} envelope bin/ # tiny shell wrappers (run via `sh bin/eval` if not +x) eval tail-log hot-reload snapshot query ``` **Per-frame drain (`Live.poll`, after `Bridge.drain`):** `Dir.entries(.agent)` → select `cmd-*` → for each: read code, **delete the cmd file**, `Bridge.eval_code`, write `result-.json` atomically. `status.json` rewritten throttled (~every 30 frames). The only agent-writable path is `.agent/cmd-*` (P5). ## mruby FS constraints (probed) - **No `Dir.glob`/`Dir[]`** → list with `Dir.entries(dir)` and filter (`start_with?("cmd-")`). - **No `File.write`** class method → `File.open(path,"w") { |f| f.write(s) }`. - Have: `Dir.mkdir`/`entries`/`foreach`, `File.read`/`rename`/`delete`/`unlink`/ `exist?`/`directory?`/`basename`/`join`. **Atomic write = temp + `File.rename`**. - No recursive mkdir → walk path components with `Dir.mkdir` (ignore "exists"). - `.live/` is runtime state → **gitignored**, never committed. ## Acceptance `sh .live/dev/bin/eval 'Rl.get_fps'` returns the JSON envelope; `bin/tail-log` streams `game-console`; `status.json` updates while the game runs; the loop survives. Works against a running desktop game with no relay. ## Web relay (W2 / R4b) — IMPLEMENTED + browser-verified Confirmed in a real browser tab: `sh .live/web/bin/eval 'Rl.get_fps'` → live fps; `Rl.platform` → `:web`; multiline+`puts` returns `result` **and** captured `stdout` (the C fd-redirect works under emscripten MEMFS); `raise` returns a backtrace into `game/physics_playground.rb`; forwarded browser console (incl. the Ruby `Log` NDJSON) lands in `game-console`. The desktop `bin/eval` drives a browser game unchanged. `tools/agent-bridge/server.js` + `web/agent-bridge.js`. **Use it:** ```sh EMSDK_ENV=/path/to/emsdk_env.sh ./build_web.sh # if not already built node tools/agent-bridge/server.js # serves http://localhost:8080 # open http://localhost:8080 in a browser (the game runs), then from a shell: sh .live/web/bin/eval 'Rl.get_fps' # -> JSON envelope from the live tab sh .live/web/bin/tail-log # stream the browser console ``` Verified headlessly with a simulated-browser node poller: `bin/eval` round-trips (`EVAL[...]`), `status.json` + `game-console` populate, `agent-bridge.js` is injected into `game.html` and served (200). The real `Module.jamstack` leg is browser-verified (W1 already proved `eval_json` works on wasm in node). A **dependency-free Node HTTP relay** (`tools/agent-bridge/server.js`) gives the browser tab the *same* `.live//` interface as desktop, so `bin/eval` etc. work identically against a browser game: - The relay **serves `build/web/`** (same-origin → no CORS, no `ws` dep) and injects `