# Llamagochi A browser-based virtual pet llama that mirrors a running `llama-server` instance by tailing its log file. The llama animates differently depending on what the server is doing — loading a model, processing a prompt, generating tokens, sleeping, or erroring out. ``` IDLE PROCESSING PROMPT GENERATING SLEEPING ear twitches eyes scan left/right mouth talks zzz floats up progress bar shown tail wags ``` ## Requirements - Python 3.10+ - `llama-server` running in **router mode** (the multi-model router that logs `cmd_child_to_router:state:{...}` JSON lines) - The log file must be accessible from the machine running Llamagochi (local path or a mount) ## Installation ```bash git clone cd llamagochi python -m venv venv source venv/bin/activate pip install -r requirements.txt ``` ## Running ```bash python server.py --log /path/to/llama-server.log ``` The web UI is then available at `http://localhost:8080`. ### Options | Flag | Default | Description | |---|---|---| | `--log PATH` | — | Path to the llama-server log file (required unless set in `config.json` or `$LLAMAGOCHI_LOG`) | | `--port PORT` | `8080` | HTTP port to listen on | | `--reopen-log` | off | Close and reopen the log file on every poll cycle. Use this when the log is on a network filesystem (sshfs, NFS) that caches file content at open time | ### Configuration file Instead of passing `--log` every time, create `config.json` in the project directory: ```json { "log": "/path/to/llama-server.log", "reopen_log": true } ``` `reopen_log` in the config is equivalent to `--reopen-log` on the command line. CLI flags take precedence. ### Environment variable ```bash export LLAMAGOCHI_LOG=/path/to/llama-server.log python server.py ``` ## Reverse proxy (HTTPS) Llamagochi uses WebSocket (`/ws`) and HTTP polling (`/state`). Both must be proxied. Example nginx snippet: ```nginx location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; } ``` The frontend automatically uses `wss://` when the page is served over HTTPS. ## States | State | What it means | |---|---| | `idle` | Server is up, no active request | | `waiting` | Router received a request, slot not yet assigned | | `loading` | Model is loading into VRAM (progress bar shown) | | `warming_up` | Model weights loaded, running warmup pass | | `processing_prompt` | Evaluating the prompt (progress bar 0–100%) | | `generating` | Generating tokens | | `sleeping` | Server idle-timeout reached, model evicted | | `unloading` | LRU eviction in progress | | `error` | Model failed to load | | `offline` / `LOG OFFLINE` | Llamagochi cannot read the log file | ## Connection status dot (top-right of screen) | Colour | Meaning | |---|---| | Green | WebSocket live — real-time updates | | Amber | WebSocket down, falling back to HTTP polling every 2 s | | Red | Both WebSocket and HTTP polling are unreachable | When the WebSocket reconnects, polling stops automatically. ## Log file format Llamagochi expects the log produced by `llama-server` router mode, optionally prefixed with timestamps by the `ts` utility: ``` [2026-06-22 20:09:31] [51201] 3.13.636.722 I srv update_slots: all slots are idle [2026-06-22 20:09:31] 339.42.030.150 I srv proxy_reques: proxying request to model ... ``` Lines prefixed with `[PORT]` are child-process lines; unprefixed lines are router-level. Both are understood. ## Running tests ```bash pytest ``` 32 tests covering the log parser state machine and log watcher.