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(seekeys.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; optionalOPENROUTER_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-Titleheaders - 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=[]