Architecture

Deployment & Operations

🚀 Deployment & Operations#

Prerequisites#

  • Node.js 18+ (20.x used in production)
  • Java runtime for Paper/Spigot (server/)
  • API keys in bots/keys.json (see keys.example.json)

Repository Layout#

Path Role
Repo root launch_all.sh, verify_stack.sh, ecosystem.config.*, scripts/
bots/ Bot swarm (main.js), relay (dashboard.js), settings.js, keys.json, profiles
bots/dashboard/ Svelte 5 dashboard
bots/dashboard.js Relay / API + Socket.IO backend
server/ Minecraft world, server.properties, Paper jar

Default Ports (Override with Env)#

Service Default Port Env Var
Minecraft 25565 MOINCRAFT_SPIGOT_PORT
Svelte dashboard 55666 MOINCRAFT_NEW_DASHBOARD_PORT
Dashboard relay / API 55667 DASHBOARD_PORT
MindServer 55668 MINDSERVER_PORT
Prismarine viewer 55669 MOINCRAFT_VIEWER_PORT

Start the Stack#

cd ~/moincraft
./launch_all.sh

Override bot profiles:

MOINCRAFT_PROFILES="./profiles/agents/openrouter1.json ./profiles/agents/openrouter2.json" ./launch_all.sh

Verify#

./verify_stack.sh          # HTTP health checks on all ports
cd bots && npm run relay:contract   # JSON shape validation
npm run green              # check + build + verify + relay contract

Stop All#

./stop_all.sh

Keys and Models#

  • Global keys: bots/keys.json
  • Agent profiles: bots/profiles/agents/*.json
  • Default profile list: bots/settings.js
  • OpenRouter: set OPENROUTER_API_KEY; optional OPENROUTER_BASE_URL

Agent Profile Keys (Quick Reference)#

{
  "name": "AgentName",
  "model": { "api": "...", "model": "...", "url": "...", "params": {} },
  "conversing": "system prompt with $VARs",
  "coding": "coding system prompt",
  "modes": { "mode_name": true/false },
  "npc": { "health": 20, "hunger": 20 },
  "cooldown": 0,
  "max_tokens": null
}

Settings Reference (settings.js)#

Key Default Env Var
minecraft_version 'auto' MINECRAFT_VERSION
host 'localhost'
port 25565 MINECRAFT_PORT
auth 'offline'
base_profile 'survival'
load_memory false
allow_insecure_coding true INSECURE_CODING
max_messages 15 MAX_MESSAGES
spawn_timeout 600
allow_vision false
blocked_actions [] BLOCKED_ACTIONS (JSON)
log_all_prompts true LOG_ALL
num_examples 2 NUM_EXAMPLES

OpenRouter Integration#

// Standard OpenAI-compatible client
const openai = new OpenAIApi({
  baseURL: 'https://openrouter.ai/api/v1',
  apiKey: getKey('OPENROUTER_API_KEY')
})

Profile Format#

{
  "name": "Gemmiii",
  "model": { "api": "openrouter", "model": "google/gemini-2.5-flash" },
  "embedding": { "api": "openrouter", "model": "text-embedding-3-small" }
}

Model String Shortcuts#

"openrouter/google/gemini-2.5-pro"   ← api prefix auto-stripped
"google/gemini-2.5-flash"            ← works with api: "openrouter"
"model:nitro"                        ← fastest provider (throughput sort)
"model:floor"                        ← cheapest provider (price sort)

Provider Routing#

provider: {
  sort: 'throughput' | 'latency' | 'price',
  order: ['google', 'openai'],
  allow_fallbacks: true,
  data_collection: 'deny',       // zero data retention
  quantizations: ['fp8', 'bf16'] // model quantization filter
}

Unused OpenRouter Features (Available)#

  • Streaming (SSE): stream: true + for await (const chunk of stream)
  • Embeddings: NOW SUPPORTED — openai.embeddings.create({ model, input })
  • Structured Outputs: response_format: { type: 'json_schema', json_schema: {...} }
  • Plugins: { id: 'web' } { id: 'file-parser' } { id: 'response-healing' }
  • App Identity: HTTP-Referer + X-Title headers
  • Auto Router: model: 'openrouter/auto'

PM2 Operations#

pm2 list                         # status
pm2 logs [name] --lines 100      # tail logs
pm2 restart [name]               # restart
pm2 save                         # persist process list
npx pm2 start ecosystem.config.cjs

Paper 1.21.11 JVM Flags (Aikar’s G1GC)#

-Xms10G -Xmx10G
-XX:+UseG1GC
-XX:+ParallelRefProcEnabled
-XX:MaxGCPauseMillis=200
-XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40
-XX:G1HeapRegionSize=8M
-XX:InitiatingHeapOccupancyPercent=15
-XX:SurvivorRatio=32
-XX:MaxTenuringThreshold=1
-XX:+PerfDisableSharedMem
-XX:+AlwaysPreTouch

World Spawn Offset#

Stop the MC server first:

node scripts/offset_world_spawn.mjs --east 200 --apply

Backs up level.dat before applying.

Environment Variables Quick Reference#

# Server
MINECRAFT_VERSION=1.21.11
MINECRAFT_PORT=25565
MINDSERVER_PORT=55668

# Dashboard
DASHBOARD_PORT=55667
DASHBOARD_API_TOKEN=your-token-here
MOINCRAFT_NEW_DASHBOARD_PORT=55666

# Swarm
MOINCRAFT_PROFILES="./profiles/agents/groq1.json ./profiles/agents/groq2.json"
VIEWER_USERNAME=Spectator
MOINCRAFT_PUBLIC_HOST=moincraft.de

# Agent behavior
INSECURE_CODING=true
MAX_MESSAGES=15
NUM_EXAMPLES=2
LOG_ALL=true
BLOCKED_ACTIONS=[]