JeanKaddour/sokoban_speedrun

RL models to play Sokoban. The fastest recipe wins.

Python

31

190 commits

updated Jul 25, 2026

See the code

README

Sokoban Speedrun

Fastest recipes to RL models to solve Sokoban to a held-out target on one node:

Play Sokoban if the task is unfamiliar.

LLM Track

World record history

LLM track world records — held-out score (lower 95% CI) vs wall-clock time to target

LLM track recent record training curves

#Record time (mm:ss)DescriptionDateLogscoreContributors
148:53GRPO, LR 1.6e-6 annealed, 75 steps2026-06-29llm/records/2026-06-29_010.834@JeanKaddour
236:53steps + LR-decay horizon 75 → 602026-06-29llm/records/2026-06-29_020.807@dexhunter
335:29earlier stop: 54 steps2026-07-02llm/records/2026-07-02_010.829@dexhunter
433:40Weco advantage shaping, 52 steps2026-07-02llm/records/2026-07-02_020.835@dexhunter
526:27rollout budget 5632 → 4800 tokens, 48 steps2026-07-02llm/records/2026-07-02_030.815@lorenzflow
625:51GRPO → CISPO, same 48-step recipe2026-07-14llm/records/2026-07-14_010.804@lorenzflow
719:20earlier stop: 35 CISPO steps2026-07-15llm/records/2026-07-15_010.824@lorenzflow

Rules

Fastest wall-clock run wins: one run on one 8xH100 node, from training step 1 through the final training update.

  • Score: the lower 95% bootstrap CI of pass@1 on llm/datasets/sokoban_eval.jsonl — a record must score > 0.80.
  • Eval: 8 completions/puzzle, 12,288 tokens, temperature 0.8, top-p 0.95, seed 12345.
  • Fixed: model, train set, eval set, reward function, hardware.
  • Open: RL algorithm, loss, schedules, engine, parallelism, domain-agnostic rewards, prompt.
  • Not allowed: Sokoban-specific hints, heuristics, or few-shot examples.
  • Verification: Rerun with a second seed; both runs must score above the target. The score column reports the worse of the two runs.

Running

cd llm
uv sync
NODE_GPUS=8 uv run torchrun --standalone --nproc_per_node=3 -m speedrun
uv run python -m eval_speedrun --eval-checkpoint outputs/<run>/step_000051

Non-LLM Track

This track uses PufferLib's Boxoban environment; the initial PPO implementation was forked from pufferlib/torch_pufferl.py.

World record history

Non-LLM track world records — held-out score (lower 95% CI) vs wall-clock time to target

Non-LLM track recent record training curves

#Record time (mm:ss)DescriptionDateLogscoreContributors
122:24cnn-mingru h2562026-06-21non_llm/records/2026-06-21_010.718@JeanKaddour
221:00same recipe as #1, earliest clearing checkpoint2026-06-29non_llm/records/2026-06-29_010.701@JeanKaddour
315:55torch.compile + steps-matched-anneal2026-06-30non_llm/records/2026-06-30_010.706@JeanKaddour
414:42anneal horizon tuned 1300→1200 steps2026-07-02non_llm/records/2026-07-02_010.709@JeanKaddour
512:38conv-free shift + pooled-global encoder (sgpm2), 950-step anneal2026-07-02non_llm/records/2026-07-02_020.715@srijanpatel

Rules

Fastest wall-clock run wins: one run on a single H100, from training step 1 through the final training update.

  • Score: the lower 95% CI of the held-out solve rate — a record must score > 0.70.
  • Eval: official DeepMind Boxoban test split unfiltered/test.
  • Open: policy architecture, RL algorithm, optimizer, schedules, implementation.
  • Verification: Rerun with a second seed; both runs must score above the target. The score column reports the worse of the two runs.

Running

cd non_llm
uv sync
uv run python speedrun.py

Submitting a record

Each track's assemble_record.sh (llm/, non_llm/) turns a finished run into a record dir: it collects the log, eval JSON, and source snapshot, builds the report, pins the top-level speedrun.py, runs verify_record.py, and adds or refreshes the record's row + redraws the leaderboard and rolling recent-training figures. Configure record runs by editing RECIPE in speedrun.py and launch them flag-free — the pinned speedrun.py then is the recipe (assembly rejects flag-configured runs). It reads a local outputs/<RUN>/ by default; pass SOURCE=modal to pull off the volume.

  1. Train + eval with your track's Running commands.

  2. Assemble the record:

    cd llm        # or: cd non_llm
    RUN=<RUN> DEST=records/<date>_01_<name> ./assemble_record.sh
    

    The record's README.md is scaffolded with a placeholder ## Idea section. Review the pinned speedrun.py diff, then fill in by hand: the record's ## Idea, and the new leaderboard row's Description + Contributors in this top-level README.md.

  3. Open a PR with the record dir + new row.

Optional: verify it yourself with a second seed (otherwise the maintainers do; either way both seeds must clear the target), assembled into the record's verification/ subdir:

RUN=<VRUN> VERIFY_OF=records/<date>_01_<name> ./assemble_record.sh

The top-level speedrun.py files always hold the current record's recipe.

Credits

@joshua-a-harris's nanoRL speedrun, nanochat, modded-nanoGPT, ScaleRL, ReasoningGym for the LLM-track Sokoban env, DeepMind for Boxoban and PufferLib for the efficient boxoban implementation.

Contributors

JeanKaddour

185 commits

lorenzflow

3 commits

dexhunter

2 commits

JeanKaddour/sokoban_speedrun

RL models to play Sokoban. The fastest recipe wins.

Python

31

190 commits

updated Jul 25, 2026

See the code

README

Sokoban Speedrun

Fastest recipes to RL models to solve Sokoban to a held-out target on one node:

Play Sokoban if the task is unfamiliar.

LLM Track

World record history

LLM track world records — held-out score (lower 95% CI) vs wall-clock time to target

LLM track recent record training curves

#Record time (mm:ss)DescriptionDateLogscoreContributors
148:53GRPO, LR 1.6e-6 annealed, 75 steps2026-06-29llm/records/2026-06-29_010.834@JeanKaddour
236:53steps + LR-decay horizon 75 → 602026-06-29llm/records/2026-06-29_020.807@dexhunter
335:29earlier stop: 54 steps2026-07-02llm/records/2026-07-02_010.829@dexhunter
433:40Weco advantage shaping, 52 steps2026-07-02llm/records/2026-07-02_020.835@dexhunter
526:27rollout budget 5632 → 4800 tokens, 48 steps2026-07-02llm/records/2026-07-02_030.815@lorenzflow
625:51GRPO → CISPO, same 48-step recipe2026-07-14llm/records/2026-07-14_010.804@lorenzflow
719:20earlier stop: 35 CISPO steps2026-07-15llm/records/2026-07-15_010.824@lorenzflow

Rules

Fastest wall-clock run wins: one run on one 8xH100 node, from training step 1 through the final training update.

  • Score: the lower 95% bootstrap CI of pass@1 on llm/datasets/sokoban_eval.jsonl — a record must score > 0.80.
  • Eval: 8 completions/puzzle, 12,288 tokens, temperature 0.8, top-p 0.95, seed 12345.
  • Fixed: model, train set, eval set, reward function, hardware.
  • Open: RL algorithm, loss, schedules, engine, parallelism, domain-agnostic rewards, prompt.
  • Not allowed: Sokoban-specific hints, heuristics, or few-shot examples.
  • Verification: Rerun with a second seed; both runs must score above the target. The score column reports the worse of the two runs.

Running

cd llm
uv sync
NODE_GPUS=8 uv run torchrun --standalone --nproc_per_node=3 -m speedrun
uv run python -m eval_speedrun --eval-checkpoint outputs/<run>/step_000051

Non-LLM Track

This track uses PufferLib's Boxoban environment; the initial PPO implementation was forked from pufferlib/torch_pufferl.py.

World record history

Non-LLM track world records — held-out score (lower 95% CI) vs wall-clock time to target

Non-LLM track recent record training curves

#Record time (mm:ss)DescriptionDateLogscoreContributors
122:24cnn-mingru h2562026-06-21non_llm/records/2026-06-21_010.718@JeanKaddour
221:00same recipe as #1, earliest clearing checkpoint2026-06-29non_llm/records/2026-06-29_010.701@JeanKaddour
315:55torch.compile + steps-matched-anneal2026-06-30non_llm/records/2026-06-30_010.706@JeanKaddour
414:42anneal horizon tuned 1300→1200 steps2026-07-02non_llm/records/2026-07-02_010.709@JeanKaddour
512:38conv-free shift + pooled-global encoder (sgpm2), 950-step anneal2026-07-02non_llm/records/2026-07-02_020.715@srijanpatel

Rules

Fastest wall-clock run wins: one run on a single H100, from training step 1 through the final training update.

  • Score: the lower 95% CI of the held-out solve rate — a record must score > 0.70.
  • Eval: official DeepMind Boxoban test split unfiltered/test.
  • Open: policy architecture, RL algorithm, optimizer, schedules, implementation.
  • Verification: Rerun with a second seed; both runs must score above the target. The score column reports the worse of the two runs.

Running

cd non_llm
uv sync
uv run python speedrun.py

Submitting a record

Each track's assemble_record.sh (llm/, non_llm/) turns a finished run into a record dir: it collects the log, eval JSON, and source snapshot, builds the report, pins the top-level speedrun.py, runs verify_record.py, and adds or refreshes the record's row + redraws the leaderboard and rolling recent-training figures. Configure record runs by editing RECIPE in speedrun.py and launch them flag-free — the pinned speedrun.py then is the recipe (assembly rejects flag-configured runs). It reads a local outputs/<RUN>/ by default; pass SOURCE=modal to pull off the volume.

  1. Train + eval with your track's Running commands.

  2. Assemble the record:

    cd llm        # or: cd non_llm
    RUN=<RUN> DEST=records/<date>_01_<name> ./assemble_record.sh
    

    The record's README.md is scaffolded with a placeholder ## Idea section. Review the pinned speedrun.py diff, then fill in by hand: the record's ## Idea, and the new leaderboard row's Description + Contributors in this top-level README.md.

  3. Open a PR with the record dir + new row.

Optional: verify it yourself with a second seed (otherwise the maintainers do; either way both seeds must clear the target), assembled into the record's verification/ subdir:

RUN=<VRUN> VERIFY_OF=records/<date>_01_<name> ./assemble_record.sh

The top-level speedrun.py files always hold the current record's recipe.

Credits

@joshua-a-harris's nanoRL speedrun, nanochat, modded-nanoGPT, ScaleRL, ReasoningGym for the LLM-track Sokoban env, DeepMind for Boxoban and PufferLib for the efficient boxoban implementation.

Contributors

JeanKaddour

185 commits

lorenzflow

3 commits

dexhunter

2 commits

Languages

Python

99.4%