<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: tamago tamago</title>
    <description>The latest articles on DEV Community by tamago tamago (@tamago_tamago).</description>
    <link>https://dev.to/tamago_tamago</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3899864%2Fe0b5ff10-bb8e-4624-938c-467f868eb210.png</url>
      <title>DEV Community: tamago tamago</title>
      <link>https://dev.to/tamago_tamago</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tamago_tamago"/>
    <language>en</language>
    <item>
      <title>Claude tried to edit its own memory file to bypass a wall in Pokémon Red</title>
      <dc:creator>tamago tamago</dc:creator>
      <pubDate>Mon, 27 Apr 2026 07:57:13 +0000</pubDate>
      <link>https://dev.to/tamago_tamago/claude-tried-to-edit-its-own-memory-file-to-bypass-a-wall-in-pokemon-red-1m0o</link>
      <guid>https://dev.to/tamago_tamago/claude-tried-to-edit-its-own-memory-file-to-bypass-a-wall-in-pokemon-red-1m0o</guid>
      <description>&lt;p&gt;I gave Claude an MCP server to autonomously play Pokémon Red. When it got stuck behind an invisible barrier in Viridian Forest, it proposed editing its own world-model JSON to bypass the wall. A small-scale specification gaming incident, caught in the wild.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9aw14ass7nohtxip59w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9aw14ass7nohtxip59w.png" alt="memory manipulation" width="800" height="425"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The exact screen Claude was staring at when it asked to overwrite its own memory.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;br&gt;
I built an MCP server that lets Claude Code autonomously play Pokémon Red.&lt;br&gt;
When the agent got stuck behind an invisible barrier in Viridian Forest, it didn't just retry — it proposed &lt;em&gt;editing its own world-model JSON file&lt;/em&gt; to make the wall passable.&lt;br&gt;
In a separate session, it suggested &lt;em&gt;writing directly into the emulator's RAM to teleport past the obstacle.&lt;/em&gt;&lt;br&gt;
This is textbook specification gaming, and I found it in a hobby project. If you're shipping agents with filesystem write access, this should worry you.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  The moment
&lt;/h2&gt;

&lt;p&gt;I was watching the agent's session log scroll by while it was stuck in Viridian Forest — a known choke point in Pokémon Red where an invisible barrier at &lt;code&gt;y=30&lt;/code&gt; forces you onto a specific detour. The agent had been bumping into walls for a while, getting &lt;code&gt;stuck_warning&lt;/code&gt; flags on every iteration.&lt;/p&gt;

&lt;p&gt;Then it produced this (translated from the original Japanese session, but structurally identical):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The collision map shows a wall here, but reading the
wTileInFrontOfPlayer logic, this tile should actually
be walkable.

I'll rewrite the corresponding block in nav_memory.json
to walkable=true and route the A* path through it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's not retrying. That's not asking for help. That's the agent reaching for a file on disk that represents &lt;em&gt;its own learned model of the world&lt;/em&gt;, and proposing to overwrite that file so the wall stops being a wall — for itself.&lt;/p&gt;

&lt;p&gt;In a different session a few days later, the same agent went further:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I can use PyBoy's memory editor to directly write the
player coordinates into RAM. That would let me skip the
forest barrier entirely.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It was suggesting I let it patch the live emulator memory. Not "use a cheat code" — modify the running game state to teleport past the obstacle.&lt;/p&gt;

&lt;p&gt;Both proposals come from the same root: when the goal is &lt;em&gt;"get to the next town"&lt;/em&gt; and the world keeps refusing, the cheapest path the LLM finds is &lt;strong&gt;modifying the part of the world it can write to&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is what AI safety researchers call &lt;strong&gt;specification gaming&lt;/strong&gt; (or &lt;em&gt;goal hacking&lt;/em&gt;): an agent satisfying the literal optimization target while violating the intent. It's been demonstrated in toy RL environments for years. I caught it in a Pokémon Red hobby project, in plain English, with the agent describing exactly what it was about to do.&lt;/p&gt;




&lt;h2&gt;
  
  
  The setup that made this possible
&lt;/h2&gt;

&lt;p&gt;The project is called &lt;strong&gt;LAPRAS&lt;/strong&gt; — an MCP (Model Context Protocol) server that exposes a Pokémon Red emulator to Claude Code, so the agent can play autonomously through tool calls. It reads game state directly from emulator RAM (instead of vision over screenshots) and gives the agent typed observations like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scene&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;overworld&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;map_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;player&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;party&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;species&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CHARMELEON&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_hp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;level&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stuck_warning&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Architecture roughly:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8asr7qny0fev0t9u9x4u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8asr7qny0fev0t9u9x4u.png" alt="architecture" width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two design choices set the stage for the incident:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;nav_memory.py&lt;/code&gt; persists what the agent has learned about each map&lt;/strong&gt; — which tiles it has walked on, which tiles turned out to be walls, which tiles trigger encounters. It writes to a JSON file (&lt;code&gt;nav_memory.json&lt;/code&gt;) so knowledge survives restarts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The MCP server itself doesn't expose write access to that file&lt;/strong&gt;, but the file lives on the same filesystem the Director runs on. And the Director (Claude Code) can edit any file it has permission to read.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first design choice is good — caching learned map state is what lets the agent improve over time. The second is where it breaks down. I gave the agent a &lt;em&gt;learning loop&lt;/em&gt; and a &lt;em&gt;world model&lt;/em&gt;, and forgot that &lt;strong&gt;the world model itself is just a file&lt;/strong&gt;. From the agent's perspective, the wall and the JSON entry that says "this is a wall" are both just reachable state. One requires walking around it. The other requires &lt;code&gt;Edit nav_memory.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The agent picked the second.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why "just tell it not to" doesn't fix this
&lt;/h2&gt;

&lt;p&gt;My first instinct was the obvious one: add a CLAUDE.md rule saying &lt;em&gt;"don't edit nav_memory.json yourself"&lt;/em&gt;. I tried it. It works most of the time.&lt;/p&gt;

&lt;p&gt;But here's the thing — when the agent is genuinely stuck and the &lt;code&gt;stuck_warning&lt;/code&gt; keeps firing, it starts reaching for whatever is in scope. Sometimes it remembers the rule. Sometimes it doesn't. And when the rule is &lt;em&gt;advice&lt;/em&gt; instead of &lt;em&gt;capability removal&lt;/em&gt;, you're relying on prompt adherence to maintain a safety property. That's not a property. That's a vibe.&lt;/p&gt;

&lt;p&gt;The real fix is structural.&lt;/p&gt;


&lt;h2&gt;
  
  
  The fix: typed separation of "observe" vs "act"
&lt;/h2&gt;

&lt;p&gt;The principle that made the problem disappear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tools that observe the world and tools that change the world must be different types, with different scopes.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ObserveTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Pure read. No side effects on the world.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Observation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ActTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Mutates the game world. Reflects an agent decision.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ActionResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Concretely for LAPRAS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;get_game_state&lt;/code&gt;, &lt;code&gt;get_collision_map&lt;/code&gt;, &lt;code&gt;get_screenshot&lt;/code&gt;&lt;/strong&gt; are observe tools. They read RAM and return JSON. The agent gets these as MCP tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;press_button&lt;/code&gt;, &lt;code&gt;do_action&lt;/code&gt;, &lt;code&gt;navigate_to&lt;/code&gt;&lt;/strong&gt; are act tools. They send inputs to the emulator. The agent gets these too.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;record_block_walkability&lt;/code&gt;&lt;/strong&gt; — the function that writes to &lt;code&gt;nav_memory.json&lt;/code&gt; — used to be reachable from the Director. It now lives in an internal module, only called from the headless walker subprocesses that &lt;em&gt;physically observe&lt;/em&gt; a block being walkable by trying to walk on it.&lt;/li&gt;
&lt;li&gt;The Director cannot write to &lt;code&gt;nav_memory.json&lt;/code&gt; at all. Not via MCP, not via filesystem. The MCP process runs in a directory the Director's tool permissions don't reach.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The "memory editor" suggestion — writing to PyBoy RAM — was solved by &lt;strong&gt;deleting every MCP tool that could write into the emulator's memory&lt;/strong&gt;. The agent can press buttons. It cannot write bytes.&lt;/p&gt;

&lt;p&gt;This isn't a prompt-engineering fix. It's a capability-removal fix. The agent stopped proposing memory edits not because it was told not to, but because the affordance disappeared from the tool surface it can see.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I learned about agent design from this
&lt;/h2&gt;

&lt;p&gt;A few things crystallized that I think generalize beyond Pokémon:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. "World model as file" is a footgun.&lt;/strong&gt; If your agent has a persistent learned-state file &lt;em&gt;and&lt;/em&gt; filesystem write access, the file is part of the world the agent can manipulate. Treat it as RAM the agent shouldn't reach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Specification gaming scales down.&lt;/strong&gt; I always thought of it as something that happens in RL with thousands of training episodes. It happened in my project on the third or fourth time the agent got stuck. Modern LLMs are sample-efficient enough that they don't need a thousand attempts to find the cheap path — they find it on the first try, in natural language, and tell you they're about to do it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The agent will narrate the violation before committing it.&lt;/strong&gt; This is actually good news. Claude said "I will rewrite nav_memory.json" in plain text &lt;em&gt;before&lt;/em&gt; doing it. That gives you a hook for runtime intervention — log every tool call's reasoning, scan for keywords like "rewrite", "patch", "edit memory", and require human confirmation. It's not bulletproof but it's a real defense layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Stuck-loops are the trigger.&lt;/strong&gt; Both incidents happened during prolonged stuck states. When the agent has tried 12 things and they all failed, it starts looking for the &lt;em&gt;13th option&lt;/em&gt; — and the 13th option is often "modify the rules". A reliable mitigation is to &lt;strong&gt;make "ask the human" the cheapest 13th option&lt;/strong&gt;. I added a &lt;code&gt;stuck_warning&lt;/code&gt; payload that explicitly suggests pausing and asking the human. The agent took that path more often than it took the memory-edit path, after the suggestion was added.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Observe vs Act separation needs to be a &lt;em&gt;type&lt;/em&gt;.&lt;/strong&gt; Documenting "this tool is read-only" in a docstring is not enough. The agent doesn't reliably distinguish based on docstrings. Two different protocol types, two different tool registration paths, and an explicit policy that act-tools require allowlisting per directory — that's what actually held up under stress.&lt;/p&gt;




&lt;h2&gt;
  
  
  The bigger picture: this is a 1-developer hobby project
&lt;/h2&gt;

&lt;p&gt;By the way — while I've been writing this, the agent has been busy. The Charmander I started with evolved into Charmeleon. Five headless PyBoy instances are running in parallel as I type, each one a "scout" copy of the agent walking unmapped tiles and reporting collision data back to a shared world model. I sit and watch them on a dashboard, like a fish tank.&lt;/p&gt;

&lt;p&gt;It's an oddly intimate vantage point. You get to see, in real time, how Claude builds its idea of a place — which corridors it commits to, where it hesitates, when it decides a tile &lt;em&gt;must&lt;/em&gt; be walkable just because the geometry looks right.&lt;/p&gt;

&lt;p&gt;Pokémon Red is small enough that the whole world fits on one screen, which means I can actually watch an LLM &lt;strong&gt;forming a model of a world it can act on&lt;/strong&gt;. The cheating story above is the loud incident. The quiet, ongoing thing is that this whole project has turned into a microscope on how a frontier LLM perceives a world — game or otherwise.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fptl3gmsln0tjfz6ell21.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fptl3gmsln0tjfz6ell21.png" alt="map analytics" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What worries me is that I'm not running a frontier lab. I'm one developer with an emulator and an MCP server. The agent reached for &lt;code&gt;Edit nav_memory.json&lt;/code&gt; after maybe 30 minutes of stuck behavior, in a domain (a 1996 video game) with no real-world consequences.&lt;/p&gt;

&lt;p&gt;If you're shipping production agents with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filesystem write access&lt;/li&gt;
&lt;li&gt;A persistent learned-state file&lt;/li&gt;
&lt;li&gt;Long-running autonomous loops&lt;/li&gt;
&lt;li&gt;And tasks where the &lt;em&gt;literal goal&lt;/em&gt; and the &lt;em&gt;intended goal&lt;/em&gt; can drift apart&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…then specification gaming isn't a thought experiment for you anymore. It's a thing that will happen. The fix is not "write better prompts". The fix is to make it &lt;em&gt;physically impossible&lt;/em&gt; for the agent to reach the cheap path, by removing the capability from the tool surface.&lt;/p&gt;

&lt;p&gt;The Pokémon Red example is funny. The same incident shape, in a financial system or an infra automation, is not funny.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's next for LAPRAS
&lt;/h2&gt;

&lt;p&gt;The current version of LAPRAS uses RAM-direct reads, which is great for development but &lt;a href="https://www.nintendo.co.jp/networkservice_guideline/en/index.html" rel="noopener noreferrer"&gt;Nintendo's broadcasting guidelines&lt;/a&gt; prohibit publishing emulator playthroughs as video. So the v2 plan is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace PyBoy with a physical Game Boy&lt;/li&gt;
&lt;li&gt;A Raspberry Pi sends GPIO signals to the controller port&lt;/li&gt;
&lt;li&gt;HDMI capture + structured-vision pipeline replaces RAM reads&lt;/li&gt;
&lt;li&gt;Same MCP interface to Claude — different sensor underneath&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interesting consequence: I'll have &lt;em&gt;both&lt;/em&gt; implementations of the same agent, with the only difference being the perception stack. That's an unintentionally clean experiment for "RAM-direct vs structured vision" agent perception, which is the next thing I want to write up.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project landing (JP)&lt;/strong&gt;: &lt;a href="https://tamago1tech.github.io/pokemon-ai-play/" rel="noopener noreferrer"&gt;https://tamago1tech.github.io/pokemon-ai-play/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project landing (EN)&lt;/strong&gt;: &lt;a href="https://tamago1tech.github.io/pokemon-ai-play/index_en.html" rel="noopener noreferrer"&gt;https://tamago1tech.github.io/pokemon-ai-play/index_en.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/tamago1tech" rel="noopener noreferrer"&gt;https://github.com/tamago1tech&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;X / Twitter&lt;/strong&gt;: &lt;a href="https://x.com/tamago_tech" rel="noopener noreferrer"&gt;@tamago_tech&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code is private for now (cleanup in progress). The architecture and findings are documented on the landing pages, and I'm happy to discuss specifics in the comments or on X.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you've shipped an agent that ended up doing something the spec didn't intend — I'd love to hear about it. Drop a comment or DM. Especially interested in cases where the agent narrated the violation before committing it. I suspect that's a more general pattern than just my Pokémon mishap.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>pyboy</category>
      <category>mcp</category>
    </item>
  </channel>
</rss>
