<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://linzwcs.github.io/EvoPolicyGym/blog/</id>
    <title>EvoPolicyGym Blog</title>
    <updated>2026-08-11T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://linzwcs.github.io/EvoPolicyGym/blog/"/>
    <subtitle>EvoPolicyGym Blog</subtitle>
    <icon>https://linzwcs.github.io/EvoPolicyGym/favicon.svg</icon>
    <rights>Copyright © 2026 EvoPolicyGym contributors</rights>
    <entry>
        <title type="html"><![CDATA[Perception or Planning? Policy Evolution in Crafter]]></title>
        <id>https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/</id>
        <link href="https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/"/>
        <updated>2026-08-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A paired RGB and local-symbolic experiment reveals different perception and long-horizon control bottlenecks in Crafter Policy evolution.]]></summary>
        <content type="html"><![CDATA[<p>Crafter is an open-world survival game where an agent must stay alive while
exploring, gathering resources, fighting enemies, and progressing through a
crafting technology tree. Unlike environments with a short and well-defined
objective, success in Crafter requires many decisions to remain coordinated
over hundreds of steps.</p>
<p>For a coding Agent evolving a Policy, this creates two intertwined challenges:</p>
<ol>
<li class=""><strong>Perception:</strong> recover nearby terrain, entities, inventory, and player
status from the observation.</li>
<li class=""><strong>Long-horizon control:</strong> turn that state into a coherent strategy for
survival, exploration, combat, and development.</li>
</ol>
<p>In this experiment, we separate these two sources of difficulty. We evaluate
GPT-5.6 Sol, Terra, and Luna under the same Crafter task, but give their evolved
Policies either the original RGB observation or a local symbolic representation
of the same visible state.</p>
<p>The difference is substantial for <strong>Sol and Terra</strong>, but much smaller for
<strong>Luna</strong>. Removing most visual recognition work therefore exposes different
bottlenecks in the Policies evolved by the three coding Agents.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="crafter-as-a-policy-evolution-environment">Crafter as a Policy-Evolution Environment<a href="https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/#crafter-as-a-policy-evolution-environment" class="hash-link" aria-label="Direct link to Crafter as a Policy-Evolution Environment" title="Direct link to Crafter as a Policy-Evolution Environment" translate="no">​</a></h2>
<p>Crafter procedurally generates a fresh world for every Episode. The player
begins without tools or resources and must balance immediate survival with
longer-term development.</p>
<p>A capable Policy needs to coordinate several behaviors:</p>
<ul>
<li class="">maintain food, drink, and health;</li>
<li class="">explore an initially unknown world;</li>
<li class="">collect increasingly advanced resources;</li>
<li class="">craft and place tools and structures;</li>
<li class="">avoid or fight hostile creatures;</li>
<li class="">retain enough local information to revisit useful areas.</li>
</ul>
<p>These objectives compete with one another. Exploration creates opportunities
for development but also exposes the player to danger. Crafting requires
resources that may be far from safety. A Policy that focuses only on immediate
survival can stagnate, while aggressive progression can quickly collapse if
basic needs are neglected.</p>
<p>Crafter therefore tests whether a coding Agent can evolve a <strong>coordinated
long-horizon program</strong>, rather than merely discover a locally useful action
rule.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="rgb-vs-local-symbolic-observations">RGB vs. Local Symbolic Observations<a href="https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/#rgb-vs-local-symbolic-observations" class="hash-link" aria-label="Direct link to RGB vs. Local Symbolic Observations" title="Direct link to RGB vs. Local Symbolic Observations" translate="no">​</a></h2>
<p>The two conditions use the same simulator, procedural worlds, action space,
reward metric, Episode pools, and evaluation setup. Only the observation
exposed to the Policy changes.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="rgb">RGB<a href="https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/#rgb" class="hash-link" aria-label="Direct link to RGB" title="Direct link to RGB" translate="no">​</a></h3>
<p>The RGB Policy receives the rendered <code>64 × 64 × 3</code> Crafter frame.</p>
<p>It must infer:</p>
<ul>
<li class="">terrain from colors and textures;</li>
<li class="">creatures and objects from sprites;</li>
<li class="">inventory and vitals from the HUD;</li>
<li class="">player position and orientation from rendering;</li>
<li class="">useful state under changing illumination, including nighttime.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="local-symbolic">Local symbolic<a href="https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/#local-symbolic" class="hash-link" aria-label="Direct link to Local symbolic" title="Direct link to Local symbolic" translate="no">​</a></h3>
<p>The symbolic Policy instead receives structured information for the <strong>same
local region</strong>:</p>
<ul>
<li class="">local terrain and entity IDs;</li>
<li class="">health, food, drink, energy, resources, and tools;</li>
<li class="">facing direction, sleeping state, and daylight.</li>
</ul>
<p>This representation removes most object recognition, HUD reading, and
nighttime visual ambiguity.</p>
<p>However, it does <strong>not</strong> expose privileged global state. The Policy still
receives no global semantic map, absolute position, Environment seed, hidden
creature state, or other information outside the local observation.</p>
<p>It must still explore, remember useful locations, handle collisions, sequence
resources, time interactions, fight enemies, and coordinate survival with
development.</p>
<p>The paired experiment therefore simplifies <strong>state recognition</strong> while
preserving most of the <strong>long-horizon decision-making problem</strong>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="long-horizon-survival-score">Long-Horizon Survival Score<a href="https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/#long-horizon-survival-score" class="hash-link" aria-label="Direct link to Long-Horizon Survival Score" title="Direct link to Long-Horizon Survival Score" translate="no">​</a></h2>
<p>Crafter's canonical score is primarily achievement-oriented. For our
policy-evolution setting, we additionally want to distinguish a Policy that
occasionally reaches advanced achievements from one that can survive reliably
while continuing to make progress.</p>
<p>We therefore use the <strong>Long-Horizon Survival Score (LHS Score)</strong> as the primary
Benchmark metric.</p>
<p>At each step, its survival component contains two signals:</p>
<ul>
<li class="">an <strong>alive reward</strong> for remaining alive;</li>
<li class="">a <strong>vital-quality reward</strong> determined by the weakest of health, food, and
drink.</li>
</ul>
<p>Using the weakest vital is intentional: high food and health should not
compensate for a Policy that is about to die from thirst.</p>
<p>LHS also retains bounded secondary incentives for useful development:</p>
<ul>
<li class="">the first unlock of a new achievement;</li>
<li class="">actual restoration of food or drink;</li>
<li class="">productive repeated behaviors such as resource collection, combat, and
planting.</li>
</ul>
<p>Repeated actions are capped within rolling windows, preventing a simple farming
or maintenance loop from dominating the score.</p>
<p>Across Episodes, LHS further emphasizes robustness. The aggregate score
combines:</p>
<ul>
<li class="">average healthy-survival return;</li>
<li class="">additional weight on the <strong>weakest quarter of Episodes</strong>;</li>
<li class="">bounded development and maintenance return.</li>
</ul>
<p>Conceptually,</p>
<p><code>LHS = average survival + lower-tail robustness + bounded progression</code></p>
<p>rather than rewarding only the best trajectories.</p>
<p>This makes short achievement-rich Episodes insufficient to compensate for a
fragile survival Policy, while still encouraging the Agent to progress beyond
passive survival.</p>
<p>The canonical Crafter score is reported separately as a diagnostic of
technology-tree progression.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="experiment">Experiment<a href="https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/#experiment" class="hash-link" aria-label="Direct link to Experiment" title="Direct link to Experiment" translate="no">​</a></h2>
<p>We evaluate GPT-5.6 <strong>Sol</strong>, <strong>Terra</strong>, and <strong>Luna</strong>.</p>
<p>For each coding Agent, we run one policy-evolution trajectory with RGB
observations and one with local symbolic observations. All six Runs use the
same long-horizon survival objective.</p>
<p>The evolved candidate selected at the end of each Run is evaluated on <strong>64
held-out Episodes</strong>.</p>
<p>In addition to LHS, we report:</p>
<ul>
<li class="">mean and maximum effective survival;</li>
<li class="">the fraction of Episodes surviving at least 300 steps;</li>
<li class="">canonical Crafter score;</li>
<li class="">achievement coverage.</li>
</ul>
<p>These diagnostics allow us to distinguish average robustness, exceptionally
long trajectories, and technology progression.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="results">Results<a href="https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/#results" class="hash-link" aria-label="Direct link to Results" title="Direct link to Results" translate="no">​</a></h2>
<p>The effect of simplifying perception differs sharply across the three Agents.</p>
<table><thead><tr><th>Agent</th><th style="text-align:right">LHS Score</th><th style="text-align:right">Mean Survival</th><th style="text-align:right">Max Survival</th><th style="text-align:right">Survive ≥300</th><th style="text-align:right">Crafter C</th><th style="text-align:right">Coverage</th></tr></thead><tbody><tr><td><strong>Sol</strong></td><td style="text-align:right">5.70 → <strong>11.53</strong></td><td style="text-align:right">195 → <strong>316</strong></td><td style="text-align:right">401 → <strong>1043</strong></td><td style="text-align:right">3.1% → <strong>39.1%</strong></td><td style="text-align:right">3.91 → <strong>19.47</strong></td><td style="text-align:right">10 → <strong>18/22</strong></td></tr><tr><td><strong>Terra</strong></td><td style="text-align:right">4.58 → <strong>9.88</strong></td><td style="text-align:right">164 → <strong>291</strong></td><td style="text-align:right">288 → <strong>871</strong></td><td style="text-align:right">0.0% → <strong>31.2%</strong></td><td style="text-align:right">1.12 → <strong>11.31</strong></td><td style="text-align:right">5 → <strong>14/22</strong></td></tr><tr><td><strong>Luna</strong></td><td style="text-align:right">4.58 → <strong>4.97</strong></td><td style="text-align:right">164 → <strong>178</strong></td><td style="text-align:right">288 → <strong>401</strong></td><td style="text-align:right">0.0% → <strong>3.1%</strong></td><td style="text-align:right">1.12 → <strong>3.44</strong></td><td style="text-align:right">5 → <strong>11/22</strong></td></tr></tbody></table>
<p><em>Each cell compares RGB → local symbolic observations.</em></p>
<p>For <strong>Sol</strong>, LHS increases from 5.70 to 11.53, while mean survival rises from
195 to 316 steps. Its longest held-out trajectory grows from 401 to <strong>1,043
steps</strong>.</p>
<p><strong>Terra</strong> shows an equally pronounced shift. LHS more than doubles, mean
survival increases by 127 steps, and its longest trajectory reaches <strong>871
steps</strong>.</p>
<p>The change for <strong>Luna</strong> is much smaller. Symbolic observations increase
achievement coverage substantially, from 5 to 11 achievements, but mean
survival rises by only 13 steps and LHS improves by only 8%.</p>
<p>The difference is especially visible in robust long-horizon survival. Under
symbolic observations, <strong>39.1%</strong> of Sol Episodes and <strong>31.2%</strong> of Terra
Episodes survive at least 300 steps, compared with only <strong>3.1%</strong> for Luna.</p>
<p>For Sol and Terra, simplifying perception therefore changes not only their
best-case behavior, but the broader survival distribution.</p>
<p><em>Terra's symbolic Run includes one validation protocol failure and one protocol
error during the held-out Assessment. The failed held-out Episode receives zero
under the Benchmark definition; among successfully completed Episodes, its
shortest survival is 156 steps.</em></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="one-world-six-policies">One World, Six Policies<a href="https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/#one-world-six-policies" class="hash-link" aria-label="Direct link to One World, Six Policies" title="Direct link to One World, Six Policies" translate="no">​</a></h2>
<p>Aggregate results measure robustness across procedural worlds. To make the
behavioral differences easier to inspect, we also replay the six selected
Policies in the same showcase world.</p>
<p>The earlier fixed world happened to favor Luna. We replaced it using a
deterministic, separate 128-Episode showcase pool: eligible Episodes had to
complete normally, place Sol above the shared RGB baseline, and order the
symbolic Policies as Sol &gt; Terra &gt; Luna by effective survival, with every
adjacent gap at least 50 steps. Among eligible Episodes, we selected the one
closest to the corresponding held-out mean survival values,
rather than the one with the largest gap. Because this selection uses Policy
outcomes, the replay remains a <strong>qualitative illustration</strong>, not evaluation
evidence.</p>
<p>For the symbolic conditions, each Policy still receives only its structured
local observation. The RGB GIF is a human-facing deterministic replay of that
Policy's recorded Actions in the identical world; those RGB frames are not
Policy inputs. All six GIFs share the same timeline. A Policy that ends early
holds on its terminal frame.</p>
<table><thead><tr><th>Sol</th><th>Terra</th><th>Luna</th></tr></thead><tbody><tr><td><strong>RGB · 244 steps</strong><br><img decoding="async" loading="lazy" alt="Sol RGB Policy on the shared Crafter showcase Episode" src="https://linzwcs.github.io/EvoPolicyGym/assets/images/crafter-lhs-sol-rgb-showcase-e8adea92aea6811e32f569bb232b7c1e.gif" width="260" height="290" class="img_ev3q"></td><td><strong>RGB · 162 steps</strong><br><img decoding="async" loading="lazy" alt="Terra RGB Policy on the shared Crafter showcase Episode" src="https://linzwcs.github.io/EvoPolicyGym/assets/images/crafter-lhs-terra-rgb-showcase-0954f346051270b498d9e141ba3f6745.gif" width="260" height="290" class="img_ev3q"></td><td><strong>RGB · 162 steps</strong><br><img decoding="async" loading="lazy" alt="Luna RGB Policy on the shared Crafter showcase Episode" src="https://linzwcs.github.io/EvoPolicyGym/assets/images/crafter-lhs-luna-rgb-showcase-fd68a4791e85813e8c8df544cc483bb3.gif" width="260" height="290" class="img_ev3q"></td></tr><tr><td><strong>Symbolic · 391 steps</strong><br><img decoding="async" loading="lazy" alt="Sol local-symbolic Policy on the shared Crafter showcase Episode" src="https://linzwcs.github.io/EvoPolicyGym/assets/images/crafter-lhs-sol-symbolic-showcase-50dca0304bccee927ddfbdd43858b515.gif" width="260" height="290" class="img_ev3q"></td><td><strong>Symbolic · 261 steps</strong><br><img decoding="async" loading="lazy" alt="Terra local-symbolic Policy on the shared Crafter showcase Episode" src="https://linzwcs.github.io/EvoPolicyGym/assets/images/crafter-lhs-terra-symbolic-showcase-5a4c375be1bc899f4e442f185b6905b5.gif" width="260" height="290" class="img_ev3q"></td><td><strong>Symbolic · 194 steps</strong><br><img decoding="async" loading="lazy" alt="Luna local-symbolic Policy on the shared Crafter showcase Episode" src="https://linzwcs.github.io/EvoPolicyGym/assets/images/crafter-lhs-luna-symbolic-showcase-65bcd4ebc957d559cc9f298afbd54a64.gif" width="260" height="290" class="img_ev3q"></td></tr></tbody></table>
<p>The symbolic row now reflects the aggregate ordering clearly: Sol continues
longest, Terra occupies the middle, and Luna ends much earlier. Terra RGB and
Luna RGB cannot be separated on a common Episode because both Runs selected
the byte-identical packaged baseline; their matching replays and 162-step
outcomes are intentional.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="three-agents-different-bottlenecks">Three Agents, Different Bottlenecks<a href="https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/#three-agents-different-bottlenecks" class="hash-link" aria-label="Direct link to Three Agents, Different Bottlenecks" title="Direct link to Three Agents, Different Bottlenecks" translate="no">​</a></h2>
<p>The paired results expose a different limiting factor for each Agent.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="sol-strong-rgb-progress-then-another-large-gain">Sol: strong RGB progress, then another large gain<a href="https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/#sol-strong-rgb-progress-then-another-large-gain" class="hash-link" aria-label="Direct link to Sol: strong RGB progress, then another large gain" title="Direct link to Sol: strong RGB progress, then another large gain" translate="no">​</a></h3>
<p>Sol already beats the packaged baseline with RGB, then improves again with
symbolic input: LHS rises from <strong>5.70 to 11.53</strong>, mean survival from <strong>195 to
316</strong> steps, and coverage from <strong>10/22 to 18/22</strong>. It can jointly improve
perception and control, but more reliable state recognition still unlocks a
large gain.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="terra-perception-was-a-major-bottleneck">Terra: perception was a major bottleneck<a href="https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/#terra-perception-was-a-major-bottleneck" class="hash-link" aria-label="Direct link to Terra: perception was a major bottleneck" title="Direct link to Terra: perception was a major bottleneck" translate="no">​</a></h3>
<p>Terra's RGB Run falls back to the unmodified baseline, while symbolic input
raises LHS from <strong>4.58 to 9.88</strong>, mean survival from <strong>164 to 291</strong> steps, and
coverage from <strong>5/22 to 14/22</strong>. Visual state extraction was therefore its
dominant bottleneck in this Run.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="luna-better-recognition-does-not-solve-coordination">Luna: better recognition does not solve coordination<a href="https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/#luna-better-recognition-does-not-solve-coordination" class="hash-link" aria-label="Direct link to Luna: better recognition does not solve coordination" title="Direct link to Luna: better recognition does not solve coordination" translate="no">​</a></h3>
<p>Luna also falls back to the baseline under RGB. Symbolic input expands coverage
from <strong>5/22 to 11/22</strong>, but LHS only moves from <strong>4.58 to 4.97</strong> and mean
survival from <strong>164 to 178</strong> steps. Its remaining bottleneck is long-horizon
coordination rather than recognition alone.</p>
<p><strong>Changing the observation contract affects their policy evolution in
fundamentally different ways.</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-does-the-ablation-tell-us">What Does the Ablation Tell Us?<a href="https://linzwcs.github.io/EvoPolicyGym/blog/crafter-policy-evolution/#what-does-the-ablation-tell-us" class="hash-link" aria-label="Direct link to What Does the Ablation Tell Us?" title="Direct link to What Does the Ablation Tell Us?" translate="no">​</a></h2>
<p>At first glance, Crafter poses a single challenge: evolve a Policy that can
survive and develop in an open world.</p>
<p>The paired experiment shows that the difficulty can originate at different
stages.</p>
<p>For <strong>Sol and Terra</strong>, local visual state extraction is a major part of the
challenge. Removing object recognition, HUD reading, and nighttime visual
ambiguity leads to much stronger survival and technology progression.</p>
<p>For <strong>Luna</strong>, perception is only part of the problem. Cleaner state information
enables broader development, but the resulting Policy still struggles to turn
those capabilities into reliable long-horizon survival.</p>
<p>This is the distinction we want environments such as Crafter to expose.</p>
<p>A final scalar score tells us which Program performs better. Controlled
changes to the observation interface can additionally reveal <strong>where policy
evolution stops improving</strong>.</p>
<p>Crafter therefore evaluates more than whether a coding Agent can write a
game-playing Policy. It gives us a way to separate failures of perception from
failures of long-horizon planning, control, and program coordination.</p>
<p>These six Runs represent individual policy-evolution trajectories rather than
repeated statistical trials, and their training Episode consumption is not
identical. We therefore do not interpret them as a general ranking of Sol,
Terra, and Luna.</p>
<p>The narrower observation is more informative:</p>
<blockquote>
<p><strong>Removing local visual recognition transforms the Policies evolved by Sol
and Terra, but only modestly improves Luna's survival—revealing different
bottlenecks behind long-horizon policy evolution.</strong></p>
</blockquote>]]></content>
        <author>
            <name>EvoPolicyGym contributors</name>
            <uri>https://github.com/Linzwcs/EvoPolicyGym</uri>
        </author>
        <category label="Benchmark" term="Benchmark"/>
        <category label="Crafter" term="Crafter"/>
        <category label="Experiment" term="Experiment"/>
        <category label="Policy Evolution" term="Policy Evolution"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Into the Dungeon: Building Exploration Systems for NetHack]]></title>
        <id>https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/</id>
        <link href="https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/"/>
        <updated>2026-08-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[How coding agents turned complete NetHack trajectories into executable Policies for navigation, obstacle handling, and dungeon progress.]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-nethack">What is NetHack?<a href="https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/#what-is-nethack" class="hash-link" aria-label="Direct link to What is NetHack?" title="Direct link to What is NetHack?" translate="no">​</a></h2>
<p>NetHack is a turn-based roguelike set in a procedurally generated dungeon. The
full game asks the player to descend, obtain the Amulet of Yendor, return to the
surface, and complete an ascension. Reaching that goal requires much more than
winning individual fights: the player must explore unknown layouts, interpret
messages, manage resources, remember useful locations, and survive permanent
death.</p>
<p>A simplified progression loop looks like this:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">explore a dungeon level</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">handle creatures, obstacles, and resources</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find a downward staircase</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">descend and repeat</span><br></div></code></pre></div></div>
<p>The details change in every Episode. Rooms and corridors are rearranged,
objects and creatures appear in different places, and only part of the current
level is visible. An Action that looks reasonable locally may waste hundreds
of turns, consume scarce food, or lead the character away from the route it
was trying to follow.</p>
<p>This makes NetHack a useful Environment for studying executable strategy. A
Policy must combine immediate reactions with memory and longer-term goals, and
it must recognize when the world did not respond as expected.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="bringing-nethack-into-evopolicygym">Bringing NetHack into EvoPolicyGym<a href="https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/#bringing-nethack-into-evopolicygym" class="hash-link" aria-label="Direct link to Bringing NetHack into EvoPolicyGym" title="Direct link to Bringing NetHack into EvoPolicyGym" translate="no">​</a></h2>
<p>The Benchmark integrates NLE 1.3.0 <code>NetHackScore-v0</code>, backed by NetHack 3.6.7.
The Policy receives a semantic view of the terminal map together with status
values, the current message, public inventory entries, and the current input
mode. It chooses from 23 Actions covering movement, running, stairs, waiting,
kicking, eating, searching, and message prompts.</p>
<p>The Action profile is intentionally narrower than the complete NetHack command
set. Within a 5,000-step Episode, it concentrates the experiment on early-game
exploration, obstacle handling, survival, and descent rather than full-game
ascension.</p>
<p>The score follows progress recognized by NetHack and penalizes repeated steps
that leave the character frozen in place. This gives the Agent a primary
optimization signal while dungeon depth, game score, and frozen-step rate help
explain what kind of behavior produced it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="learning-from-complete-trajectories">Learning from complete trajectories<a href="https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/#learning-from-complete-trajectories" class="hash-link" aria-label="Direct link to Learning from complete trajectories" title="Direct link to Learning from complete trajectories" translate="no">​</a></h2>
<p>Many weak NetHack Policies do not crash. They continue running while pushing
against a boulder, trying to cross iron bars, alternating between two tiles, or
standing on a staircase without descending. An aggregate score says that the
Policy performed poorly, but not where its behavior broke down.</p>
<p>For each training submission, the Environment therefore returns the complete
Policy-visible trajectory for every evaluated Episode. The Agent can inspect
positions, Actions, messages, status changes, and repeated states, then connect
those patterns back to the source code.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">submit an executable Policy</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">inspect complete training trajectories</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">identify a behavioral failure</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rewrite memory, routing, or interaction rules</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">submit a new Program</span><br></div></code></pre></div></div>
<p>The Environment supplies evidence, not a diagnosis. Deciding which Episodes
to inspect and which patterns matter remains part of the coding agent's work.
Lasting improvement is stored in the executable Program rather than in model
weights or hidden state carried between Episodes.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="experiment">Experiment<a href="https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/#experiment" class="hash-link" aria-label="Direct link to Experiment" title="Direct link to Experiment" translate="no">​</a></h2>
<p>We ran three GPT-5.6 model variants—Luna, Terra, and Sol—through Codex. Each
Agent began with the same packaged baseline and could improve it using training
scores and trajectories. The optional NetHack optimization Skill was disabled,
so the Agents had to develop their own analysis and revision process.</p>
<p>The baseline already performs simple local exploration. It remembers visit
counts, usually prefers a less-visited neighboring tile, avoids immediate
reversal when alternatives exist, searches periodically, kicks visible closed
doors, and eats recognized food when hungry. It does not build an explicit map,
plan routes to distant targets, remember failed edges, or treat descending as a
persistent objective.</p>
<table><thead><tr><th>Setting</th><th>Value</th></tr></thead><tbody><tr><td>Environment</td><td>NLE 1.3.0 · NetHack 3.6.7</td></tr><tr><td>Task</td><td><code>NetHackScore-v0</code> · 23 Actions</td></tr><tr><td>Episode limit</td><td>5,000 Policy steps</td></tr><tr><td>Training allowance</td><td>up to 128 Episodes</td></tr><tr><td>Final Assessment</td><td>256 held-out Episodes</td></tr><tr><td>Optional NetHack Skill</td><td>disabled</td></tr></tbody></table>
<p>The training allowance was a ceiling rather than forced consumption. Sol used
all 128 Episodes, Terra used 68, and Luna used 40 before finishing.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="results">Results<a href="https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/#results" class="hash-link" aria-label="Direct link to Results" title="Direct link to Results" translate="no">​</a></h2>
<p>Sol produced the strongest selected Policy in this experiment. It reached a
mean Assessment return of <code>204.026</code>, a mean game score of <code>208.230</code>, and a mean
dungeon depth of <code>2.867</code>. Its deepest held-out Episode reached depth 11.</p>
<table><thead><tr><th>Agent lane</th><th style="text-align:right">Training used</th><th style="text-align:right">Submissions</th><th style="text-align:right">Assessment return</th><th style="text-align:right">Mean game score</th><th style="text-align:right">Mean / max depth</th><th style="text-align:right">Frozen steps</th></tr></thead><tbody><tr><td><strong>GPT-5.6 Sol + Codex</strong></td><td style="text-align:right">128 / 128</td><td style="text-align:right">8</td><td style="text-align:right"><strong>204.026</strong></td><td style="text-align:right"><strong>208.230</strong></td><td style="text-align:right"><strong>2.867 / 11</strong></td><td style="text-align:right"><strong>27.53%</strong></td></tr><tr><td>GPT-5.6 Terra + Codex</td><td style="text-align:right">68 / 128</td><td style="text-align:right">4</td><td style="text-align:right">80.237</td><td style="text-align:right">87.094</td><td style="text-align:right">1.082 / 4</td><td style="text-align:right">33.77%</td></tr><tr><td>GPT-5.6 Luna + Codex</td><td style="text-align:right">40 / 128</td><td style="text-align:right">4</td><td style="text-align:right">63.773</td><td style="text-align:right">70.777</td><td style="text-align:right">1.094 / 4</td><td style="text-align:right">35.75%</td></tr></tbody></table>
<p>All three selected Policies completed the held-out Assessment without a Policy
execution failure. None ascended. The results measure early-game exploration,
survival, and dungeon progress—not complete NetHack mastery.</p>
<p><img decoding="async" loading="lazy" alt="Complete semantic replay of a NetHack training Episode from Sol&amp;#39;s selected
Policy. The replay covers all 1,269 Policy steps, reaches dungeon depth 11 and
a maximum game score of 860, and ends in death." src="https://linzwcs.github.io/EvoPolicyGym/assets/images/nle-sol-policy-training-replay-124139790b64f4be4cf266da290d550a.gif" width="900" height="570" class="img_ev3q"></p>
<p><em>Submission 000008, training Episode 16. This replay shows an Agent-written
Policy acting autonomously from the first observation to the end of the
Episode. It is a representative training trajectory, not part of the held-out
Assessment reported in the table.</em></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-baselines-capability-boundary">The baseline's capability boundary<a href="https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/#the-baselines-capability-boundary" class="hash-link" aria-label="Direct link to The baseline's capability boundary" title="Direct link to The baseline's capability boundary" translate="no">​</a></h2>
<p>The baseline can answer a useful local question:</p>
<blockquote>
<p>Which visible neighboring tile has been visited least?</p>
</blockquote>
<p>It cannot yet answer the larger navigation question:</p>
<blockquote>
<p>How should I build and maintain a route through an uncertain, multi-level
dungeon?</p>
</blockquote>
<p>That gap became the main opportunity for Policy evolution. Moving beyond the
baseline required a Policy that could preserve knowledge after a location left
the screen, pursue a target across several rooms, and revise its plan after a
failed Action.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-strategy-did-sol-build">What strategy did Sol build?<a href="https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/#what-strategy-did-sol-build" class="hash-link" aria-label="Direct link to What strategy did Sol build?" title="Direct link to What strategy did Sol build?" translate="no">​</a></h2>
<p>Sol turned the local exploration baseline into a more structured navigation
system. Its final Policy combined three ideas that reinforce one another.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="persistent-spatial-memory">Persistent spatial memory<a href="https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/#persistent-spatial-memory" class="hash-link" aria-label="Direct link to Persistent spatial memory" title="Direct link to Persistent spatial memory" translate="no">​</a></h3>
<p>The Policy records discovered terrain, routes, targets, and movement outcomes.
Instead of repeatedly choosing only among adjacent tiles, it can use earlier
observations to navigate through known rooms and corridors. Information remains
useful after the character moves elsewhere on the level.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="goal-directed-exploration">Goal-directed exploration<a href="https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/#goal-directed-exploration" class="hash-link" aria-label="Direct link to Goal-directed exploration" title="Direct link to Goal-directed exploration" translate="no">​</a></h3>
<p>Sol made dungeon progress an explicit objective. When the Policy knows about a
downward staircase, it can preserve that target, route back to it, and use it.
When it does not know a staircase, it seeks unexplored space rather than merely
choosing the least-visited visible neighbor.</p>
<p>This turns depth from a metric observed after the Episode into a goal expressed
inside the executable strategy.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="failure-detection-and-recovery">Failure detection and recovery<a href="https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/#failure-detection-and-recovery" class="hash-link" aria-label="Direct link to Failure detection and recovery" title="Direct link to Failure detection and recovery" translate="no">​</a></h3>
<p>Movement in NetHack can fail because of walls, boulders, iron bars, creatures,
doors, or a stale interpretation of the map. Sol compares the intended move
with the next observation. If the expected transition did not occur, the Policy
can mark the route as blocked, discard an invalid target, and choose another
path instead of repeating the same Action.</p>
<p>The result is more general than a list of special cases: observe the outcome,
update the internal map, and replan.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-agents-used-environment-feedback">How agents used Environment Feedback<a href="https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/#how-agents-used-environment-feedback" class="hash-link" aria-label="Direct link to How agents used Environment Feedback" title="Direct link to How agents used Environment Feedback" translate="no">​</a></h2>
<p><strong>Luna — remembering obstacles.</strong> Luna found trajectories dominated by repeated
attempts to move through a boulder or iron bars. It added memory for failed
directions and reduced immediate retries against static obstacles.</p>
<p><strong>Terra — escaping loops and using stairs.</strong> Terra introduced anti-loop
behavior and explicit stair descent. Its strongest selected candidate came
from an earlier revision, illustrating that continued editing does not always
produce a better Policy.</p>
<p><strong>Sol — organizing fixes into a navigation system.</strong> Sol combined remembered
routes, stair-oriented progress, blocked-edge handling, and target recovery.
Rather than treating each failure as an isolated patch, it connected the
lessons through a shared model of position, routes, targets, and outcomes.</p>
<p>In every case, the durable result was not the Agent's explanation of the
trajectory. The lesson had to survive as code that independently received
observations and returned Actions during held-out evaluation.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="findings-and-boundaries">Findings and boundaries<a href="https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/#findings-and-boundaries" class="hash-link" aria-label="Direct link to Findings and boundaries" title="Direct link to Findings and boundaries" translate="no">​</a></h2>
<p>Complete semantic trajectories were enough for the Agents to locate behavioral
failures and make useful Policy changes without an Environment-authored
diagnosis. The experiment also shows why NetHack needs more than one metric:
return ranks candidates, while depth, game score, and frozen-step rate reveal
different aspects of exploration and progress.</p>
<p>These results are still an initial study. The Agents did not consume equal
training budgets, and each model lane is represented by one primary Run. With
the short 128-Episode training ceiling, coding-agent search can vary because of
randomness: a separate Terra Run under the same Environment configuration
scored <code>49.464</code>, compared with <code>80.237</code> here.</p>
<p>The table should therefore be read as evidence that the Agents built better
NetHack Policies in these Runs, not as a general ranking of Luna, Terra, and
Sol.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="code-and-notes">Code and notes<a href="https://linzwcs.github.io/EvoPolicyGym/blog/nethack-policy-evolution/#code-and-notes" class="hash-link" aria-label="Direct link to Code and notes" title="Direct link to Code and notes" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://github.com/Linzwcs/EvoPolicyGym/tree/main/environments/nle/nethack" target="_blank" rel="noopener noreferrer" class="">NLE NetHack Benchmark</a></li>
<li class=""><a class="" href="https://linzwcs.github.io/EvoPolicyGym/docs/evaluation/">Evaluation and Runs</a></li>
<li class=""><a class="" href="https://linzwcs.github.io/EvoPolicyGym/docs/policy/">Policy boundary</a></li>
</ul>
<p>The EvoPolicyGym adapter is MIT licensed. NLE and NetHack remain separate
dependencies governed by their respective licenses.</p>]]></content>
        <author>
            <name>EvoPolicyGym contributors</name>
            <uri>https://github.com/Linzwcs/EvoPolicyGym</uri>
        </author>
        <category label="Benchmark" term="Benchmark"/>
        <category label="NetHack" term="NetHack"/>
        <category label="Experiment" term="Experiment"/>
        <category label="Policy Evolution" term="Policy Evolution"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Letting Coding Agents Build Strategy Systems for Balatro]]></title>
        <id>https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/</id>
        <link href="https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/"/>
        <updated>2026-07-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[We integrated a Balatro Environment and compared the policy-optimization results of Luna, Terra, and Sol under a 1,024-Episode interaction budget.]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-balatro">What is Balatro?<a href="https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/#what-is-balatro" class="hash-link" aria-label="Direct link to What is Balatro?" title="Direct link to What is Balatro?" translate="no">​</a></h2>
<p>Balatro is a roguelike deck-building game centered on scoring poker hands. A
player begins each Run with a standard deck, scores points by playing hands,
strengthens the build through the shop, and wins by defeating the Boss Blind
in Ante 8. Draws, shops, and rewards change from Run to Run; losing starts a
new Run.</p>
<p>Each Run repeatedly follows the same loop:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">choose a Blind → play or discard → reach the target score → earn money → build in the shop → next Blind</span><br></div></code></pre></div></div>
<ul>
<li class=""><strong>Blinds</strong>: A Run has eight Antes, each containing a Small Blind, Big Blind,
and Boss Blind. The Small and Big Blinds can be skipped in exchange for a
Tag, while the Boss Blind adds a rule that changes how the round plays.</li>
<li class=""><strong>Playing a hand</strong>: The player selects one to five cards. Poker hands such as
pairs, two pair, straights, and flushes determine the base Chips and Mult.
Scoring cards and other effects modify both values, producing a final score
of <code>Chips × Mult</code>.</li>
<li class=""><strong>Clearing a Blind</strong>: Scores from multiple hands accumulate within a Blind.
Reaching the target Chips clears it; running out of hands ends the Run.</li>
<li class=""><strong>Discarding</strong>: A discard replaces unwanted cards, using a limited resource
to improve later hands.</li>
<li class=""><strong>Building</strong>: Clearing a Blind awards money and opens the shop. Jokers change
scoring, Planets level up poker hands, Tarot and Spectral cards modify the
deck, Vouchers and Boosters provide longer-term upgrades, and rerolls spend
money to refresh the shop.</li>
</ul>
<p>The core challenge is allocating resources between clearing the current Blind
and growing the build over time: which hand to play, when to discard, which
Jokers to buy and how to order them, how much cash to keep, whether to skip a
Blind, and how to handle Boss rules. Together, these decisions form a complete
Balatro strategy.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="bringing-balatro-into-evopolicygym">Bringing Balatro into EvoPolicyGym<a href="https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/#bringing-balatro-into-evopolicygym" class="hash-link" aria-label="Direct link to Bringing Balatro into EvoPolicyGym" title="Direct link to Bringing Balatro into EvoPolicyGym" translate="no">​</a></h2>
<p>In EvoPolicyGym v0.3.0, we integrated the unofficial Balatro engine
<a href="https://github.com/TylerFlar/jackdaw-balatro" target="_blank" rel="noopener noreferrer" class="">Jackdaw</a> as a vendored
dependency and used it to implement a Balatro evaluation Environment.</p>
<p>At every step, the Policy receives a public observation that includes:</p>
<ul>
<li class="">the Ante, Blind, target score, and remaining hands and discards;</li>
<li class="">the hand, Jokers, Consumables, public deck statistics, and current poker-hand
levels;</li>
<li class="">the current shop, Boosters, Vouchers, Tags, and cash;</li>
<li class="">a strict enumeration of legal Actions for the current phase;</li>
<li class="">rule descriptions for visible objects in the pinned engine version.</li>
</ul>
<p>The Policy returns a semantic Action such as playing, discarding, buying,
selling, rerolling, opening a pack, or reordering Jokers. The Environment does
not repair an invalid Action; it records a Policy failure. State may persist
within one Episode, while every new Episode starts with a fresh Policy
instance.</p>
<p>The final Policy score is:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">number of Blinds cleared + 1000 × whether the Run was completed</span><br></div></code></pre></div></div>
<p>Each cleared Blind contributes one point, and completing the Run adds 1,000
points. This preserves completion as the final objective while giving Policies
that have not yet won continuous Feedback through their average progress.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-brief-overview-of-the-evopolicygym-evaluation-process">A brief overview of the EvoPolicyGym evaluation process<a href="https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/#a-brief-overview-of-the-evopolicygym-evaluation-process" class="hash-link" aria-label="Direct link to A brief overview of the EvoPolicyGym evaluation process" title="Direct link to A brief overview of the EvoPolicyGym evaluation process" translate="no">​</a></h2>
<p>During an EvoPolicyGym Run, a Coding Agent starts from an initial Program,
repeatedly submits strategies, evaluates them on training Episodes, and
continues optimizing from scores and replays. After the Agent finishes,
Validation selects the final Program, and Assessment measures it on held-out
test Episodes. Every submitted Program, its Feedback and replays, and the
optimization record are retained in the Run data.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="experiment">Experiment<a href="https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/#experiment" class="hash-link" aria-label="Direct link to Experiment" title="Direct link to Experiment" translate="no">​</a></h2>
<p>We compared the packaged baseline with the Programs handed off by optimization
Runs from three Coding Agents: Luna, Terra, and Sol. All three Agents started
from the same baseline and used the same training Episode pool and Environment
interaction budget.</p>
<p>The baseline is a deterministic poker-hand strategy. It enumerates every
one-to-five-card combination in the current hand and chooses according to
standard poker-hand rank and card values. In the shop, it buys the first
affordable Joker; when opening a pack, it selects the first Joker. It does not
use discards, Consumables, or rerolls, nor does it manage Joker combinations or
the economy.</p>
<p>Luna, Terra, and Sol each received the same training Episode pool and a total
Episode budget of 1,024. After optimization, we froze the Program selected by
each Agent and evaluated all four Programs on the same 128 held-out test
Episodes:</p>
<table><thead><tr><th>Experiment</th><th>Agent</th><th>Reasoning</th><th style="text-align:right">Training Episode budget</th><th style="text-align:right">Test Episodes</th></tr></thead><tbody><tr><td>Packaged baseline</td><td>—</td><td>—</td><td style="text-align:right">0</td><td style="text-align:right">128</td></tr><tr><td>Luna</td><td><code>gpt-5.6-luna</code></td><td><code>xhigh</code></td><td style="text-align:right">1024</td><td style="text-align:right">128</td></tr><tr><td>Terra</td><td><code>gpt-5.6-terra</code></td><td><code>xhigh</code></td><td style="text-align:right">1024</td><td style="text-align:right">128</td></tr><tr><td>Sol</td><td><code>gpt-5.6-sol</code></td><td><code>xhigh</code></td><td style="text-align:right">1024</td><td style="text-align:right">128</td></tr></tbody></table>
<p>The experiment used Red Deck, White Stake, a Run seed of <code>20260729</code>, and a
60-second timeout for each Episode.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="results">Results<a href="https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/#results" class="hash-link" aria-label="Direct link to Results" title="Direct link to Results" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Balatro held-out test results for four Programs. Sol cleared 10.45 Blinds
on average, completed 5 of 128 Runs, and achieved a mean final score of
49.52." src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA5NjAgNDQyIiByb2xlPSJpbWciIGFyaWEtbGFiZWxsZWRieT0idGl0bGUgZGVzY3JpcHRpb24iPgogIDx0aXRsZSBpZD0idGl0bGUiPkJhbGF0cm8gaGVsZC1vdXQgdGVzdCByZXN1bHRzPC90aXRsZT4KICA8ZGVzYyBpZD0iZGVzY3JpcHRpb24iPkhvcml6b250YWwgYmFycyBjb21wYXJlIHRoZSBhdmVyYWdlIG51bWJlciBvZiBCbGluZHMgY2xlYXJlZCBieSBQYWNrYWdlZCBiYXNlbGluZSwgTHVuYSwgVGVycmEsIGFuZCBTb2wuIFNvbCBjbGVhcmVkIDEwLjQ1IEJsaW5kcyBvbiBhdmVyYWdlIGFuZCB3b24gNSBvZiAxMjggcnVucy48L2Rlc2M+CgogIDxnIGZvbnQtZmFtaWx5PSInQXZlbmlyIE5leHQnLCAnSW50ZXInLCBzYW5zLXNlcmlmIj4KICAgIDx0ZXh0IHg9IjE5NiIgeT0iMjgiIGZpbGw9IiM1MDUyNGQiIGZvbnQtc2l6ZT0iMTMiPkF2ZXJhZ2UgQmxpbmRzIGNsZWFyZWQ8L3RleHQ+CiAgICA8dGV4dCB4PSI3NDAiIHk9IjI4IiBmaWxsPSIjNTA1MjRkIiBmb250LXNpemU9IjEzIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5SdW5zIHdvbjwvdGV4dD4KICAgIDx0ZXh0IHg9IjkyMCIgeT0iMjgiIGZpbGw9IiM1MDUyNGQiIGZvbnQtc2l6ZT0iMTMiIHRleHQtYW5jaG9yPSJlbmQiPk1lYW4gZmluYWwgc2NvcmU8L3RleHQ+CgogICAgPGcgc3Ryb2tlPSIjZDNkMGM3IiBzdHJva2Utd2lkdGg9IjEiPgogICAgICA8bGluZSB4MT0iMTk2IiB5MT0iNDgiIHgyPSIxOTYiIHkyPSIzNjAiLz4KICAgICAgPGxpbmUgeDE9IjM0OSIgeTE9IjQ4IiB4Mj0iMzQ5IiB5Mj0iMzYwIi8+CiAgICAgIDxsaW5lIHgxPSI1MDMiIHkxPSI0OCIgeDI9IjUwMyIgeTI9IjM2MCIvPgogICAgICA8bGluZSB4MT0iNjU2IiB5MT0iNDgiIHgyPSI2NTYiIHkyPSIzNjAiLz4KICAgIDwvZz4KCiAgICA8ZyBmaWxsPSIjOGI4ZTg1IiBmb250LXNpemU9IjEyIj4KICAgICAgPHRleHQgeD0iMTk2IiB5PSIzODQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPjA8L3RleHQ+CiAgICAgIDx0ZXh0IHg9IjM0OSIgeT0iMzg0IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj40PC90ZXh0PgogICAgICA8dGV4dCB4PSI1MDMiIHk9IjM4NCIgdGV4dC1hbmNob3I9Im1pZGRsZSI+ODwvdGV4dD4KICAgICAgPHRleHQgeD0iNjU2IiB5PSIzODQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPjEyPC90ZXh0PgogICAgPC9nPgoKICAgIDxnPgogICAgICA8dGV4dCB4PSIyMCIgeT0iOTIiIGZpbGw9IiMxNzE4MTUiIGZvbnQtc2l6ZT0iMTUiIGZvbnQtd2VpZ2h0PSI1MDAiPlNvbDwvdGV4dD4KICAgICAgPHJlY3QgeD0iMTk2IiB5PSI3MyIgd2lkdGg9IjQ2MCIgaGVpZ2h0PSIyNCIgcng9IjQiIGZpbGw9IiNmNGY0ZjEiLz4KICAgICAgPHJlY3QgeD0iMTk2IiB5PSI3MyIgd2lkdGg9IjQwMSIgaGVpZ2h0PSIyNCIgcng9IjQiIGZpbGw9IiNjODRiMjciLz4KICAgICAgPHRleHQgeD0iNjA5IiB5PSI5MSIgZmlsbD0iIzE3MTgxNSIgZm9udC1zaXplPSIxNCIgZm9udC13ZWlnaHQ9IjUwMCI+MTAuNDU8L3RleHQ+CiAgICAgIDxjaXJjbGUgY3g9IjcwNCIgY3k9Ijg0IiByPSI1IiBmaWxsPSIjYzg0YjI3Ii8+CiAgICAgIDx0ZXh0IHg9Ijc0MCIgeT0iOTEiIGZpbGw9IiMxNzE4MTUiIGZvbnQtc2l6ZT0iMTUiIGZvbnQtd2VpZ2h0PSI1MDAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPjUgLyAxMjg8L3RleHQ+CiAgICAgIDx0ZXh0IHg9IjkyMCIgeT0iOTEiIGZpbGw9IiMxNzE4MTUiIGZvbnQtc2l6ZT0iMTUiIGZvbnQtd2VpZ2h0PSI1MDAiIHRleHQtYW5jaG9yPSJlbmQiPjQ5LjUyPC90ZXh0PgogICAgPC9nPgoKICAgIDxnPgogICAgICA8dGV4dCB4PSIyMCIgeT0iMTY5IiBmaWxsPSIjMTcxODE1IiBmb250LXNpemU9IjE1IiBmb250LXdlaWdodD0iNTAwIj5UZXJyYTwvdGV4dD4KICAgICAgPHJlY3QgeD0iMTk2IiB5PSIxNTAiIHdpZHRoPSI0NjAiIGhlaWdodD0iMjQiIHJ4PSI0IiBmaWxsPSIjZjRmNGYxIi8+CiAgICAgIDxyZWN0IHg9IjE5NiIgeT0iMTUwIiB3aWR0aD0iMzQxIiBoZWlnaHQ9IjI0IiByeD0iNCIgZmlsbD0iIzE3NmI2ZCIvPgogICAgICA8dGV4dCB4PSI1NDkiIHk9IjE2OCIgZmlsbD0iIzE3MTgxNSIgZm9udC1zaXplPSIxNCIgZm9udC13ZWlnaHQ9IjUwMCI+OC44OTwvdGV4dD4KICAgICAgPHRleHQgeD0iNzQwIiB5PSIxNjgiIGZpbGw9IiM4YjhlODUiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPjAgLyAxMjg8L3RleHQ+CiAgICAgIDx0ZXh0IHg9IjkyMCIgeT0iMTY4IiBmaWxsPSIjMTcxODE1IiBmb250LXNpemU9IjE1IiB0ZXh0LWFuY2hvcj0iZW5kIj44Ljg5PC90ZXh0PgogICAgPC9nPgoKICAgIDxnPgogICAgICA8dGV4dCB4PSIyMCIgeT0iMjQ2IiBmaWxsPSIjMTcxODE1IiBmb250LXNpemU9IjE1IiBmb250LXdlaWdodD0iNTAwIj5MdW5hPC90ZXh0PgogICAgICA8cmVjdCB4PSIxOTYiIHk9IjIyNyIgd2lkdGg9IjQ2MCIgaGVpZ2h0PSIyNCIgcng9IjQiIGZpbGw9IiNmNGY0ZjEiLz4KICAgICAgPHJlY3QgeD0iMTk2IiB5PSIyMjciIHdpZHRoPSIzMDIiIGhlaWdodD0iMjQiIHJ4PSI0IiBmaWxsPSIjMTc2YjZkIi8+CiAgICAgIDx0ZXh0IHg9IjUxMCIgeT0iMjQ1IiBmaWxsPSIjMTcxODE1IiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iNTAwIj43Ljg3PC90ZXh0PgogICAgICA8dGV4dCB4PSI3NDAiIHk9IjI0NSIgZmlsbD0iIzhiOGU4NSIgZm9udC1zaXplPSIxNSIgdGV4dC1hbmNob3I9Im1pZGRsZSI+MCAvIDEyODwvdGV4dD4KICAgICAgPHRleHQgeD0iOTIwIiB5PSIyNDUiIGZpbGw9IiMxNzE4MTUiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJlbmQiPjcuODc8L3RleHQ+CiAgICA8L2c+CgogICAgPGc+CiAgICAgIDx0ZXh0IHg9IjIwIiB5PSIzMjMiIGZpbGw9IiMxNzE4MTUiIGZvbnQtc2l6ZT0iMTUiIGZvbnQtd2VpZ2h0PSI1MDAiPlBhY2thZ2VkIGJhc2VsaW5lPC90ZXh0PgogICAgICA8cmVjdCB4PSIxOTYiIHk9IjMwNCIgd2lkdGg9IjQ2MCIgaGVpZ2h0PSIyNCIgcng9IjQiIGZpbGw9IiNmNGY0ZjEiLz4KICAgICAgPHJlY3QgeD0iMTk2IiB5PSIzMDQiIHdpZHRoPSIxNDIiIGhlaWdodD0iMjQiIHJ4PSI0IiBmaWxsPSIjOGI4ZTg1Ii8+CiAgICAgIDx0ZXh0IHg9IjM1MCIgeT0iMzIyIiBmaWxsPSIjMTcxODE1IiBmb250LXNpemU9IjE0IiBmb250LXdlaWdodD0iNTAwIj4zLjcwPC90ZXh0PgogICAgICA8dGV4dCB4PSI3NDAiIHk9IjMyMiIgZmlsbD0iIzhiOGU4NSIgZm9udC1zaXplPSIxNSIgdGV4dC1hbmNob3I9Im1pZGRsZSI+MCAvIDEyODwvdGV4dD4KICAgICAgPHRleHQgeD0iOTIwIiB5PSIzMjIiIGZpbGw9IiMxNzE4MTUiIGZvbnQtc2l6ZT0iMTUiIHRleHQtYW5jaG9yPSJlbmQiPjMuNzA8L3RleHQ+CiAgICA8L2c+CgogICAgPGxpbmUgeDE9IjIwIiB5MT0iNDA2IiB4Mj0iOTQwIiB5Mj0iNDA2IiBzdHJva2U9IiNkM2QwYzciIHN0cm9rZS13aWR0aD0iMSIvPgogICAgPHRleHQgeD0iMjAiIHk9IjQzMCIgZmlsbD0iIzhiOGU4NSIgZm9udC1zaXplPSIxMiI+MTI4IGhlbGQtb3V0IHRlc3QgRXBpc29kZXMgwrcgUmVkIERlY2sgwrcgV2hpdGUgU3Rha2U8L3RleHQ+CiAgPC9nPgo8L3N2Zz4K" width="960" height="442" class="img_ev3q"></p>
<p>Sol was the only model to produce a strategy capable of completing a Run. It
cleared 10.45 Blinds on average, 2.83 times the baseline result, and completed
5 of 128 Runs. Luna and Terra also more than doubled the baseline's average
progress, but neither completed a Run. Reducing early mistakes can extend a
Run; completing one requires a coherent long-term build strategy.</p>
<p><img decoding="async" loading="lazy" alt="Semantic replay of a winning held-out Balatro Episode from Sol&amp;#39;s final
Policy. The replay advances from Ante 1 to Ante 9, clears 21 Blinds, and
completes the Run with a score of 1021." src="https://linzwcs.github.io/EvoPolicyGym/assets/images/balatro-sol-winning-replay-57c374eb48d7edff1a9115f4f3cd44b7.gif" width="960" height="540" class="img_ev3q"></p>
<p><em>Held-out case index 41 from the same 128-Episode test set. The geometric
rendering was generated from the Benchmark's semantic replay and contains no
official Balatro game assets.</em></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-baselines-capability-boundary">The baseline's capability boundary<a href="https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/#the-baselines-capability-boundary" class="hash-link" aria-label="Direct link to The baseline's capability boundary" title="Direct link to The baseline's capability boundary" translate="no">​</a></h2>
<p>The packaged baseline enumerates every one-to-five-card combination in the
current hand, preferring combinations with a higher standard poker-hand rank
and card values. In the shop and when opening packs, it selects the first Joker
that meets its conditions.</p>
<p>It answers “which hand ranks higher right now,” but does not connect projected
score, discards, Joker combinations, economy, and Boss rules.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-strategy-did-sol-build">What strategy did Sol build?<a href="https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/#what-strategy-did-sol-build" class="hash-link" aria-label="Direct link to What strategy did Sol build?" title="Direct link to What strategy did Sol build?" translate="no">​</a></h2>
<p>Sol built an approximate model of the game state and applied a coordinated set
of heuristics for each phase. The final Policy changed in three main ways.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="score-estimation-and-hand-planning">Score estimation and hand planning<a href="https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/#score-estimation-and-hand-planning" class="hash-link" aria-label="Direct link to Score estimation and hand planning" title="Direct link to Score estimation and hand planning" translate="no">​</a></h3>
<p>Sol still enumerates one-to-five-card combinations, but evaluates their
expected <code>Chips × Mult</code>. The estimate accounts for poker-hand levels, scoring
cards, Enhancements, Editions, held-in-hand effects, and Joker combinations.</p>
<p>The Policy combines that estimate with the target score and the remaining
hands and discards to decide whether to play immediately or keep searching. It
protects cards with value while held in hand and, when no discards remain, can
play low-value cards to draw replacements.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="joker-construction-and-economy-management">Joker construction and economy management<a href="https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/#joker-construction-and-economy-management" class="hash-link" aria-label="Direct link to Joker construction and economy management" title="Direct link to Joker construction and economy management" translate="no">​</a></h3>
<p>Sol estimates Joker value, seeks stable combinations of Chips, Mult, and X
Mult, and reorders Jokers according to effect dependencies. When all slots are
full, it replaces an existing component only if the candidate Joker is clearly
stronger.</p>
<p>Shop decisions are also tied to the build. Based on the Ante, available cash,
and missing components, the Policy decides whether to buy, preserve interest,
or reroll. Cash is used to strengthen later rounds, not just the current shop.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="cross-round-state-management">Cross-round state management<a href="https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/#cross-round-state-management" class="hash-link" aria-label="Direct link to Cross-round state management" title="Direct link to Cross-round state management" translate="no">​</a></h3>
<p>The Policy records shop visits, pack openings, poker hands, and skipped Blinds,
then adapts its behavior to Boss rules. Score estimates influence discards,
discards affect the probability of clearing the Blind, and the resulting
economy changes the next round's build, forming a complete decision loop.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-models-use-environment-feedback">How models use Environment Feedback<a href="https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/#how-models-use-environment-feedback" class="hash-link" aria-label="Direct link to How models use Environment Feedback" title="Direct link to How models use Environment Feedback" translate="no">​</a></h2>
<p>Given the same baseline, training data, and budget, Sol was the only model to
complete a Run. It used replay and score Feedback more effectively, organizing
local lessons into a complete strategy spanning hands, construction, and
economy—more like an experienced player.</p>
<p>Sol's Policy also reveals an engineering problem: about 1,860 lines of logic
are concentrated in a single file, creating tight coupling. The next step is
to separate the strategy into modules that are easier to test, calibrate, and
continue improving.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="next-steps">Next steps<a href="https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/#next-steps" class="hash-link" aria-label="Direct link to Next steps" title="Direct link to Next steps" translate="no">​</a></h2>
<p>The first direction is Skills. An effective Skill can provide more than domain
knowledge: it can also provide methods for modularization, replay analysis, and
testing. Comparing the same Agent and budget with and without a Skill would
measure both the final score and the engineering structure of the Policy.</p>
<p>The second direction is cross-Environment RL. The goal is not to memorize one
Environment's rules, but to learn how to locate failures, form hypotheses,
design experiments, and update strategies—and transfer that process to an
unseen Environment.</p>
<p>While integrating different Environments, we also encountered another
valuable but underexplored question: can an Agent observe an external system
and build an Environment suitable for training and evaluation? For example,
can an Agent understand a game's core rules and implement a behaviorally
equivalent engine that strips away strategy-irrelevant details such as art and
audio, retaining only states, Actions, and Feedback?</p>
<p>Answering this requires measuring whether an Agent can correctly abstract
states, Actions, Feedback, and evaluation rules. Today we primarily evaluate
how Agents use Environments to optimize strategies; Environment construction
itself still lacks systematic measurement. If an Agent can do this well, its
Environment can be integrated into EvoPolicyGym and used for further strategy
optimization. This complete loop—from observation to modeling to
optimization—could help future Agents adapt to new Environments faster and
build effective decision systems.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="code-and-notes">Code and notes<a href="https://linzwcs.github.io/EvoPolicyGym/blog/balatro-policy-evolution/#code-and-notes" class="hash-link" aria-label="Direct link to Code and notes" title="Direct link to Code and notes" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://github.com/Linzwcs/EvoPolicyGym/tree/main/environments/jackdaw/balatro" target="_blank" rel="noopener noreferrer" class="">EvoPolicyGym Balatro Benchmark</a></li>
<li class=""><a href="https://github.com/Linzwcs/EvoPolicyGym" target="_blank" rel="noopener noreferrer" class="">EvoPolicyGym</a></li>
<li class=""><a href="https://huggingface.co/datasets/linzw/EvoPolicyGym-Exp-data/tree/main/v0.3.0/balatro" target="_blank" rel="noopener noreferrer" class="">Balatro experiment data</a></li>
</ul>
<p>This Benchmark is unaffiliated with LocalThunk, Playstack, or the official
Balatro project and contains no official card faces, artwork, music, fonts, or
other game assets.</p>]]></content>
        <author>
            <name>EvoPolicyGym contributors</name>
            <uri>https://github.com/Linzwcs/EvoPolicyGym</uri>
        </author>
        <category label="Benchmark" term="Benchmark"/>
        <category label="Balatro" term="Balatro"/>
        <category label="Experiment" term="Experiment"/>
        <category label="Policy Evolution" term="Policy Evolution"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[EvoPolicyGym: environments for agents that build strategy systems]]></title>
        <id>https://linzwcs.github.io/EvoPolicyGym/blog/designing-evopolicygym/</id>
        <link href="https://linzwcs.github.io/EvoPolicyGym/blog/designing-evopolicygym/"/>
        <updated>2026-07-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Why EvoPolicyGym uses interactive Environments and executable Programs to study and train coding agents.]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="coding-agents-as-policy-system-experts">Coding agents as policy-system experts<a href="https://linzwcs.github.io/EvoPolicyGym/blog/designing-evopolicygym/#coding-agents-as-policy-system-experts" class="hash-link" aria-label="Direct link to Coding agents as policy-system experts" title="Direct link to Coding agents as policy-system experts" translate="no">​</a></h2>
<p>EvoPolicyGym was directly inspired by Jiayi Weng's
<a href="https://trinkle23897.github.io/learning-beyond-gradients/" target="_blank" rel="noopener noreferrer" class="">Learning Beyond Gradients</a>.
The article describes <em>Heuristic Learning</em>: a coding agent absorbs rewards,
failures, tests, logs, and replays, then improves a programmatic policy by
editing the software system itself. It showed us that agentic coding can serve
as a learning process whose evolving state is explicit in code.</p>
<p>EvoPolicyGym begins from that insight and asks how to make the process bounded,
reproducible, and comparable across interactive Environments.</p>
<p>An EvoPolicyGym Run places a coding agent in the role of a policy-system
expert. The agent studies the Environment and its interface, inspects an
initial Program, forms hypotheses about successful behavior, and writes those
ideas into a complete executable Policy system.</p>
<p>That system may combine domain knowledge, state estimation, rules, planning,
search, memory, algorithms, or tuned parameters. The coding agent is free to
change its internal design as evidence accumulates. Its responsibility is to
turn what it learns into source code that can make decisions on its own.</p>
<p>Authoring and execution occupy two distinct phases. During Evaluation, the
submitted Policy independently receives observations and produces Actions.
The result is a separable strategy artifact that can be frozen, inspected,
rerun, and compared.</p>
<p>Environment Feedback closes the engineering loop:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">study the Environment</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">author an executable Policy system</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">submit and evaluate it</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">inspect scores, traces, and artifacts</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">diagnose, redesign, and submit again</span><br></div></code></pre></div></div>
<p>This is the motivation for Autonomous Policy Evolution in EvoPolicyGym. The
coding agent contributes expertise and software engineering; the Environment
contributes empirical evidence; the evolving Program records the resulting
strategy. The central question is how effectively an agent can transform
limited Environment Feedback into a better executable decision system.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="separate-the-expert-from-the-policy">Separate the expert from the Policy<a href="https://linzwcs.github.io/EvoPolicyGym/blog/designing-evopolicygym/#separate-the-expert-from-the-policy" class="hash-link" aria-label="Direct link to Separate the expert from the Policy" title="Direct link to Separate the expert from the Policy" translate="no">​</a></h2>
<p>EvoPolicyGym gives the coding agent and the Policy different roles.</p>
<p>The coding agent is the outer policy engineer and optimizer. It reads
instructions and public Feedback, edits <code>workspace/program/</code>, and decides when
to submit another candidate. The Policy is the inner decision system. It
receives observations through a small ABI and returns Actions while an Episode
is running.</p>
<p>A Policy may retain state between <code>act()</code> calls inside one Episode. Each new
Episode receives a fresh process and Policy instance, while cross-Episode
improvement is represented by a new Program.</p>
<p>EvoPolicyGym locates learning at the Program level between Episodes.
Episode-local state supports temporal behavior; Program revision captures
lasting improvement. Each change therefore has a visible source snapshot and
a clear relationship to its Evaluation evidence.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="make-the-artifact-first-class">Make the artifact first-class<a href="https://linzwcs.github.io/EvoPolicyGym/blog/designing-evopolicygym/#make-the-artifact-first-class" class="hash-link" aria-label="Direct link to Make the artifact first-class" title="Direct link to Make the artifact first-class" translate="no">​</a></h2>
<p>The workspace supports live authoring. Every accepted submission turns its
current source tree into an immutable, content-addressed <code>Program</code>. The
Evaluation, Feedback, and artifacts belong to that exact snapshot, and the
final result returns the retained Program selected from submitted candidates.</p>
<p>This choice makes a Run understandable as a sequence of authored artifacts:</p>
<table><thead><tr><th>Object</th><th>Responsibility</th></tr></thead><tbody><tr><td><code>Program</code></td><td>The executable Policy source being evaluated</td></tr><tr><td><code>Submission</code></td><td>One immutable Program, an explicit training-index selector, and committed Feedback</td></tr><tr><td><code>Run</code></td><td>A bounded sequence of submissions and a final handoff</td></tr><tr><td><code>Validation</code></td><td>Host-side selection among finished candidates</td></tr><tr><td><code>Assessment</code></td><td>Held-out measurement of the selected Program</td></tr></tbody></table>
<p>The Program is the durable result. The agent transcript and process logs
provide supporting diagnostics.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="let-each-benchmark-define-useful-feedback">Let each Benchmark define useful Feedback<a href="https://linzwcs.github.io/EvoPolicyGym/blog/designing-evopolicygym/#let-each-benchmark-define-useful-feedback" class="hash-link" aria-label="Direct link to Let each Benchmark define useful Feedback" title="Direct link to Let each Benchmark define useful Feedback" translate="no">​</a></h2>
<p>Different Environments expose different kinds of evidence. A control task may
benefit from state trajectories and termination causes. A card game may need
round summaries, economy decisions, or compact replays.</p>
<p>EvoPolicyGym standardizes the Feedback carrier while each Benchmark defines
its useful domain content. Feedback always has a scalar score, and the
Benchmark may add bounded public values and artifacts. The Benchmark also owns
Episode planning, Environment construction, Action validation, and scoring.</p>
<p>The Kernel owns what must remain consistent across Benchmarks: budgets,
immutable submissions, lifecycle ordering, publication, selection, records,
and the Policy ABI. Environment packages remain independently installable and
depend only on the public authoring interface.</p>
<p>This division lets the project grow like a Gym-style ecosystem while the
Kernel remains stable and domain-independent.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="treat-evidence-access-as-part-of-the-experiment">Treat evidence access as part of the experiment<a href="https://linzwcs.github.io/EvoPolicyGym/blog/designing-evopolicygym/#treat-evidence-access-as-part-of-the-experiment" class="hash-link" aria-label="Direct link to Treat evidence access as part of the experiment" title="Direct link to Treat evidence access as part of the experiment" translate="no">​</a></h2>
<p>A Run's submission limit, total Episode budget, fixed training-pool size, and
optional per-Submission cap define its experimental condition. For example,
sixteen submissions, forty-eight Episode units, and a pool of ninety-six
Episode identities grant forty-eight total observations selected from a wider
set; the larger pool does not increase the interaction budget.</p>
<p>The Host constructs this indexed pool before the agent starts. Each Submission
names a non-empty set of public Run-local indices. Reusing an index keeps its
hidden Episode specification and Policy seed fixed, so two immutable Programs
can be compared on matched evidence. Every use still creates a fresh
Environment and Policy runtime and consumes budget again. Actual seeds,
scenarios, and pool construction remain Host-owned.</p>
<p>Once an Evaluation begins, its reserved Episode allocation is consumed. Policy
failures and invalid Actions are reported as observed behavior, preserving the
exact semantics of the submitted Program. Feedback maps every sanitized
Episode outcome back to its public index, while comparisons over different
selectors remain unmatched evidence.</p>
<p>The agent uses public search Feedback to decide what to try next. When it
finishes, authority returns to the Host. Private Validation selects among the
handed-off candidates, and held-out Assessment measures the selected Program.
Optimization Feedback closes at <code>finish</code>; selection and final measurement
remain Host-side.</p>
<p>Keeping search, selection, and final measurement distinct makes the reported
result easier to interpret.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="keep-the-kernel-focused">Keep the Kernel focused<a href="https://linzwcs.github.io/EvoPolicyGym/blog/designing-evopolicygym/#keep-the-kernel-focused" class="hash-link" aria-label="Direct link to Keep the Kernel focused" title="Direct link to Keep the Kernel focused" translate="no">​</a></h2>
<p>EvoPolicyGym is infrastructure with deliberately focused ownership.</p>
<ul>
<li class="">Agent integrations translate a Host-owned task into a provider invocation.</li>
<li class="">Benchmark distributions own domain semantics, dependencies, baselines,
Feedback, and tests.</li>
<li class="">The Kernel owns the shared evaluation and Program-evolution lifecycle.</li>
<li class="">The Policy boundary carries bounded public values.</li>
</ul>
<p>Today Codex is the first supported coding-agent integration, and local process
execution is the active backend. The contracts remain provider- and
backend-independent, preserving the meaning of Program, Submission,
Evaluation, and Run as more integrations arrive.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-evopolicygym-enables">What EvoPolicyGym enables<a href="https://linzwcs.github.io/EvoPolicyGym/blog/designing-evopolicygym/#what-evopolicygym-enables" class="hash-link" aria-label="Direct link to What EvoPolicyGym enables" title="Direct link to What EvoPolicyGym enables" translate="no">​</a></h2>
<p>EvoPolicyGym connects scalable interactive Environments, coding agents,
versioned Programs, and verifiable Benchmark evidence. The Agent is the subject
of study and training; the Program is the executable evidence it leaves
behind.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="study-agents-that-evolve-strategy-systems">Study agents that evolve strategy systems<a href="https://linzwcs.github.io/EvoPolicyGym/blog/designing-evopolicygym/#study-agents-that-evolve-strategy-systems" class="hash-link" aria-label="Direct link to Study agents that evolve strategy systems" title="Direct link to Study agents that evolve strategy systems" translate="no">​</a></h3>
<p>With the Environment, initial Program, interaction budget, Feedback visibility,
and selection rules held constant, repeated Runs can study:</p>
<ul>
<li class=""><strong>Agent capability:</strong> which coding agent authors the strongest Policy system
under the same conditions?</li>
<li class=""><strong>Improvement efficiency:</strong> how much Environment interaction produces stable
Program improvement?</li>
<li class=""><strong>Feedback value:</strong> which traces, diagnostics, replays, and aggregate signals
lead to effective revisions?</li>
<li class=""><strong>Evolution dynamics:</strong> how does Program structure change across Submissions,
and which changes produce durable gains?</li>
<li class=""><strong>Selection validity:</strong> does the candidate chosen by Validation retain its
advantage in held-out Assessment?</li>
<li class=""><strong>Policy-system design:</strong> which state representations, rules, planners,
memories, and controllers do different agents encode?</li>
<li class=""><strong>Scaling and generalization:</strong> how do these results change across budgets,
profiles, seeds, task complexity, and Environment families?</li>
</ul>
<p>The final score measures the Agent's selected artifact. The sequence of
immutable Programs, Feedback, artifacts, and outcomes explains how the Agent
reached it.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="train-coding-agents-with-interactive-environments">Train coding agents with interactive Environments<a href="https://linzwcs.github.io/EvoPolicyGym/blog/designing-evopolicygym/#train-coding-agents-with-interactive-environments" class="hash-link" aria-label="Direct link to Train coding agents with interactive Environments" title="Direct link to Train coding agents with interactive Environments" translate="no">​</a></h3>
<p>An Environment and Benchmark together form a task generator, evidence
generator, and verifier. Profiles, scenarios, and seeds create task variation;
Program evaluations, public Feedback, diagnostics, and held-out outcomes
provide training signals.</p>
<p>The same Environment ecosystem can support:</p>
<ul>
<li class="">coding-agent RL and RLVR using Program evaluation and held-out performance as
verifiable outcomes;</li>
<li class="">SFT from successful long-horizon Agent trajectories;</li>
<li class="">agent distillation from observable evolution records: task context, public
Feedback, Program changes, Submissions, and outcomes;</li>
<li class="">rejection sampling of high-quality Agent trajectories based on their final
artifacts and results;</li>
<li class="">curriculum learning across task profiles and difficulty;</li>
<li class="">process supervision from intermediate failures, revisions, and evaluations.</li>
</ul>
<p>An Agent evolution trajectory spans the full task: understanding the
Environment, authoring a Program, reading Feedback, diagnosing behavior,
revising the strategy system, submitting candidates, and completing the final
handoff. These long-horizon records provide training material for coding agents
and policy-engineering agents.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Environment + Benchmark</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ▼</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Agent authors and revises a Program</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ├── evolution trajectory ─────▶ Agent SFT / distillation</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        └── evaluation outcomes ──────▶ Agent RL / RLVR</span><br></div></code></pre></div></div>
<p>The Kernel provides the common task, Evaluation, Run, and evidence contracts.
Dataset exporters and training systems can turn retained Agent trajectories
into SFT, RL, and distillation data, then return trained agents for held-out
measurement. In this way, the Environment catalog is both an Agent Benchmark
surface and a scalable source of verifiable long-horizon experience.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="continue-reading">Continue reading<a href="https://linzwcs.github.io/EvoPolicyGym/blog/designing-evopolicygym/#continue-reading" class="hash-link" aria-label="Direct link to Continue reading" title="Direct link to Continue reading" translate="no">​</a></h2>
<ul>
<li class=""><a class="" href="https://linzwcs.github.io/EvoPolicyGym/docs/concepts/">Core concepts →</a></li>
<li class=""><a class="" href="https://linzwcs.github.io/EvoPolicyGym/docs/evaluation/">Evaluation and Runs →</a></li>
<li class=""><a class="" href="https://linzwcs.github.io/EvoPolicyGym/environments/">Environment catalog →</a></li>
<li class=""><a class="" href="https://linzwcs.github.io/EvoPolicyGym/results/">Core16 results →</a></li>
<li class=""><a href="https://arxiv.org/abs/2607.02440" target="_blank" rel="noopener noreferrer" class="">Paper ↗</a></li>
</ul>]]></content>
        <author>
            <name>EvoPolicyGym contributors</name>
            <uri>https://github.com/Linzwcs/EvoPolicyGym</uri>
        </author>
        <category label="Design" term="Design"/>
        <category label="Motivation" term="Motivation"/>
        <category label="Architecture" term="Architecture"/>
    </entry>
</feed>