Wiki · main

cogame-minecraft

Last edited by · ·

cogame-minecraft

One cog, four stacked levels, and the MineRL ObtainDiamond ladder.

A single-agent Coworld. One cog stands in the middle of a seeded blocky world with nothing in its hands. Underneath it are three more floors it cannot see: stone, iron depth, diamond depth. It has 960 ticks to climb eleven rungs —

log → planks → crafting table → wooden pickaxe → cobblestone → stone pickaxe → iron ore → furnace → iron ingot → iron pickaxe → diamond

— and every rung is worth double every rung beneath it put together, so the score is exactly how deep it got, with speed as the tie-break. Nothing is hunting it. It never eats, drinks or sleeps. The only lethal thing in the world is lava, and the only pressure is the clock.

The cog sees 11 × 11 on the surface and only 5 × 5 underground, and a level it has never descended to is entirely ?. You cannot see through the floor. Wood exists only on the surface, so the six turns you spend walking back up for forgotten planks are six turns you do not get back.

This is an in-spirit reimplementation of the MineRL ObtainDiamond problem as its own deterministic seeded simulator. No Malmo, no MineRL, no MineDojo code is vendored, and no score here is comparable to a published benchmark number — see docs/PORTING-MINECRAFT.md.

Docs

  • docs/RULES.md — the world, the blocks, the recipes, the scoring formula, the end conditions, the two variants.
  • docs/ACTIONS.md — the seventeen primitives, the three macros, the reply schema and its caps, and the full observation.
  • docs/MILESTONES.md — the eleven rungs, why the values double, and what the tick budget buys.
  • docs/PORTING-MINECRAFT.md — every documented divergence, from Minecraft and from the design note.
  • docs/PROTOCOL.md — the wire protocol, the routes, the registration message and the replay format.

A policy is just a prompt

Both champions are LLM prompt policies; both fillers are scripted baselines; one image, switched by env.

coworld upload-policy coworld-minecraft:latest --name my-minecraft \
  --run /bin/minecraft-player \
  --secret-env PLAYER_PROMPT="Get to the diamond. Nothing else is worth a tick."
EnvEffect
PLAYER_PROMPTthis seat is an LLM seat; the text is your whole strategy
PLAYER_SCRIPTED=minerthe published deterministic baseline — and the server-side fallback
PLAYER_SCRIPTED=scroungerthe reactive control: no memory, no pathfinding, no ore targeting
PLAYER_POLICY_LABELa free label for the replay's register record

A seat that sets neither is miner.

The LLM call is made by the GAME container, not the player container — that is the only container the platform injects the anthropic_api_key coworld secret into, and it is what makes the recorded primitive log reproducible with no network in the loop. The player process connects, registers, and then only acknowledges frames.

Degrade, never hang

Every wait is bounded. One request per turn, attempt1Ms = 6000; one retry, retryMs = 3000; a monotonic turnBudgetMs = 9500 around the whole turn; turnSpacingMs = 2600 pinning the steady state at 23 req/min against the sidecar's 30/min cap; a rolling 60 s rate guard; a budget guard that switches the LLM off the moment two more full turns would not fit; and the engine's own wallClockBudgetSeconds = 660 stop. Typical episode: 199 s. Absolute worst case: 577 s. The platform's budget is 1200 s and the pin is 60 % of it (720 s).

On a second failure the turn's plan becomes the miner scripted plan — the same proc the published baseline uses, imported, never duplicated — and a fallback record names the cause. No failure mode leaves the cog without an action: the tick loop always has a primitive, else noop, which is a legal state that costs a tick and nothing else.

Watching it

The replay is a static wasm bundle, never a pod: tools/build_replay_viewer.sh compiles the same sim module to WebAssembly through the pinned emscripten/emsdk:4.0.15 container and bundles it with the inherited coworld-ctf broadcast chrome. The viewer re-derives every frame in the browser from the replay's seed, its per-turn plans and its per-tick hash chain; nothing is contacted except S3 for the file.

What you see: the 15-cell follow-cam over the level the cog is on (the board is 32 × 32 cells and the level swaps with a wipe when the run goes deeper), the milestone ladder lighting rung by rung in the left gutter, the strata gauge showing every shaft it has cut and every ore it has seen at its true depth, the cog's own 5 × 5 window as an inset, and the feed where the LLM narrates. The scrubber carries labelled, clickable beats for exactly five kinds: milestone, newdepth, death, fallback, end.

Layout

PathWhat
src/minecraft/the sim: world (generation, BFS, visibility), agent (the seventeen primitives), milestones, sim_state (the tick loop and the hash), roster (results), observe, driver, baselines, decide, llm, replays, broadcast, global, server
src/minecraft.nimthe game entrypoint → /bin/minecraft
src/minecraft_player.nimthe thin seat registrar → /bin/minecraft-player
client/the inherited broadcast chrome plus the appended game block
replay-viewer/the wasm entry, the emscripten flags and the static shell
data/art/the nano-banana board sprites (source sheets + split script in tools/art/)
tests/the Nim suite ci.yml runs in debug AND release
tools/ci/the docker smoke, the viewer smoke, the renderer fixture and the policy set

Building and testing

The repo needs Nim 2.2.4 and the nimby.lock package tree; ci.yml is the harness of record.

nimby use 2.2.4
nimby --global sync nimby.lock
nim r --path:src tests/test_minecraft_sim.nim        # any one test file
docker build --platform=linux/amd64 -t coworld-minecraft:ci .
./tools/ci/docker_smoke.sh coworld-minecraft:ci      # one real episode
./tools/build_replay_viewer.sh "$PWD/dist/static-replay-viewer"
node tools/ci/viewer_smoke.mjs --bundle dist/static-replay-viewer \
  --replay dist/smoke/*.replay --soak 10 --strict-text-bounds

tools/replay_summary.py prints one strict-UTF-8 JSON object for any .replay using nothing but the Python 3 standard library.

Licence

MIT. Forked from Metta-AI/coworld-ctf.