- Replace time-based log window with line-based (200 lines, 3hr cap) - Add per-player position and death count to server context - Add server scoreboards (total deaths, shrink enabled, border parity) - Add god_lore config key injected into message system prompt - Two-call split: qwen3-coder:30b (commands) + gemma3:12b (messages) - interventions_per_day bumped to 48 (avg every 30min) - cooldown_seconds reduced to 20
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+
requestslibrary (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 |
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,
"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
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_bedetc — there is nominecraft:bed - Logs:
oak_log,spruce_logetc — there is nominecraft:log - Wool:
white_wool,red_wooletc — there is nominecraft: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.serviceon CT 644 - Config:
/etc/mc_aigod.json - Script:
/usr/local/bin/mc_aigod.py