Files
minecraft-ai-god-paper-fork/README.md
T
Seth 52d288406a Add sudo translator agent with whitelist and user lock
- New sudo chat trigger: 'sudo <request>'
- Authorized user only (configurable, default slingshooter08)
- Uses command_model to translate natural language to JSON commands
- Executes commands through existing whitelist/validator pipeline
- No God persona or speech call in sudo mode
- Added sudo_enabled/sudo_user/sudo_max_commands config keys
- Added common give-item alias normalization (wood->oak_log, bed->white_bed)
- Updated README with sudo usage and config docs
2026-03-15 19:56:50 -04:00

12 KiB

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.

No mods, no plugins, no server restarts required. Works with any vanilla Minecraft 1.21+ server.


How It Works

Player types: pray <message>
        │
        ▼
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

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: <instance_data_dir>/aigod_memory.json

Example config

{
  "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 <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

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 <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

# 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

# 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

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