# Minecraft AI God A Python-based "plugin" for vanilla Minecraft servers that integrates a locally-hosted LLM as an in-game God character. Players interact by typing `pray ` in chat. God responds with dramatic prose and optionally executes server commands via RCON. No mods, no plugins, no server restarts required. Works with any vanilla Minecraft 1.21+ server. --- ## How It Works ``` Player types: pray │ ▼ latest.log ←─ tailed by mc_aigod.py │ ▼ RCON: immediate acknowledgment to player ("The heavens stir...") │ ▼ RCON: fetch live server context - Online players, time of day, weather, world border │ ▼ RCON: fetch praying player's state - Full inventory (with rarity annotations), position, health, food, XP, deaths │ ▼ Call 1 — command_model (qwen3-coder:30b or similar) - Decides what server commands to execute (JSON only, no prose) - Low temperature (0.3) for precise structured output │ ▼ Call 2 — model (gemma3:12b or similar) - Writes God's spoken message knowing what was decided - No token competition with commands — full creative freedom │ ▼ RCON: execute commands + broadcast message ``` **Divine Intervention Timer** — a background thread fires at random intervals (Poisson process, user-defined average per day). If players are online, God acts unprompted. LLM can choose silence (`commands: []`) and nothing happens. **Memory** — last 10 prayer exchanges stored as conversation history and passed to every LLM call. Persists across service restarts via JSON file. God remembers. **Server log context** — last 20 minutes of meaningful server events (chat, deaths, joins, leaves) included with every prayer. God knows what's been happening. --- ## Requirements - Python 3.11+ - `requests` library (`apt install python3-requests`) - Ollama instance with at least one model pulled - Minecraft vanilla server with RCON enabled - Server running on Linux (systemd for service management) ### Minecraft server.properties requirements ```properties enable-rcon=true rcon.port=25575 rcon.password=yourpassword broadcast-rcon-to-ops=false ``` --- ## File Structure ``` mc_aigod.py # Main script — deploy to /usr/local/bin/ mc_aigod_shrink.json # Example config — deploy to /etc/mc_aigod.json mc-aigod.service # Systemd unit — deploy to /etc/systemd/system/ Minecraft_Ai_God.md # Full design document with architecture details ``` --- ## Configuration `/etc/mc_aigod.json`: | Key | Type | Default | Description | |---|---|---|---| | `server_name` | string | required | Server name passed to God's persona | | `log_path` | string | required | Absolute path to `logs/latest.log` | | `rcon_host` | string | `"127.0.0.1"` | RCON host | | `rcon_port` | int | `25575` | RCON port | | `rcon_password` | string | required | RCON password | | `ollama_url` | string | required | Ollama base URL e.g. `http://192.168.0.1:11434` | | `model` | string | required | Message model — creative writing (e.g. `gemma3:12b`) | | `command_model` | string | falls back to `model` | Commands model — structured JSON (e.g. `qwen3-coder:30b`) | | `temperature` | float | `0.85` | Message model temperature | | `max_tokens` | int | `600` | Max tokens for message call | | `cooldown_seconds` | int | `20` | Per-player prayer cooldown | | `max_commands_per_response` | int | `6` | Max commands God can issue per prayer | | `interventions_per_day` | float | `4` | Avg unprompted interventions per 24h. `0` to disable | | `debug_commands` | bool | `false` | Show executed commands in-game via dark gray tellraw | | `sudo_enabled` | bool | `true` | Enable sudo translator mode | | `sudo_user` | string | `"slingshooter08"` | Only this username can execute sudo commands | | `sudo_max_commands` | int | `3` | Max translated commands per sudo request | | `memory_path` | string | see below | Path to persist prayer memory JSON | | `god_chat_prefix` | string | `"[GOD]"` | Chat prefix (supports Minecraft color codes) | Default memory path: `/aigod_memory.json` ### Example config ```json { "server_name": "my-server", "log_path": "/path/to/minecraft/logs/latest.log", "rcon_host": "127.0.0.1", "rcon_port": 25575, "rcon_password": "yourpassword", "ollama_url": "http://localhost:11434", "model": "gemma3:12b", "command_model": "qwen3-coder:30b", "temperature": 0.85, "max_tokens": 600, "cooldown_seconds": 20, "max_commands_per_response": 6, "interventions_per_day": 4, "debug_commands": false, "sudo_enabled": true, "sudo_user": "slingshooter08", "sudo_max_commands": 3, "memory_path": "/path/to/minecraft/aigod_memory.json", "god_chat_prefix": "[§6§lGOD§r]" } ``` --- ## Player Usage Type in chat (no slash — vanilla 1.21 rejects unknown slash commands client-side): ``` pray — send a prayer to God bible — show help/guidance sudo — command translator mode (authorized user only) ``` ### Sudo Translator Mode `sudo` is a separate agent path bundled in the same script. It does not use God's persona or speech pipeline. - Trigger: `sudo ` - Authorization: only `sudo_user` (default `slingshooter08`) - Model: uses `command_model` - Output: JSON commands only, then executes via same whitelist validator - No divine speech generated Example: ``` sudo give me 500 wood ``` Best-effort translation: ``` give slingshooter08 minecraft:oak_log 500 ``` On login players see: ``` [GOD] GOD ENABLED — Type "bible" in chat for guidance. Type "pray " to pray. ``` --- ## God's Capabilities ### Commands God can issue **Give any item:** ``` give minecraft: give minecraft:[enchantments={sharpness:4,unbreaking:3}] 1 xp add levels ``` **Effects (positive/negative):** regeneration, strength, speed, night_vision, fire_resistance, water_breathing, instant_health, blindness, slowness, weakness, hunger, nausea, levitation, effect clear **Movement:** `tp ` **World:** `time set day/night`, `weather clear/thunder/rain ` **Punishment:** `execute at run summon minecraft:lightning_bolt ~ ~ ~`, `kill ` **Mobs:** `execute at run summon minecraft:creeper ~ ~ ~3` ### Item naming rules (Minecraft 1.21) - Always use `minecraft:` namespace prefix - Beds: `white_bed`, `red_bed` etc — there is no `minecraft:bed` - Logs: `oak_log`, `spruce_log` etc — there is no `minecraft:log` - Wool: `white_wool`, `red_wool` etc — there is no `minecraft:wool` - Enchantments use component syntax: `item[enchantments={sharpness:5,unbreaking:3}]` - Give syntax: `give minecraft: ` — count is LAST ### God's persona - Benevolent but just, theatrical and dramatic (Old Testament style) - Aware of player inventory, health, food, position, deaths - Aware of server state: time, weather, world border, online players - Aware of recent server events: deaths, chat, joins, leaves (last 20 min) - Remembers last 10 prayer exchanges across all players - Acts on own accord via intervention timer — may choose silence - Not obligated to grant requests — may reward someone else, punish the requester, or do something unexpected --- ## Model Recommendations **Command model** — needs reliable structured JSON output and Minecraft syntax knowledge: - `qwen3-coder:30b` (recommended, ~19GB Q4) - `qwen2.5:1.5b` (fast/small, acceptable for commands) **Message model** — needs creative writing, roleplay, dramatic biblical prose: - `gemma3:12b` (recommended, ~8GB) - `llama3.1:8b` (good alternative) Avoid coding models for the message role. Avoid general models for the command role. Both calls go to the same Ollama instance. If both models fit in VRAM simultaneously there is no swap overhead. If not, Ollama swaps them — adds a few seconds per prayer. --- ## Deployment ```bash # Install dependencies apt install python3-requests # Deploy files cp mc_aigod.py /usr/local/bin/mc_aigod.py chmod +x /usr/local/bin/mc_aigod.py cp mc_aigod_shrink.json /etc/mc_aigod.json # edit as needed cp mc-aigod.service /etc/systemd/system/mc-aigod.service # Enable and start systemctl daemon-reload systemctl enable --now mc-aigod.service # Monitor journalctl -fu mc-aigod.service tail -f /var/log/mc_aigod.log tail -f /var/log/mc_aigod_responses.log # full untruncated LLM responses ``` --- ## Debugging **`debug_commands: true` in config** — shows executed commands in-game as dark gray italic text: ``` [~] give slingshooter08 minecraft:spruce_log 64 | weather thunder 6000 ``` Never appears in `latest.log`. Toggle off by setting `false` and restarting. **Log files:** - `/var/log/mc_aigod.log` — startup, prayers received, RCON results, errors - `/var/log/mc_aigod_responses.log` — full untruncated LLM responses with commands and messages **Common issues:** | Symptom | Cause | Fix | |---|---|---| | `Unknown item 'minecraft:64'` | LLM put count before item | Auto-fixed by `fix_give_command()`, also update command model | | `Unknown item 'minecraft:bed'` | Missing colour prefix | Item library includes warning; auto-namespaced | | Message truncated | Token limit hit | Increase `max_tokens`; two-call split helps | | `commands: []` but message says it will give something | LLM treating message as action | CRITICAL rule in prompt: commands array is the only way things happen | | Prayer not detected | Typed as `/pray` (slash command) | Must type `pray` in chat without slash | --- ## Architecture Notes ### Why no Minecraft plugin? No Java plugin required. The script tails `latest.log` for chat lines matching `pray ` and `bible`, then acts via RCON. This means: - Works with any vanilla server version that has RCON - No server restart required to install or update - Script restarts independently of the server ### Log detection patterns ```python # Chat messages in vanilla 1.21: # [HH:MM:SS] [Server thread/INFO]: pray message here # [HH:MM:SS] [Server thread/INFO]: bible PRAY_PATTERN = re.compile(r'\[.*?\]: <(\w+)> [Pp]ray (.+)') BIBLE_PATTERN = re.compile(r'\[.*?\]: <(\w+)> [Bb]ible\s*$') JOIN_PATTERN = re.compile(r'\[.*?\]: (\w+) joined the game') ``` Note: `/pray` as a slash command does NOT work — vanilla 1.21 rejects unknown commands client-side before they reach the server log. ### Two-call LLM architecture ``` Prayer received │ ├─► Command call (command_model, temp=0.3, max_tokens=200, format=json) │ System: terse spec, command palette, item rules │ Returns: {"commands": [...]} │ └─► Message call (model, temp=0.85, max_tokens=600, no format constraint) System: God persona only User: prayer + context + "You decided to execute: [commands]" Returns: plain prose, any length ``` Separating the calls means: - Commands are never truncated by a long message - Message has full token budget for dramatic prose - Each model does what it's best at ### Prayer memory format Stored as a list of `[player, prayer, god_message]` tuples in JSON. Loaded at startup, appended after every successful prayer, capped at 10 entries. Injected into the message call as alternating `user`/`assistant` messages so the LLM sees genuine conversation history. ### Divine intervention timing Uses exponential distribution (`random.expovariate`) — the correct model for Poisson arrivals. `interventions_per_day=4` means an average gap of 6 hours but intervals are random and memoryless. Could be 3 in one hour, then nothing for 18 hours. --- ## Sethpc Infrastructure Context This was developed and deployed on: - MCSManager on CT 644 (Proxmox, Debian 12, node-112) - Minecraft shrink-world server: port 25566, RCON 25576 - Ollama on steel141 (192.168.0.141:11434) - Models: `gemma3:12b` (messages), `qwen3-coder:30b` (commands) - Service: `mc-aigod.service` on CT 644 - Config: `/etc/mc_aigod.json` - Script: `/usr/local/bin/mc_aigod.py`