Repository navigation
Train a Wordle agent: SFT, then GRPO - #1479
sergiopaniego wants to merge 13 commits into
Conversation
There was a problem hiding this comment.
Alignment Review Report
Automated Checks
- Lint: PASS —
usort check src/ tests/andruff check src/ tests/are clean;ruff format --check src/ tests/ envs/flags 47 pre-existing files, none touched by this diff (this PR only changesdocs/,envs/textarena_env/README.md, andexamples/wordle/). Runningruff check/ruff format --checkdirectly against the newexamples/wordle/*.pyfiles (outside the hook's scope) is also clean. - Debug code: CLEAN —
check-debug.shonly scanssrc/, which this PR doesn't touch. Noprint/breakpoint/pdb debug code in the newexamples/wordle/*.pyfiles beyond intentional CLI/progress output, and no TODO/FIXME added.
Open RFCs Context
- RFC 005 (Agentic Harness Integration) and RFC 006 (Agentic RL through Harness Interception) are both In Review but cover installed-CLI-agent harnesses (OpenClaw, Claude Code, opencode, Pi) and token-capture proxies — not relevant here, since this tutorial uses the standard TextArena HTTP/MCP client wired into TRL's
environment_factory, the same pattern already used byrl-training-2048andend_to_end_walkthrough. - RFC 002 (Env Spec, In Review) is the RFC behind the "rewards inside environment" principle — see the alignment flag below.
- No other Draft/In Review RFC (000, 001, 003, 004, 008, 010, 011, 012) touches docs or training-example conventions in a way this PR conflicts with.
Tier 1: Fixes Required
-
examples/wordle/generate_sft_data.py:4,examples/wordle/grpo.py:6,examples/wordle/evaluate.py:6,examples/wordle/wordle.ipynb:21,docs/source/tutorials/wordle-grpo.md:40— the pip-installable dependency URL still readsgit+https://github.com/huggingface/OpenEnv.git@v0.10.0#subdirectory=envs/textarena_env, while this same PR'sd5f95805commit ("point its links at openenv/OpenEnv") updated the surrounding prose links (Colab badges, GitHub source tree,raw.githubusercontent.comURLs in the notebook) toopenenv/OpenEnv. Worth a pass to make these consistent with the new canonical org, matching this PR's own stated goal — GitHub's repo-rename redirect means installs won't break, but it reintroduces the exact link the commit set out to replace.
Tier 2: Alignment Discussion
Principle Conflicts
ALIGNMENT FLAG: Reward shaping defined in the training script, not the environment
- Principle/RFC at stake: "Rewards inside environment" (
PRINCIPLES.md, backed by RFC 002) — "Domain knowledge encapsulated in env, not external";INVARIANTS.mdadds that external reward augmentation should go through the server-side Transform pipeline. - The concern:
examples/wordle/grpo.pydefinesreward_win,reward_partial, andreward_invalidas plain Python functions passed toGRPOTrainer(reward_funcs=...), readingenv.num_guesses,env.won,env.best_greens,env.invalid_movesoff the client-sideWordleEnvwrapper rather than through a server-side Transform. This is consistent with three other existing examples (browsergym_trl_hf_sandbox.py,pelican_svg_grpo.py,sophistry_bench_sprint_grpo.py), so it's a pre-existing pattern this PR follows rather than originates — but it's still worth a human check on whetherenvironment_factory+ client-sidereward_funcsis meant to be the sanctioned exception to this invariant, or whether the invariant/examples need reconciling. - Suggested reviewer: @Darktex (author of the "Rewards inside environment" row in
PRINCIPLES.mdand RFC 002 co-author)
RFC Conflicts
None identified.
Summary
- 1 mechanical issue to fix (stale
huggingface/OpenEnvinstall URLs left behind by this PR's own link-update commit, 5 occurrences) - 1 alignment point for human review (client-side reward shaping vs. "rewards inside environment")
- 0 RFC conflicts to discuss
Sent by Cursor Automation: Pre-review
| PROMPT = """You are an expert Wordle solver with deep knowledge of English vocabulary, letter frequency patterns, and optimal guessing strategies. | ||
|
|
||
| Follow these rules to play Wordle: | ||
|
|
There was a problem hiding this comment.
ALIGNMENT FLAG: reward_win/reward_partial/reward_invalid live in this training script and read fields off the client-side WordleEnv wrapper, rather than the environment emitting a single domain-aware reward. That's a tension with "Rewards inside environment" in PRINCIPLES.md (RFC 002) and the Transform-pipeline guidance in INVARIANTS.md. It matches existing precedent (browsergym_trl_hf_sandbox.py, pelican_svg_grpo.py, sophistry_bench_sprint_grpo.py), so likely fine as a sanctioned environment_factory pattern — flagging for @Darktex to confirm rather than as a blocker.
There was a problem hiding this comment.
The environment keeps its own reward (1.0 for a win, a letter score for a loss), and the tutorial documents it. These three functions are a training choice for this recipe. With the raw reward, a policy with thinking on learned to think less and use all six guesses, so the script pays more for faster wins and adds partial credit. Moving this into a server-side Transform would change what the shared openenv/wordle Space returns for everyone using it, so it stays in the script, like the other environment_factory examples. Happy to change it if @Darktex prefers a Transform.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 72be56c. Configure here.



The Wordle tutorial trained Qwen3-1.7B with GRPO from the base model and the environment's raw reward. That recipe barely learns. The base model almost never wins, and the raw reward pays a win the same at any speed, so a policy with thinking on learns to think less and use all six guesses. This rewrites the tutorial around a recipe that works, and adds its scripts.
examples/wordle/: the whole pipeline, each script self-contained and pinned (trl==1.16.0,openenv==0.10.0):generate_sft_data.py: a solver plays 1,000 games against the environment (in-process) and writes them as tool-calling conversations, in the format TRL renders during GRPO.sft.py: SFT warmup on those games.grpo.py: GRPO from the SFT model, with a reward split in three terms (a win that pays more the faster it comes, partial credit from the best guess, a penalty for invalid moves).evaluate.pyandmake_gif.py: play models on fixed words and render a side-by-side GIF.wordle.ipynb: the same pipeline for Colab. On a T4 it launches SFT and GRPO on Hugging Face Jobs and compares the published models.docs/source/tutorials/wordle-grpo.md: rewritten as "Train a Wordle Agent", with the results first, the hardware, time and cost of every step, and why the SFT warmup is needed. The tutorials index and the sidebar point to it and to the new notebook.envs/textarena_env/README.md: links the tutorial (sync_env_docs.py --fixrefreshes its docs page).Results on the same 30 words, played greedily: Qwen3-1.7B wins 0, the SFT model 10 and the SFT + GRPO model 19. The models and the dataset are in the
openenvorg (Qwen3-1.7B-Wordle-SFT,Qwen3-1.7B-Wordle-SFT-GRPO,wordle-tool-calls-sft), and the Wordle Arena Space replays their games. The full run costs about $6 on one A100.The
openenv/wordleSpace was redeployed from v0.10.0, so it reports how a game ended (#1455), and allows 64 concurrent sessions.This PR was prepared with AI assistance.
Note
Low Risk
Documentation and example/training scripts only; no production API or auth changes. Training scripts push to the Hub and call remote Spaces when users run them.
Overview
Replaces the old Play Wordle with GRPO tutorial (base-model GRPO via an external TRL notebook) with Train a Wordle Agent, centered on an SFT warmup followed by GRPO on Qwen3-1.7B against the OpenEnv TextArena Wordle Space.
Adds
examples/wordle/as a pinned, end-to-end recipe: solver-driven SFT data generation,sft.py,grpo.pywith split rewards (fast wins, partial greens, invalid-move penalties),evaluate.pywith fixed secrets and a six-legal-guess budget,make_gif.py,secrets30.txt, and a Colabwordle.ipynb. Docs (sidebar, tutorials index,wordle-grpo.md, TextArena README) are retitled and relinked to the new notebook and scripts.Adds lightweight tests for the evaluator guess budget, notebook input validation, and GIF rendering. No changes to core environment server code in this diff—mostly documentation, examples, and tests.
Reviewed by Cursor Bugbot for commit 18b7afc. Bugbot is set up for automated code reviews on this repo. Configure here.