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
This commit is contained in:
2026-03-15 21:24:52 -04:00
parent ead48cd399
commit 83b9037a94
+178 -284
View File
@@ -1,353 +1,247 @@
# Minecraft AI God # 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 <message>` 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
``` - **God prayer pipeline** (`pray <message>`)
Player types: pray <message> - **Two-call LLM architecture**
- command model decides commands (JSON)
- message model writes divine speech (text)
latest.log ←─ tailed by mc_aigod.py - **Divine intervention timer** (random unprompted acts)
- **First-login benevolence** (one-time blessing per player)
- **Bundled sudo translator agent** (`sudo <request>`) with whitelist + user lock
RCON: immediate acknowledgment to player ("The heavens stir...") - **Persistent prayer memory**
- **Rolling server event memory** (up to 3 hours / 200 events)
- **Debug command preview** toggle
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 ## Trigger Commands (Chat, No Slash)
- Python 3.11+ Vanilla 1.21 rejects unknown slash commands client-side. Use plain chat messages:
- `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 - `pray <message>` — prayer flow (God judgment + optional commands + speech)
- `bible` — private usage/help text
- `sudo <request>` — command translator mode (authorized user only)
```properties Examples:
enable-rcon=true - `pray Lord, I need food and shelter`
rcon.port=25575 - `bible`
rcon.password=yourpassword - `sudo give me 500 wood`
broadcast-rcon-to-ops=false
```
--- ---
## 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 ### Two-call design (prayer/intervention)
mc-aigod.service # Systemd unit — deploy to /etc/systemd/system/
Minecraft_Ai_God.md # Full design document with architecture details 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 ## Configuration
`/etc/mc_aigod.json`: Main file: `/etc/mc_aigod.json`
| Key | Type | Default | Description | | Key | Type | Description |
|---|---|---|---| |---|---|---|
| `server_name` | string | required | Server name passed to God's persona | | `server_name` | string | Friendly server name for prompts |
| `log_path` | string | required | Absolute path to `logs/latest.log` | | `log_path` | string | Absolute path to `latest.log` |
| `rcon_host` | string | `"127.0.0.1"` | RCON host | | `rcon_host` | string | RCON host |
| `rcon_port` | int | `25575` | RCON port | | `rcon_port` | int | RCON port |
| `rcon_password` | string | required | RCON password | | `rcon_password` | string | RCON password |
| `ollama_url` | string | required | Ollama base URL e.g. `http://192.168.0.1:11434` | | `ollama_url` | string | Ollama API base URL |
| `model` | string | required | Message model creative writing (e.g. `gemma3:12b`) | | `model` | string | Message model (creative prose) |
| `command_model` | string | falls back to `model` | Commands model — structured JSON (e.g. `qwen3-coder:30b`) | | `command_model` | string | Command model (JSON/command generation) |
| `temperature` | float | `0.85` | Message model temperature | | `temperature` | float | Message generation temperature |
| `max_tokens` | int | `600` | Max tokens for message call | | `max_tokens` | int | Message call max tokens |
| `cooldown_seconds` | int | `20` | Per-player prayer cooldown | | `cooldown_seconds` | int | Prayer cooldown per player |
| `max_commands_per_response` | int | `6` | Max commands God can issue per prayer | | `max_commands_per_response` | int | Max commands in prayer/intervention response |
| `interventions_per_day` | float | `4` | Avg unprompted interventions per 24h. `0` to disable | | `interventions_per_day` | float | Avg random acts/day (Poisson) |
| `debug_commands` | bool | `false` | Show executed commands in-game via dark gray tellraw | | `god_chat_prefix` | string | Prefix for God speech |
| `sudo_enabled` | bool | `true` | Enable sudo translator mode | | `debug_commands` | bool | Show `[~]` command preview in chat |
| `sudo_user` | string | `"slingshooter08"` | Only this username can execute sudo commands | | `god_lore` | string | Optional lore block injected into message system prompt |
| `sudo_max_commands` | int | `3` | Max translated commands per sudo request | | `memory_path` | string | Prayer memory JSON path |
| `memory_path` | string | see below | Path to persist prayer memory JSON | | `sudo_enabled` | bool | Enable/disable sudo agent |
| `god_chat_prefix` | string | `"[GOD]"` | Chat prefix (supports Minecraft color codes) | | `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: `<instance_data_dir>/aigod_memory.json` ### Current shrink-world example
### Example config
```json ```json
{ {
"server_name": "my-server", "server_name": "shrink-world",
"log_path": "/path/to/minecraft/logs/latest.log", "log_path": "/opt/mcsmanager/daemon/data/InstanceData/shrinkborder1234567890abcdef12345/logs/latest.log",
"rcon_host": "127.0.0.1", "rcon_host": "127.0.0.1",
"rcon_port": 25575, "rcon_port": 25576,
"rcon_password": "yourpassword", "rcon_password": "REDACTED_RCON",
"ollama_url": "http://localhost:11434", "ollama_url": "http://192.168.0.141:11434",
"model": "gemma3:12b", "model": "gemma3:12b",
"command_model": "qwen3-coder:30b", "command_model": "qwen3-coder:30b",
"temperature": 0.85, "temperature": 0.85,
"max_tokens": 600, "max_tokens": 600,
"cooldown_seconds": 20, "cooldown_seconds": 20,
"max_commands_per_response": 6, "max_commands_per_response": 6,
"interventions_per_day": 4, "interventions_per_day": 48,
"debug_commands": false, "god_chat_prefix": "[§6§lGOD§r]",
"debug_commands": true,
"sudo_enabled": true, "sudo_enabled": true,
"sudo_user": "slingshooter08", "sudo_user": "slingshooter08",
"sudo_max_commands": 3, "sudo_max_commands": 3,
"memory_path": "/path/to/minecraft/aigod_memory.json", "first_login_benevolence_enabled": true,
"god_chat_prefix": "[§6§lGOD§r]" "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 <message> — send a prayer to God
bible — show help/guidance
sudo <request> — 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 <natural language request>`
- 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 <message>" to pray.
```
---
## God's Capabilities
### Commands God can issue
**Give any item:**
```
give <player> minecraft:<item_id> <count>
give <player> minecraft:<item_id>[enchantments={sharpness:4,unbreaking:3}] 1
xp add <player> <amount> 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 <player> <x> <y> <z>`
**World:** `time set day/night`, `weather clear/thunder/rain <duration>`
**Punishment:** `execute at <player> run summon minecraft:lightning_bolt ~ ~ ~`, `kill <player>`
**Mobs:** `execute at <player> 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 <player> minecraft:<item> <count>` — 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 ## Deployment
```bash ```bash
# Install dependencies # Dependencies
apt install python3-requests apt install -y python3-requests
# Deploy files # Install script + config + service
cp mc_aigod.py /usr/local/bin/mc_aigod.py cp mc_aigod.py /usr/local/bin/mc_aigod.py
chmod +x /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 cp mc-aigod.service /etc/systemd/system/mc-aigod.service
# Enable and start # Start service
systemctl daemon-reload systemctl daemon-reload
systemctl enable --now mc-aigod.service systemctl enable --now mc-aigod.service
# Monitor # Logs
journalctl -fu mc-aigod.service journalctl -fu mc-aigod.service
tail -f /var/log/mc_aigod.log 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: - No response on trigger?
``` - Ensure you typed `pray` / `bible` / `sudo` in chat **without slash**
[~] give slingshooter08 minecraft:spruce_log 64 | weather thunder 6000 - Sudo does nothing?
``` - Confirm username matches `sudo_user`
Never appears in `latest.log`. Toggle off by setting `false` and restarting. - Check `sudo_enabled`
- Unknown item errors?
**Log files:** - See `/var/log/mc_aigod.log` for translated command + server error
- `/var/log/mc_aigod.log` — startup, prayers received, RCON results, errors - Alias/repair may still need extension for new slang terms
- `/var/log/mc_aigod_responses.log` — full untruncated LLM responses with commands and messages - Long God speech issues?
- Two-call design is active; commands are decided separately from message text
**Common issues:** - Random acts too frequent?
- Lower `interventions_per_day`
| 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 ## File Map
### Why no Minecraft plugin? - `mc_aigod.py` — main script
- `mc_aigod_shrink.json` — real config template
No Java plugin required. The script tails `latest.log` for chat lines matching `pray ` and `bible`, then acts via RCON. This means: - `mc-aigod.service` — systemd unit
- Works with any vanilla server version that has RCON - `Minecraft_Ai_God.md` — deeper design/context notes
- No server restart required to install or update - `CONTEXT.md` / `COMMANDS.md` — local infrastructure references
- Script restarts independently of the server
### Log detection patterns
```python
# Chat messages in vanilla 1.21:
# [HH:MM:SS] [Server thread/INFO]: <playername> pray message here
# [HH:MM:SS] [Server thread/INFO]: <playername> 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 ## Deployed Reference (Sethpc)
This was developed and deployed on: - Host: CT 644 (MCSManager)
- MCSManager on CT 644 (Proxmox, Debian 12, node-112) - Server: `shrink-world` (RCON `25576`)
- Minecraft shrink-world server: port 25566, RCON 25576 - Ollama: `http://192.168.0.141:11434`
- Ollama on steel141 (192.168.0.141:11434) - Models:
- Models: `gemma3:12b` (messages), `qwen3-coder:30b` (commands) - message: `gemma3:12b`
- Service: `mc-aigod.service` on CT 644 - commands: `qwen3-coder:30b`
- Config: `/etc/mc_aigod.json` - Service: `mc-aigod.service`
- Script: `/usr/local/bin/mc_aigod.py`