From 83b9037a9419011991aacd4910994ac4fad0d3cd Mon Sep 17 00:00:00 2001 From: Seth Date: Sun, 15 Mar 2026 21:24:52 -0400 Subject: [PATCH] Docs: full README refresh for current runtime behavior - Rewrite README to reflect live architecture and feature set - Document pray/bible/sudo triggers (chat without slash) - Document two-call model split and context payloads - Add first-login benevolence behavior and persistence - Add sudo history context and whitelist details - Update config table and shrink-world example values - Refresh deployment and debugging sections --- README.md | 462 +++++++++++++++++++++--------------------------------- 1 file changed, 178 insertions(+), 284 deletions(-) diff --git a/README.md b/README.md index fb080d2..fe11cee 100644 --- a/README.md +++ b/README.md @@ -1,353 +1,247 @@ # 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. +A Python log-watcher + RCON automation script that gives a vanilla Minecraft server an in-game AI "God". -No mods, no plugins, no server restarts required. Works with any vanilla Minecraft 1.21+ server. +Players type chat triggers (`pray`, `bible`, `sudo`) and the agent: +- reads context from server state + player state + recent logs, +- calls local LLM(s), +- executes validated commands via RCON, +- and speaks in public chat. + +No Bukkit/Paper plugin required. --- -## How It Works +## What Is Included -``` -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. +- **God prayer pipeline** (`pray `) +- **Two-call LLM architecture** + - command model decides commands (JSON) + - message model writes divine speech (text) +- **Divine intervention timer** (random unprompted acts) +- **First-login benevolence** (one-time blessing per player) +- **Bundled sudo translator agent** (`sudo `) with whitelist + user lock +- **Persistent prayer memory** +- **Rolling server event memory** (up to 3 hours / 200 events) +- **Debug command preview** toggle --- -## Requirements +## Trigger Commands (Chat, No Slash) -- 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) +Vanilla 1.21 rejects unknown slash commands client-side. Use plain chat messages: -### Minecraft server.properties requirements +- `pray ` — prayer flow (God judgment + optional commands + speech) +- `bible` — private usage/help text +- `sudo ` — command translator mode (authorized user only) -```properties -enable-rcon=true -rcon.port=25575 -rcon.password=yourpassword -broadcast-rcon-to-ops=false -``` +Examples: +- `pray Lord, I need food and shelter` +- `bible` +- `sudo give me 500 wood` --- -## File Structure +## Architecture +```text +chat line -> latest.log tail -> trigger parser + +pray path: + ack player -> gather context -> commands call -> message call -> execute commands -> broadcast message + +sudo path: + auth check -> translate request to commands -> validate/repair -> execute -> private preview + +join path: + login notice -> one-time first-login benevolence event + +timer path: + poisson interval -> if players online -> intervention commands+message ``` -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 -``` + +### Two-call design (prayer/intervention) + +1. **Commands call** (`command_model`) + - strict JSON output + - low temp for stable command generation +2. **Message call** (`model`) + - prose only + - no token competition with command JSON + +This avoids the common failure mode where long speech truncates commands. + +--- + +## Context Passed to LLM + +### Prayer / Intervention context + +- Online players +- Player positions + distance from spawn +- Time of day, weather, world border +- Scoreboard-derived state where available (deaths, shrink flags) +- Recent server events (chat/death/join/leave), capped by both: + - last **3 hours** + - last **200 events** +- Prayer memory (last 10 exchanges) + +### Praying player state + +- Inventory summary (with rarity annotations) +- Health +- Food level +- XP level +- Death count + +### Sudo context + +- Requesting player +- Online players +- Current natural-language sudo request +- Last 10 sudo actions: + - request text + - translated commands + - executed commands + +This helps sudo correct previous bad translations. + +--- + +## Safety and Validation + +- Command-family whitelist enforced (`give`, `effect`, `xp`, `tp`, `time`, `weather`, `execute`, `kill`, `summon`, `tellraw`, `worldborder`) +- Auto-repair for common malformed outputs: + - transposed `give` args (`give player 64 item`) + - missing `minecraft:` namespace + - shorthand aliases (`wood` -> `oak_log`, `door` -> `oak_door`, `bed` -> `white_bed`, etc.) + - malformed `effect` form corrected to `effect give ...` +- Max commands per response cap +- Per-player prayer cooldown +- First-login benevolence can include many commands but is benevolent by prompt rules +- If kill commands appear in first-login mode, at most one player kill is allowed --- ## Configuration -`/etc/mc_aigod.json`: +Main file: `/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) | +| Key | Type | Description | +|---|---|---| +| `server_name` | string | Friendly server name for prompts | +| `log_path` | string | Absolute path to `latest.log` | +| `rcon_host` | string | RCON host | +| `rcon_port` | int | RCON port | +| `rcon_password` | string | RCON password | +| `ollama_url` | string | Ollama API base URL | +| `model` | string | Message model (creative prose) | +| `command_model` | string | Command model (JSON/command generation) | +| `temperature` | float | Message generation temperature | +| `max_tokens` | int | Message call max tokens | +| `cooldown_seconds` | int | Prayer cooldown per player | +| `max_commands_per_response` | int | Max commands in prayer/intervention response | +| `interventions_per_day` | float | Avg random acts/day (Poisson) | +| `god_chat_prefix` | string | Prefix for God speech | +| `debug_commands` | bool | Show `[~]` command preview in chat | +| `god_lore` | string | Optional lore block injected into message system prompt | +| `memory_path` | string | Prayer memory JSON path | +| `sudo_enabled` | bool | Enable/disable sudo agent | +| `sudo_user` | string | Authorized sudo username | +| `sudo_max_commands` | int | Max commands translated from one sudo request | +| `first_login_benevolence_enabled` | bool | Enable one-time first-login blessing | +| `first_login_benevolence_max_commands` | int | Max commands in first-login blessing | +| `first_login_path` | string | Persistent file storing already-blessed players | -Default memory path: `/aigod_memory.json` - -### Example config +### Current shrink-world example ```json { - "server_name": "my-server", - "log_path": "/path/to/minecraft/logs/latest.log", + "server_name": "shrink-world", + "log_path": "/opt/mcsmanager/daemon/data/InstanceData/shrinkborder1234567890abcdef12345/logs/latest.log", "rcon_host": "127.0.0.1", - "rcon_port": 25575, - "rcon_password": "yourpassword", - "ollama_url": "http://localhost:11434", + "rcon_port": 25576, + "rcon_password": "REDACTED_RCON", + "ollama_url": "http://192.168.0.141: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, + "interventions_per_day": 48, + "god_chat_prefix": "[§6§lGOD§r]", + "debug_commands": true, "sudo_enabled": true, "sudo_user": "slingshooter08", "sudo_max_commands": 3, - "memory_path": "/path/to/minecraft/aigod_memory.json", - "god_chat_prefix": "[§6§lGOD§r]" + "first_login_benevolence_enabled": true, + "first_login_benevolence_max_commands": 10, + "first_login_path": "/opt/mcsmanager/daemon/data/InstanceData/shrinkborder1234567890abcdef12345/aigod_first_login_seen.json", + "god_lore": "This is the shrink-world server...", + "memory_path": "/opt/mcsmanager/daemon/data/InstanceData/shrinkborder1234567890abcdef12345/aigod_memory.json" } ``` --- -## 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 -- Uses rolling sudo memory: last 10 sudo actions (request + translated + executed commands) -- Uses strict command-family whitelist (`give`, `effect`, `xp`, `tp`, `time`, `weather`, `execute`, `kill`, `summon`, `tellraw`, `worldborder`) -- Includes syntax repair for common model mistakes (e.g., `give player 64 item`, missing `minecraft:`) -- Must be typed in chat as `sudo ...` (no slash) - -Example: -``` -sudo give me 500 wood -``` -Best-effort translation: -``` -give slingshooter08 minecraft:oak_log 500 -``` - -Another example: -``` -sudo give me 10 doors -``` -Best-effort translation (can be multiple commands): -``` -give slingshooter08 minecraft:oak_door 10 -``` - -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 +# Dependencies +apt install -y python3-requests -# Deploy files +# Install script + config + service 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_shrink.json /etc/mc_aigod.json cp mc-aigod.service /etc/systemd/system/mc-aigod.service -# Enable and start +# Start service systemctl daemon-reload systemctl enable --now mc-aigod.service -# Monitor +# Logs journalctl -fu mc-aigod.service tail -f /var/log/mc_aigod.log -tail -f /var/log/mc_aigod_responses.log # full untruncated LLM responses +tail -f /var/log/mc_aigod_responses.log ``` --- -## Debugging +## Debugging Checklist -**`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 | +- No response on trigger? + - Ensure you typed `pray` / `bible` / `sudo` in chat **without slash** +- Sudo does nothing? + - Confirm username matches `sudo_user` + - Check `sudo_enabled` +- Unknown item errors? + - See `/var/log/mc_aigod.log` for translated command + server error + - Alias/repair may still need extension for new slang terms +- Long God speech issues? + - Two-call design is active; commands are decided separately from message text +- Random acts too frequent? + - Lower `interventions_per_day` --- -## Architecture Notes +## File Map -### 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. +- `mc_aigod.py` — main script +- `mc_aigod_shrink.json` — real config template +- `mc-aigod.service` — systemd unit +- `Minecraft_Ai_God.md` — deeper design/context notes +- `CONTEXT.md` / `COMMANDS.md` — local infrastructure references --- -## Sethpc Infrastructure Context +## Deployed Reference (Sethpc) -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` +- Host: CT 644 (MCSManager) +- Server: `shrink-world` (RCON `25576`) +- Ollama: `http://192.168.0.141:11434` +- Models: + - message: `gemma3:12b` + - commands: `qwen3-coder:30b` +- Service: `mc-aigod.service`