Step-by-step practice for learning DSPy by playing Factorio through the Factorio Learning Environment (FLE).
You write (or optimize) small Python programs that act in the game — Predict, GEPA, RLM, Flex — and see the factory respond. The game is the gym; DSPy is what you’re learning.
FLE / Factorio ←── programs / tools ── DSPy modules
obs text ──────────────────────► (Predict → GEPA → RLM → Flex)
| Step | What you practice | Entry |
|---|---|---|
| 1 | Connect + one FLE program | HELLO_WORLD.md · examples/01_… |
| 2 | Scripted multi-step play | examples/03_scripted_miner.py |
| 3 | DSPy Predict agent loop |
examples/04_dspy_agent_loop.py |
| 4 | Optimize instructions (GEPA) | GEPA_STARTER.md · 07/08 |
| 5 | REPL agent (dspy.RLM) |
RLM_STARTER.md · 11 |
| 6 | Structure search (dspy.Flex) |
FLEX_STARTER.md · 12/13a/13b |
Same early milestone across advanced paths: place and fuel one burner mining drill.
# 1) deps
uv sync
# 2) API keys
cp .env.example .env
# put OPENAI_API_KEY=... in .env
# 3) Factorio cluster (Docker required)
uv run fle cluster start -n 1
# wait ~30–90s on Apple Silicon for RCON to come up
# 4) Hello World
uv run python examples/01_hello_world.py| Doc | What it covers |
|---|---|
| docs/SETUP.md | Install, cluster, env vars, Apple Silicon notes |
| docs/HELLO_WORLD.md | First working program end-to-end |
| docs/VISUALIZATION.md | PNG map dumps (no client) + optional live Factorio client |
| docs/SCENARIOS.md | Building scripted + LLM scenarios |
| docs/AI_OPTIMIZATION.md | DSPy runtime vs optimization tracks |
| docs/GEPA_STARTER.md | Minimal GEPA optimize → load flow |
| docs/RLM_STARTER.md | dspy.RLM REPL agent → place a fueled drill |
| docs/FLEX_STARTER.md | dspy.Flex intro → train from play → run |
| docs/TROUBLESHOOTING.md | Docker / RCON / eval pitfalls we hit |
FLE reference (0.3.x docs — partly outdated vs installed 0.4.x):
| Script | Purpose |
|---|---|
examples/01_hello_world.py |
Connect + nearest(Resource.IronOre) |
examples/02_list_environments.py |
List FLE task IDs |
examples/03_scripted_miner.py |
Deterministic multi-step scenario |
examples/09_visualize_renders.py |
Save map PNGs after each action |
examples/10_live_client_watch.py |
Join Factorio client + slow watchable scenario |
examples/04_dspy_agent_loop.py |
Intro DSPy agent loop (--renders for map PNGs) |
examples/05_optimize_agent.py |
Offline BootstrapFewShot train |
examples/06_run_inspect_eval.py |
Thin wrapper for fle inspect-eval |
examples/07_gepa_train.py |
Offline GEPA train → save module |
examples/08_gepa_run.py |
Run a GEPA-compiled module in Factorio |
examples/11_dspy_rlm_miner.py |
dspy.RLM + run_factorio tool (RLM_STARTER.md) |
examples/12_dspy_flex_miner.py |
Flex intro (baseline), same drill goal (FLEX_STARTER.md) |
examples/13a_dspy_flex_train.py |
Online play → demos → Flex+GEPA compile |
examples/13b_dspy_flex_run.py |
Load learned Flex → Factorio rollout |
fle evalis removed → usefle inspect-eval- Always pass
--model ...(omitting it can crash) - With one Factorio container use
--epochs 1(default Pass@8 needs 8 instances) gym.make(env_id)needsrun_idx=0— preferdspy_factorio.env.make_env- Pin
a2a-sdk>=0.3.26,<1(1.x breaks imports) - FLE still uses OpenAI
gym(helpers silence deprecation noise; do not blindly switch to Gymnasium) - LLM agents must emit
Resource.*/Prototype.*enums andmove_tobefore distant placements
uv run fle inspect-eval \
--env-id iron_ore_throughput \
--model openai/gpt-4o-mini \
--limit 1 --epochs 1 \
--trajectory-length 64 \
--max-connections 1dspy_factorio/ # env + agent + offline trainset
examples/ # numbered DSPy / FLE practice scripts
docs/ # setup + step-by-step tutorials
.env # secrets (gitignored)