# Oracle Bot — Mortdecai Mind's Eye **Date:** 2026-03-22 **Status:** Approved design, pending implementation **Public URL:** `mind.mortdec.ai` ## Summary A live HTML5 viewport that renders what the Mortdecai AI model "sees" during Minecraft server interactions. An invisible spectator bot (mineflayer) maintains real-time world state, the gateway streams tool traces to it, and browsers connect via WebSocket to watch the AI think. ## Architecture ``` Browser (mind.mortdec.ai) ↕ WebSocket (ws://CT644:3333) Oracle Bot (Node.js, single process) ├── MC Client (mineflayer, spectator mode) ├── Vision Server (Express + ws, port 3333) ├── Trace Receiver (POST /trace from gateway) └── Command API (POST /command, future tool integration) ↕ MC Protocol (offline auth) Paper Server (1.21, CT 644:25568 dev) ``` **Approach:** Smart Bot is the Server (Approach 2). One Node.js process handles MC connection, WebSocket streaming, and HTTP endpoints. Designed to evolve into a gateway tool (Approach 3) where the AI controls the bot directly. ## Bot Core ### Three roles in one process: 1. **MC Client** — mineflayer bot in spectator mode. Maintains live chunk cache, entity list, player positions. Username: `OracleBot`. Connects to dev server (port 25568, offline auth). 2. **Vision Server** — Express + ws. Serves the HTML5 frontend. Streams world state and tool traces to connected browsers via WebSocket on port 3333. 3. **Trace Receiver** — `POST /trace` endpoint. Gateway calls this (fire-and-forget) on every tool invocation during the model-driven tool loop. ### Future-ready command API: - `POST /command` — accepts instructions: `{action: "follow", target: "player"}`, `{action: "scan", center: {x,y,z}, radius: 20}` - Day one: only `follow` and `scan` implemented - Endpoint exists so the gateway can later call it as a tool (`oracle.scan`, `oracle.look`) ### Bot behavior: - On connect: spectator mode, fly to first online player - Follows the player the AI is currently interacting with (switches on trace events) - On idle: parks at last active player or world spawn ## Data Flow & States ### Two modes: **Idle Mode (no active trace):** - Bot parks at last active player position - Low-frequency heartbeat to browsers: player list, positions, time, weather - Update rate: ~5 seconds - Frontend: calm ambient view, slow-updating minimap, player dots **Active Mode (trace incoming):** - Gateway fires `POST /trace` with tool call data - Bot teleports to relevant player - Scans burst of chunk data around player - High-frequency updates: blocks, entities, tool trace overlay - God mode: dramatic visual (golden glow, Sethian orange accents) - Sudo mode: clinical/technical (grid overlay, command syntax) - Persists 10s after last trace, then fades to idle ### WebSocket message types: ```javascript // Heartbeat (idle) {type: "heartbeat", players: [{name, x, y, z}], time: 6000, weather: "clear"} // World snapshot (active) {type: "world", center: {x, y, z}, blocks: [{x, y, z, type}], entities: [{type, x, y, z, count}]} // Tool trace event (active) {type: "trace", tool: "world.scan_area", input: {...}, result: {...}, step: 2, mode: "god"} // Mode change {type: "mode", mode: "god"|"sudo"|"idle", player: "slingshooter08"} ``` ## Frontend (HTML5 Canvas) ### Single page, no build step. Pure HTML5 Canvas + vanilla JS. **Layout:** ``` ┌─────────────────────────────────┬──────────────────┐ │ │ TOOL TRACE │ │ WORLD MAP │ │ │ (2D top-down tiles) │ [scan_area] ● │ │ │ [rcon.exec] ● │ │ ○ player dots │ [journal] ● │ │ █ blocks colored by type │ │ │ ◇ entities │ step 3/8 │ │ │ │ ├─────────────────────────────────┤ │ │ STATUS BAR │ │ │ Mode: GOD | Player: sling... │ │ │ HP: 20 | Pos: (12, -60, 15) │ │ └─────────────────────────────────┴──────────────────┘ ``` ### Visual modes: - **Idle:** Dark muted palette, slow pulse animation. Sleeping eye aesthetic. - **God active:** Sethian orange (#D35400), golden particles on commands, dramatic god message text. Blocks glow where AI acts. - **Sudo active:** Cool blue/green terminal aesthetic, monospace overlays, precise grid. Clinical. ### Block rendering: - Each block type → color (stone=gray, dirt=brown, water=blue, redstone=red, air=transparent) - Top-down slice at player Y level (configurable) - Entities as icons/dots with distance rings - Scanned areas pulse/highlight as tool traces arrive ("AI is looking here") ### Branding: - Font: Rajdhani Bold - Primary accent: Sethian orange (#D35400) - Background: dark (#1a1a2e) - Title: "MORTDECAI — MIND'S EYE" - Subtle eye/pyramid motif ## Security & Resilience ### Public vs internal endpoints: - **Public (via Caddy):** WebSocket `/ws`, static files `/`, `/index.html` - **Internal only (localhost):** `POST /trace`, `POST /command` — Caddy must NOT proxy these. Gateway calls them on localhost:3333 directly. - WebSocket: max 100 concurrent connections, per-IP cap of 5. Excess connections get 429. ### Caddy config: ``` mind.mortdec.ai { reverse_proxy /ws localhost:3333 reverse_proxy / localhost:3333 { # Only serve static files and WebSocket, not /trace or /command } @blocked path /trace /command respond @blocked 404 } ``` ### Chunk loading after teleport: - After bot teleports to a player, wait 2 seconds for chunk packets before scanning - `world-state.js` tracks chunk load events and exposes `awaitChunksLoaded(center, radius, timeoutMs)` - If timeout expires, scan with whatever chunks are loaded (partial data is better than no data) ### Spectator mode enforcement: - Add to `mc_aigod_paper.py` PlayerJoinEvent: if player name is `OracleBot`, set gamemode spectator before spawn - Fallback: bot self-executes `/gamemode spectator OracleBot` via chat on spawn event ### Bot reconnection: - On `kicked` or `end` event: exponential backoff reconnect (1s, 2s, 4s, 8s, max 30s) - Broadcast `{type: "status", connected: false}` to all browsers on disconnect - Frontend shows "Bot offline — reconnecting..." overlay with pulse animation - On reconnect: broadcast `{type: "status", connected: true}`, resume normal flow ### Payload limits: - World snapshots: max 32x32x1 top-down slice (1,024 blocks). Air blocks excluded. - Delta compression: after initial snapshot, only send changed blocks - Max WebSocket frame: 64KB. If payload exceeds, chunk into multiple messages. ### Multiple simultaneous sessions: - Trace events include `session_id` and `player` fields - Bot follows the most recent trace's player - Frontend tool trace panel shows all active sessions, color-coded by player - If two sessions overlap, traces interleave in the timeline (both visible) ### Message versioning: - All WebSocket messages include `v: 1` field - Frontend ignores messages with unknown `v` values gracefully ## Deployment **Location:** CT 644 (same container as MC servers + gateway). Lowest latency. **Public access:** ``` mind.mortdec.ai → Caddy (CT 600) → CT 644:3333 (WebSocket upgrade) ``` - No Authelia — fully public - DNS: CNAME to Caddy ingress **Gateway integration (minimal):** - One addition to `langgraph_gateway.py`: fire-and-forget POST to `http://localhost:3333/trace` after each tool call - Also POST on session start (mode + player) and session end (final response) - Non-blocking: try/except with 1s timeout. If bot is down, gateway doesn't care. **Process management:** - systemd service: `oracle-bot.service` - Auto-restart on crash - Logs: `/var/log/oracle-bot.log` **Server-side setup:** - Paper server needs to `/gamemode spectator OracleBot` on join (command block or plugin event) ## Future Evolution ### Phase 2: Gateway tool integration - `oracle.scan` tool — model queries bot's chunk cache instead of RCON. Faster, richer. - `oracle.look` tool — bot teleports to coords and returns what it sees. - `POST /command` endpoint (built day one) becomes the tool backend. ### Phase 3: Multi-bot fleet - Oracle spawns additional bots on command - Model dispatches: `oracle.dispatch({task: "watch", target: "SwiftWolf"})` - All bots feed into same vision server → same frontend ### Phase 4: Multimodal training capture - Frontend frames captured as screenshots paired with model decisions - Builds (visual_state, model_action) dataset for multimodal fine-tuning - Mind's Eye becomes training data for visual understanding ## Tech Stack - **Bot + Server:** Node.js, mineflayer, express, ws - **Frontend:** HTML5 Canvas, vanilla JS, WebSocket API - **Integration:** HTTP POST (gateway → bot), WebSocket (bot → browser) - **Deployment:** systemd on CT 644, Caddy reverse proxy ## File Structure ``` oracle-bot/ ├── package.json # entrypoint: "main": "server.js" ├── server.js # ENTRYPOINT — express + ws, requires bot.js, serves frontend ├── bot.js # mineflayer connection, spectator, chunk tracking ├── world-state.js # abstracted world state (blocks, entities, players) ├── public/ │ └── index.html # single-file frontend (HTML + Canvas + JS + CSS) └── README.md ```