Skip to the page
It's Decomplicated
Nintendo, 1989

Game Boy decomp guide

A free recompiler gets most games running fast. A port-ready source still takes months.

What this system is like

Game Boy games are small. The reviewed games use ROMs from 32 KB (Tetris) to 1 MB (Pokemon Red). The chip is the Sharp SM83, a simple 8-bit CPU. That makes this one of the easiest systems to start on.

For Path A, a free tool called gb-recompiled does most of the work. Its gbrecomp program turns a ROM into C code plus a runtime. A runtime is the code that stands in for the console. Six of the twelve reviewed projects used it.

Path B is different here. Game Boy games were written by hand in assembly, not in C. So there is no C to match. The community instead builds a byte-matching assembly listing with RGBDS, like pret/pokered. A port then means rewriting the game routine by routine, with tests.

Recomp work runs on Windows or in WSL. The disassembly path is smoothest in WSL. Expect days to weeks for Path A, and many months for Path B.

The games were assembly, not C

Nintendo's kit was an assembler called ISAS. So there is no original C compiler to match. On this system, a full decomp is a labeled assembly listing that rebuilds the same bytes.

Banks hide the real address

Only two 16 KB windows of ROM are visible at once. The same address can mean different code in different banks. Every tool and note must name a function as bank plus address, like 03:47f2.

A ready-made recompiler exists

gbrecomp turns a ROM into a C project in one command. It also ships an interpreter as a safety net. You spend your time on missed code and runtime bugs, not on the tool. Its README calls it experimental and makes no promise that every game works.

Code hides behind jump tables

Games jump through tables and rst calls. Some code is copied into RAM and runs there. Static analysis misses these spots. Real play logs fill the gaps.

Strong free references

Pan Docs explains the hardware. SameBoy passes the main hardware test ROMs. Many games already have byte-matching disassemblies from pret and others. Check for one before you start.

Two paths

Path A

Get it running on PC

You run gbrecomp on your own ROM. It writes a C project and copies in its runtime. You build it with CMake and SDL2. Then you fix missed code one address at a time. You check each fix with the tool's built-in differential test.

Go to the steps

Path B

Full decomp for porting

Game Boy games were assembly, so the matching source is labeled assembly. You start with mgbdis, which writes RGBDS files that rebuild the exact ROM. Then you split code from data, name every routine and document it. Last, you port the game by rewriting each routine in C or Rust. A byte-level test proves each rewrite. No reviewed project built a Game Boy disassembly from zero with AI. So the first half of this path has no AI track record yet.

Go to the steps

Path A: Get it running on PC

You run gbrecomp on your own ROM. It writes a C project and copies in its runtime. You build it with CMake and SDL2. Then you fix missed code one address at a time. You check each fix with the tool's built-in differential test.

Method: static recompilation

Pick this first. It gives you a playable PC build in days to weeks. Pick it even if you want Path B later, because the function list helps there too.

  1. Pick the game and write the scope

    You pin down the exact ROM and goal. A different revision is a different program. You also look for prior work. A disassembly or a symbol file saves weeks.

    • Hash your own dump in WSL: sha1sum roms/game.gb. For CRC32, run python3 -c "import zlib,sys;print(hex(zlib.crc32(open(sys.argv[1],'rb').read())))" roms/game.gb.
    • Search for an existing disassembly on pret.github.io and GitHub. Search RecompLauncher for an existing recomp.
    • Read the header byte at $0147 to learn the MBC type. Pan Docs lists the values.
    • Write SCOPE.md: game, revision, SHA-1, CRC32, size, goal, technique, first milestone, out-of-scope list.
    Prompt for Claude
    GOAL: Draft SCOPE.md for a Game Boy static recomp of <GAME> (<REGION> <REVISION>).
    READ FIRST: the ROM header bytes $0100-$014F of `<ABSOLUTE_PATH_TO_ROM>` (read only), https://gbdev.io/pandocs/The_Cartridge_Header.html, https://pret.github.io/
    FENCE: Create only `SCOPE.md` and `notes/prior-work.md`. Do not copy or move the ROM. Do not write code.
    CHECK: Run `sha1sum <ABSOLUTE_PATH_TO_ROM>` and paste it. Done means SCOPE.md has the game, revision, SHA-1, CRC32, size in bytes, MBC type from byte $0147, goal, technique (gb-recompiled), first milestone and its check, and an out-of-scope list.
    BUDGET: Stop after 30 minutes of searching for prior work.
    IF BLOCKED: Stop. Do not guess a revision or a hash. Tell me what is missing.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: paste the sha1sum output and the header fields. 3) Files changed. 4) Prior work found, with links. 5) New parking-lot items.
    Done whenSCOPE.md names the exact ROM by SHA-1 and size, and you approved it.

    Proof this works: TetrisGBRecomp, DK94 Recomp, https://gbdev.io/pandocs/MBCs.html

  2. Set up the repo and the recompiler

    You build gbrecomp and lay out a small repo. The repo holds only your config and code. The ROM and the generated C stay out of git. You also write one check command.

    • In WSL: sudo apt install build-essential cmake ninja-build libsdl2-dev git python3.
    • Add the tool as a pinned submodule: git submodule add https://github.com/arcanite24/gb-recompiled.
    • Build it: cmake -G Ninja -S gb-recompiled -B gb-recompiled/build then ninja -C gb-recompiled/build.
    • Add *.gb, *.gbc, roms/, output/ and logs/ to .gitignore before the first commit.
    • Write tools/check.sh. It regenerates, builds, and runs --headless --limit-frames 600.
    • Write CLAUDE.md and PROGRESS.md.
    Prompt for Claude
    GOAL: Make one command, `tools/check.sh`, that regenerates, builds and smoke-runs the recomp of <GAME>.
    READ FIRST: `SCOPE.md`, `gb-recompiled/README.md`, `gb-recompiled/AGENTS.md` (section "Required validation for generated behavior").
    FENCE: Edit only `tools/check.sh`, `.gitignore`, `CLAUDE.md`, `PROGRESS.md`. Do not edit anything inside `gb-recompiled/`. Do not add features or tools I did not ask for.
    CHECK: Run `bash tools/check.sh`. Done means it runs `gbrecomp <ABSOLUTE_PATH_TO_ROM> -o output/game`, builds with CMake and Ninja, runs `--headless --limit-frames 600`, and exits 0. Then break the build on purpose and show the script exits non-zero.
    BUDGET: Stop after 3 failed tries at the same error.
    IF BLOCKED: Stop. Do not work around a missing package. Tell me the exact error and the command.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: paste both check outputs. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whenbash tools/check.sh exits 0, and exits non-zero when you break the build.

    Proof this works: TetrisGBRecomp, Bigodao, https://github.com/arcanite24/gb-recompiled

  3. Map the ROM

    You find the code that static analysis will miss. That means jump tables, the bank-switch routine and code copied into RAM. You write each one down with its bank and address. This list becomes the recompiler's hints.

    • Install Ghidra 11.3.2 with JDK 21. Add the GhidraBoy zip built for 11.3.2 through File, Install Extensions. Version 11.3.2 is the one release that both GhidraBoy and GhidraMCP 1.4 support.
    • Import the ROM with the GhidraBoy loader. It maps each bank as an overlay.
    • GhidraBoy does not know which bank a call into $4000-$7FFF goes to. Its README says you must set the bank by hand for each such call.
    • If a disassembly exists, build its .sym file and pass it with --symbols.
    • List interrupt vectors ($0040 to $0060), rst dispatchers, the bank-switch routine and any HRAM code, like the OAM DMA routine.
    • Save it all in notes/map.md with one line per address and a reason.
    Prompt for Claude
    GOAL: Write `notes/map.md`: every dispatcher, bank-switch routine and RAM-copied routine in <GAME>, as bank:address with evidence.
    READ FIRST: `SCOPE.md`, Ghidra project `<GHIDRA_PROJECT>` with GhidraBoy loaded, https://gbdev.io/pandocs/Memory_Map.html
    FENCE: Edit only `notes/map.md`. Do not edit generated C. Do not change recompiler code.
    CHECK: For each entry, paste the Ghidra listing lines that prove it (address, bytes, instruction). Done means the file lists the five interrupt vectors, each rst handler used, the bank-switch routine, every jump table found, and every routine copied to RAM, each with proof.
    BUDGET: Stop after 90 minutes, or after 20 minutes with no new entry.
    IF BLOCKED: Stop. If Ghidra or GhidraBoy is not loaded, say so and stop. Do not decode bytes by hand.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: counts per entry type. 3) Files changed. 4) Addresses you could not explain. 5) New parking-lot items.
    Done whennotes/map.md lists every vector, dispatcher, bank switch and RAM routine, each with a Ghidra listing as proof.

    Proof this works: DK94 Recomp, WarioBlast Recomp, TetrisGBRecomp, https://github.com/Gekkio/GhidraBoy

  4. Boot to the first frame

    You run the recompiler on the whole ROM and build it. The game should open a window and reach its title screen. You save frame dumps as proof. This is the smallest full run.

    • Generate: gb-recompiled/build/bin/gbrecomp roms/game.gb -o output/game.
    • Build: cmake -G Ninja -S output/game -B output/game/build then ninja -C output/game/build.
    • Make the log folder first: mkdir -p logs. The runtime does not create it.
    • Run headless with frame dumps: ./output/game/build/game --headless --limit-frames 600 --dump-frames 60,300,600 --screenshot-prefix logs/shot. It writes logs/shot_00060.ppm, logs/shot_00300.ppm and logs/shot_00600.ppm.
    • Open the dumps and compare them by eye with the same frames in SameBoy.
    • Keep output/game/*_metadata.json. It lists every function by bank and address.
    Prompt for Claude
    GOAL: Show <GAME> reaching its title screen in the recompiled build.
    READ FIRST: `SCOPE.md`, `notes/map.md`, `gb-recompiled/RUNTIME.md` (Execution options).
    FENCE: Edit only `tools/check.sh` and `PROGRESS.md`. Never edit files under `output/`. Generated C is a build artifact.
    CHECK: Run `bash tools/check.sh`, then `mkdir -p logs && ./output/game/build/game --headless --limit-frames 600 --dump-frames 60,300,600 --screenshot-prefix logs/shot`. Done means it exits 0, `logs/shot_00300.ppm` exists, and that frame shows the title screen.
    BUDGET: Stop after 3 failed builds with the same error.
    IF BLOCKED: Stop. Do not patch generated C. Tell me the first error line, the command, and what you tried.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the run output and the paths of the three frame files. 3) Files changed. 4) Interpreter fallback lines seen in the log. 5) New parking-lot items.
    Done whenThe headless run exits 0 and test -s logs/shot_00300.ppm passes. Then you confirm by eye that the frame is the title screen.

    Proof this works: Kirby's Dream Land Recomp, Super Mario Land 3: Wario Land — Recomp, https://github.com/arcanite24/gb-recompiled/blob/main/RUNTIME.md

  5. Close the code gaps

    Code the analyzer missed runs on the built-in interpreter instead. That still works, but it hides gaps. You log each fallback address, prove it is real code, and add it as an entry point. You repeat until a full play log shows no fallbacks.

    • Record a route through the game: ./output/game/build/game --record-input logs/route1.input.
    • Replay it and log fallbacks: ./output/game/build/game --headless --limit-frames <N> --input "$(cat logs/route1.input)" --log-file logs/interp.log --log-frame-fallbacks --report-interpreter-hotspots. Set <N> to the route's length in frames, so the run stops.
    • Summarize: python3 gb-recompiled/tools/summarize_interpreter_log.py logs/interp.log. When it prints No interpreter fallback recorded, the route is clean.
    • Check each address in Ghidra. Then regenerate with --add-entry-point <BANK>:<ADDR>. The tool reads the address as hex. It reads the bank as decimal, or as hex with 0x. So write bank 10 as 10 or 0x0a. A leading zero, as in 08, is read the wrong way.
    • For more coverage, use the trace tool. It must run from inside the tool's own folder: cd gb-recompiled && python3 tools/run_ground_truth.py ../roms/game.gb --output-dir ../output/game-trace --frames 18000. It needs PyBoy. It deletes and remakes its output folder. It samples only one address per frame, so treat its hits as hints.
    Prompt for Claude
    GOAL: Remove the interpreter fallback at <BANK:ADDRESS> from the replay of `logs/<ROUTE>.input`.
    READ FIRST: `notes/map.md`, `logs/interp.log` (only lines for <BANK:ADDRESS>), `gb-recompiled/GROUND_TRUTH_WORKFLOW.md`.
    FENCE: Edit only the `--add-entry-point` list in `tools/check.sh` and `notes/map.md`. Never edit generated C. Do not add an address you have not proven is code.
    CHECK: Run `bash tools/check.sh`, replay with `--headless --limit-frames <N> --input "$(cat logs/<ROUTE>.input)" --log-file logs/interp.log --log-frame-fallbacks`, then run `python3 gb-recompiled/tools/summarize_interpreter_log.py logs/interp.log`. Done means <BANK:ADDRESS> is gone from the summary and no new fallback appears.
    BUDGET: Stop after 3 tries, or 30 minutes.
    IF BLOCKED: Stop. If the address is RAM code or data, do not force it in. Tell me what Ghidra shows there.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the Ghidra lines and the before and after summary. 3) Files changed. 4) Fallbacks left. 5) New parking-lot items.
    Done whenFor every recorded route, summarize_interpreter_log.py prints No interpreter fallback recorded.

    Proof this works: TetrisGBRecomp, DK94 Recomp, WarioBlast Recomp, https://github.com/arcanite24/gb-recompiled/blob/main/GROUND_TRUTH_WORKFLOW.md

  6. Fix runtime bugs with proof

    Now you fix wrong pictures, sound or timing. One bug per session. Each fix needs proof of the cause first. The differential mode compares compiled code with the interpreter, step by step.

    • Run the differential check from boot: ./output/game/build/game --differential 500000 --differential-log 100000 --differential-fail-on-fallback.
    • Reproduce the bug with a recorded input file. Stop just before it and save the machine: --headless --limit-frames <N> --input "$(cat logs/<ROUTE>.input)" --dump-state logs/bug.json --save-state-file logs/bug.state.
    • Run the differential check from that point: --differential 500000 --differential-state logs/bug.state --differential-fail-on-fallback.
    • Remember what the differential check proves. It compares compiled code with the tool's own interpreter. Both share the same graphics, sound and timer code, so it cannot catch a bug in those parts.
    • Compare the same moment in SameBoy's debugger. Pan Docs is the first hardware reference.
    • Fix the recompiler or runtime, never the generated C. Regenerate and replay.
    Prompt for Claude
    GOAL: Find and fix the cause of <BUG> seen at frame <N> of `logs/<ROUTE>.input`.
    READ FIRST: `notes/map.md`, `notes/findings.md`, Pan Docs page <PAGE>, the frame dump `logs/<FILE>`.
    FENCE: Edit only `<RUNTIME_OR_RECOMPILER_FILE>` and `notes/findings.md`. Never edit generated C. No game-specific hacks unless I approve them.
    CHECK: Run `bash tools/check.sh`. Replay with `--headless --limit-frames <N> --input "$(cat logs/<ROUTE>.input)" --dump-frames <N> --screenshot-prefix logs/fix --save-state-file logs/bug.state`. Then run `--differential 500000 --differential-state logs/bug.state --differential-fail-on-fallback`. Done means the frame is correct, the differential run passes, and the check script exits 0.
    BUDGET: Stop after 2 failed fixes. Write the cause first; no fix before the cause is proven.
    IF BLOCKED: Stop. Tell me the evidence you have, the guesses you ruled out, and what you need.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: before and after frames and the differential output. 3) Files changed. 4) Cause in one sentence, with addresses. 5) New parking-lot items.
    Done whenThe differential run from logs/bug.state reports no mismatch and no fallback. bash tools/check.sh exits 0. The new frame dump matches SameBoy at the same frame.

    Proof this works: Bigodao, TetrisGBRecomp, https://github.com/arcanite24/gb-recompiled/blob/main/AGENTS.md

  7. Build a regression set

    You turn your recorded routes into tests. Each route has a saved final-state hash. Any change that alters game logic then fails the test. This keeps old fixes fixed.

    • Copy each route's input file out of the ignored logs/ folder: cp logs/route1.input tests/routes/route1.input. Input files hold your button presses, not game data.
    • Save each route's final state: --headless --input "$(cat tests/routes/route1.input)" --limit-frames <N> --dump-state tests/routes/route1.json.
    • If the game has a clock chip (MBC3 RTC), add --rtc-unix-time <SECONDS> so every replay sees the same time.
    • Write tools/regress.sh. It replays every route and compares the state files.
    • Keep extras like widescreen render-only, so the state hash still proves logic is unchanged.
    • Run the full check from a fresh clone before each release.
    Prompt for Claude
    GOAL: Make `tools/regress.sh` replay every route in `tests/routes/` and fail on any state change.
    READ FIRST: `PROGRESS.md`, `gb-recompiled/RUNTIME.md` (--input, --dump-state, --rtc-unix-time).
    FENCE: Edit only `tools/regress.sh`, `tests/` and `PROGRESS.md`. Do not change expected state files except for a route I name.
    CHECK: Run `bash tools/regress.sh` on a clean clone, with the ROM path passed in. Done means every route passes. Then change one byte of one expected file and show the script fails.
    BUDGET: Stop after 3 failed tries.
    IF BLOCKED: Stop. Tell me which route is not repeatable and why.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: both outputs. 3) Files changed. 4) Routes not yet covered. 5) New parking-lot items.
    Done whenbash tools/regress.sh passes on a clean clone and fails when an expected file is changed.

    Proof this works: DK94 Recomp, WarioBlast Recomp, G1R Deluxe

  8. Build for Windows and ship without the game

    You build a Windows program and package it. The package must hold no ROM bytes and no generated C files. The program checks the player's own ROM by hash. Then you test it from a clean folder. Know this first: by default gbrecomp writes the whole ROM into a file named <NAME>_rom.c and builds it into the program. And any built program still holds the game's code, turned into machine code. DK94 Recomp and WarioBlast Recomp avoid that by recompiling the player's ROM on the player's PC at start.

    • Remove the built-in ROM. Bigodao drops *_rom.c from its CMake build, loads the player's ROM at start, and fails the build if rom_data is still used. Plan this as runtime work.
    • Install MSYS2. In its UCRT64 shell run pacman -S mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-ninja mingw-w64-ucrt-x86_64-SDL2.
    • Build with a clean PATH that has only MSYS2 and Windows folders. Other toolchains on PATH broke builds.
    • Gate the ROM by CRC32 or SHA-256 at start. Check the baked value matches your dump.
    • Write tools/check_release.py. It fails if any 32-byte run of the ROM appears in the package. WarioBlast Recomp uses this rule.
    • Copy the package to a fresh folder on another PC and run it.
    Prompt for Claude
    GOAL: Produce a Windows release zip of the <GAME> recomp that runs from a clean folder and holds no ROM data.
    READ FIRST: `SCOPE.md`, `PROGRESS.md`, `tools/check_release.py`, the generated `CMakeLists.txt` (find `<NAME>_rom.c`).
    FENCE: Edit only `tools/package.sh`, `tools/check_release.py` and `PROGRESS.md`. Do not put the ROM, generated C, or files under `output/` in the zip. If the program still builds in `<NAME>_rom.c`, stop and report BLOCKED.
    CHECK: Run `python3 tools/check_release.py dist/<ZIP>`. Done means it prints zero ROM matches, and the unzipped program starts with the correct ROM and refuses a wrong one.
    BUDGET: Stop after 3 failed packaging tries.
    IF BLOCKED: Stop. Tell me which DLL or file is missing, with the exact error.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the scan output and both launch results. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whenThe release scan finds zero ROM bytes, and the unzipped build runs on a clean PC with your ROM.

    Proof this works: TetrisGBRecomp, WarioBlast Recomp, Bigodao, https://packages.msys2.org/base/mingw-w64-SDL2

Path B: Full decomp for porting

Game Boy games were assembly, so the matching source is labeled assembly. You start with mgbdis, which writes RGBDS files that rebuild the exact ROM. Then you split code from data, name every routine and document it. Last, you port the game by rewriting each routine in C or Rust. A byte-level test proves each rewrite. No reviewed project built a Game Boy disassembly from zero with AI. So the first half of this path has no AI track record yet.

Method: matching disassembly, then a port by rewrite

Pick this when you want the game on other systems, or deep mods. First check pret and GitHub for an existing disassembly. If one exists, skip to the port steps.

  1. Look for an existing disassembly

    Many Game Boy games already have byte-matching disassemblies. Using one saves months. If none exists, you plan your own. Either way, you write the scope.

    • Check pret.github.io and search GitHub for "<GAME> disassembly".
    • Check if an existing one builds your exact revision. Compare its listed SHA-1 with sha1sum roms/game.gb.
    • Write SCOPE.md: revision, hash, goal (port to which system), language for the port, and the check.
    Prompt for Claude
    GOAL: Find prior disassembly work for <GAME> and draft SCOPE.md for Path B.
    READ FIRST: https://pret.github.io/, GitHub search results for "<GAME> disassembly", my ROM hash `<SHA1>`.
    FENCE: Create only `SCOPE.md` and `notes/prior-work.md`. Do not clone or download ROMs.
    CHECK: For each disassembly found, list its URL, last commit date, the SHA-1 it builds, and whether that SHA-1 equals `<SHA1>`. Done means SCOPE.md names the starting point (existing repo or empty) and the port target.
    BUDGET: Stop after 45 minutes.
    IF BLOCKED: Stop. Tell me what you could not find or check.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the table of repos and hashes. 3) Files changed. 4) Your recommended start. 5) New parking-lot items.
    Done whenSCOPE.md names a starting repo, or says none exists, and you approved it.

    Proof this works: Six Golden Coins, G1R Deluxe, https://github.com/pret/pokered

  2. Make a ROM that rebuilds byte for byte

    You turn the ROM into assembly files that rebuild it exactly. This is your first check. From now on, every change must keep the hash the same.

    • In WSL, install the basics: sudo apt install make git python3.
    • Install RGBDS 1.0.4: download rgbds-linux-x86_64.tar.xz, then mkdir rgbds && tar xf rgbds-linux-x86_64.tar.xz -C rgbds && cd rgbds && sudo ./install.sh. Check it with rgbasm -V.
    • Get mgbdis: git clone https://github.com/mattcurrie/mgbdis.
    • Disassemble: python3 mgbdis/mgbdis.py roms/game.gb. It writes to a new disassembly/ folder.
    • Build: cd disassembly && make. The made makefile writes game.gb.
    • Write make compare. It builds and checks sha1sum against the hash in SCOPE.md.
    Prompt for Claude
    GOAL: Make `make compare` rebuild <GAME> from RGBDS source with the same SHA-1 as my ROM.
    READ FIRST: `SCOPE.md`, `mgbdis/README.md`, https://rgbds.gbdev.io/install/linux
    FENCE: Edit only `Makefile` and `tools/`. Do not edit `game.sha1`. Do not commit the ROM; it stays at `<ABSOLUTE_PATH_TO_ROM>`.
    CHECK: Run `make compare`. Done means it prints OK with the SHA-1 from SCOPE.md. Then change one byte in one .asm file and show `make compare` fails.
    BUDGET: Stop after 3 failed tries.
    IF BLOCKED: Stop. Tell me the exact error and the RGBDS version from `rgbasm -V`.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: both outputs. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whenmake compare prints OK, and fails when one byte is changed.

    Proof this works: https://github.com/mattcurrie/mgbdis, https://github.com/Kak2X/wl, https://github.com/pret/pokered/blob/master/INSTALL.md

  3. Separate code from data and list every routine

    A raw disassembly guesses where code starts. Wrong guesses turn data into fake code. You feed it real evidence of what ran. Then you build the routine ledger.

    • Record which addresses ran during play. Use a PyBoy trace or the gbrecomp metadata file from Path A. The Kak2X/wl disassembly started from a code/data log made by a debug emulator.
    • Write them into a symbol file as .code blocks. Mark tables with .data, text with .text and tile graphics with .image. Entries look like 03:47f2 Read_Joypad and 0d:4800 .data:200, all in hex.
    • mgbdis only reads the symbol file if it sits next to the ROM with the same name: roms/game.sym for roms/game.gb. Keep your master copy in the repo as notes/game.sym and copy it over. Do not keep it in disassembly/, because make clean deletes disassembly/game.sym.
    • Re-run with python3 mgbdis/mgbdis.py roms/game.gb --overwrite. Without --overwrite it stops, because the folder exists. Run make compare again.
    • Do all re-runs before you hand-edit any .asm file. A later re-run with --overwrite would replace your edits.
    • Write ledger/routines.csv: bank, address, size, name, status.
    Prompt for Claude
    GOAL: Build `ledger/routines.csv` with every routine in <GAME>, and a `notes/game.sym` that marks code, data, text and graphics.
    READ FIRST: `SCOPE.md`, `mgbdis/README.md` (Symbol Files), `<PATH_TO>_metadata.json` from the recomp (use a script, do not read it whole), `logs/<TRACE>`.
    FENCE: Edit only `notes/game.sym`, its copy at `<ROM_DIR>/game.sym`, `ledger/routines.csv` and the regenerated `disassembly/` folder. Do not hand-edit any .asm file in this task.
    CHECK: Run `python3 mgbdis/mgbdis.py <ROM_DIR>/game.gb --overwrite`, then `make compare`. Done means it prints OK, and every routine in the metadata file appears in the ledger with bank, address and status.
    BUDGET: Stop after 2 hours or 3 failed compares.
    IF BLOCKED: Stop. List the address ranges you cannot class as code or data.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the compare output and ledger row counts. 3) Files changed. 4) Unknown ranges. 5) New parking-lot items.
    Done whenmake compare prints OK and ledger/routines.csv lists every known routine with a status.

    Proof this works: https://github.com/mattcurrie/mgbdis, https://github.com/arcanite24/gb-recompiled/blob/main/AGENTS.md, https://github.com/Kak2X/wl

  4. Finish one routine end to end

    You take one small routine all the way. You name it and its RAM, swap raw numbers for labels, and write a comment. The ROM must still match. This proves the whole loop works.

    • Pick a short routine, like the joypad reader.
    • Use the SameBoy or BGB debugger to watch which RAM it writes.
    • Name the routine, its labels and its RAM in ram.asm. Use hardware.inc names for I/O registers.
    • Run make compare. Set the ledger status to named.
    Prompt for Claude
    GOAL: Fully name and document routine <BANK:ADDRESS> in the <GAME> disassembly.
    READ FIRST: `ledger/routines.csv` (row for <BANK:ADDRESS>), the routine's .asm file, `notes/ram-map.md`.
    FENCE: Edit only the routine's .asm lines, `ram.asm`, `notes/ram-map.md` and its ledger row. Do not change any byte the build emits.
    CHECK: Run `make compare`. Done means OK, no raw ROM or RAM address is left inside the routine, and the ledger row says `named`.
    BUDGET: Stop after 3 failed compares or 30 minutes.
    IF BLOCKED: Stop. Say which value you cannot explain and what you checked.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: compare output and the diff. 3) Files changed. 4) Names you are unsure of. 5) New parking-lot items.
    Done whenmake compare prints OK and the routine has no raw addresses left.

    Proof this works: https://github.com/zladx/LADX-Disassembly, https://bgb.bircd.org/

  5. Name every routine, bank by bank

    Now you repeat the unit loop many times. Workers each take routines from one bank. Easy leaf routines go first. Each change must keep make compare at OK.

    • Sort the ledger: leaf routines first, then routines whose callees are all named.
    • Give each worker one bank file and its own git worktree.
    • Run make compare after every routine, and again after each merge.
    • Record dead ends in notes/findings.md so nobody repeats them.
    Prompt for Claude
    GOAL: Name and document the next <N> `raw` routines in bank <BANK>, one at a time.
    READ FIRST: `ledger/routines.csv` (bank <BANK> rows only), `notes/ram-map.md`, `notes/findings.md`.
    FENCE: Edit only `<BANK_FILE>.asm`, `ram.asm`, `notes/ram-map.md` and ledger rows for bank <BANK>. Work in worktree `<ABSOLUTE_WORKTREE_PATH>`. Do not touch other banks.
    CHECK: Run `make compare` after each routine. Done means OK after each one and each finished row says `named`.
    BUDGET: Skip a routine after 3 failed tries and mark it `hard`.
    IF BLOCKED: Stop. Tell me which routine and why.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the last compare output. 3) Files changed. 4) Routines named, routines marked hard. 5) New parking-lot items.
    Done whenEvery ledger row says named or hard, and make compare prints OK on the merged branch.

    Proof this works: https://github.com/pret/pokered, https://github.com/pret/pokecrystal

  6. Pull out the graphics and tables

    Ports need the art and data as real files. You turn tile data into PNG images. The build turns them back into bytes with rgbgfx. The hash must not change.

    • Find each tile block in the ledger and the .sym file.
    • Easiest way, before any hand edits: mark the block as .image in notes/game.sym, for example 02:791a .image:500:w128. Re-run mgbdis with --overwrite. It writes gfx/<LABEL>.png and a make rule that runs rgbgfx.
    • After hand edits, do it by hand. Write the block out as PNG. Swap its bytes for an INCBIN of the built file. Add a make rule that runs rgbgfx on it.
    • Do the same for level, text and music tables as .asm data with labels.
    • Run make compare after each block.
    Prompt for Claude
    GOAL: Move graphics block <LABEL> out of the .asm file into `gfx/<NAME>.png`, built back with `rgbgfx`.
    READ FIRST: `game.sym`, `Makefile`, https://rgbds.gbdev.io/
    FENCE: Edit only `Makefile`, `gfx/<NAME>.png` and the lines for <LABEL>. Do not commit any other ROM-derived file outside `gfx/`.
    CHECK: Run `make clean && make compare`. Done means OK.
    BUDGET: Stop after 3 failed compares.
    IF BLOCKED: Stop. Tell me the bit depth or layout you could not match.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: compare output. 3) Files changed. 4) Blocks left. 5) New parking-lot items.
    Done whenmake clean && make compare prints OK with graphics built from PNG files.

    Proof this works: https://github.com/pret/pokered, https://github.com/gbdev/rgbds, https://github.com/mattcurrie/mgbdis

  7. Harden the disassembly

    You make the build repeatable for anyone. A clean clone plus the user's own ROM must give OK. Game files never enter git. A second session checks the work.

    • Add a CI job that builds the tools and runs the ROM-free checks.
    • Run make compare on a fresh clone with baserom.gb supplied by you.
    • Scan git ls-files for any .gb file or large binary.
    • Have a fresh session re-check ten random named rows.
    Prompt for Claude
    GOAL: Prove the <GAME> disassembly builds from a clean clone and holds no game files.
    READ FIRST: `PROGRESS.md`, `.gitignore`, `Makefile`.
    FENCE: Edit only `.github/workflows/`, `.gitignore` and `PROGRESS.md`.
    CHECK: Clone to `<ABSOLUTE_TEMP_PATH>`, copy in my ROM from `<ABSOLUTE_PATH_TO_ROM>`, run `make compare`. Done means OK, and `git ls-files` lists no .gb, .gbc or .sav file.
    BUDGET: Stop after 3 failed tries.
    IF BLOCKED: Stop. Tell me which file the clean build needs that git lacks.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: both outputs. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whenA clean clone plus your ROM gives make compare OK, and git holds no game files.

    Proof this works: https://github.com/pret/pokered, G1R Deluxe

  8. Port one routine at a time

    Now you rewrite the game in C or Rust. One routine is one ticket. A script slices the routine out of the disassembly. The test sets up memory, runs the new code, and checks the same bytes the assembly writes.

    • Write a slicer script that cuts one routine, with its jump tables and bank switches, into a task file.
    • Keep pending tickets in PORT_QUEUE.json. Move done ones to a separate file.
    • For each ticket, write the new code and a byte-level test. The test must fail if you revert the line under test.
    • Run cargo test (Rust) or your C test runner after each ticket.
    • Keep the original memory layout behind a small conversion layer, so tests can compare bytes.
    Prompt for Claude
    GOAL: Port routine <BANK:ADDRESS> (<NAME>) to <LANGUAGE> with a byte-level test.
    READ FIRST: `tasks/<BANK_ADDRESS>.md` (the slice), at most 4 named source files: <FILES>.
    FENCE: Edit only <PORT_FILE> and <TEST_FILE>. Do not bulk-translate assembly. Do not load `PORT_QUEUE.done.json` or whole data dumps.
    CHECK: Run `<TEST_COMMAND>`. Done means the new test passes, it fails when you revert the ported line, and all older tests still pass.
    BUDGET: After 2 failed compile or fix tries, stop and reply ESCALATE with a short summary.
    IF BLOCKED: Stop. Tell me which instruction or table you could not settle from the slice.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: test output, and output with the line reverted. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whenEvery ticket is closed, and the full test suite passes.

    Proof this works: Six Golden Coins, https://github.com/patricksmill/sml2-rs/blob/main/PORTING.md

  9. Check the port against the real game

    Unit tests prove routines, not the whole game. You add golden runs. The port plays a fixed input and must reach the same points as the original. You compare pictures and RAM. Treat these as a second check, not the main one. Six Golden Coins found capture-based checks unreliable and made its byte-level unit tests the gate.

    • Record input routes in an emulator and save RAM at set frames with PyBoy.
    • Play the same input in the port and save the same RAM fields.
    • Write a compare script that reports each frame and field that differs.
    • Load assets from the player's own ROM at first launch. Check its hash first.
    Prompt for Claude
    GOAL: Make `tools/golden.sh` replay route <ROUTE> in the port and in PyBoy and compare RAM at frames <FRAMES>.
    READ FIRST: `PROGRESS.md`, `notes/ram-map.md`, https://docs.pyboy.dk/
    FENCE: Edit only `tools/golden.sh`, `tools/compare_ram.py` and `tests/golden/`. Do not change the port's game code in this task.
    CHECK: Run `bash tools/golden.sh <ROUTE>`. Done means it prints a per-frame table and exits 0 only when every listed field matches.
    BUDGET: Stop after 3 failed tries.
    IF BLOCKED: Stop. Tell me which frame cannot be lined up and why.
    OTHER PROBLEMS: Write differences you find in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the table. 3) Files changed. 4) Differences found. 5) New parking-lot items.
    Done whenEvery golden route matches the original at every checked frame.

    Proof this works: Six Golden Coins, G1R Deluxe, https://github.com/Baekalfen/PyBoy

Tools you need

ToolWhat it doesHow to get itHow we know
gb-recompiled (`gbrecomp`)
Required both
Turns a Game Boy ROM into a C project with an SDL2 runtime. It also has a fallback interpreter, a differential test and input replay.
Path A Path B
Download `gb-recompiled-windows-x64.zip` or `gb-recompiled-linux-x64.tar.gz` from release v0.1.0, or build: `git clone https://github.com/arcanite24/gb-recompiled.git && cd gb-recompiled && cmake -G Ninja -B build . && ninja -C build` (needs CMake 3.20+, Ninja, SDL2 files and a C11/C++20 compiler)README, RUNTIME.md, AGENTS.md, GROUND_TRUTH_WORKFLOW.md, releases and the flag code in recompiler/src/main.cpp read 2026-11-13; used by Bigodao, TetrisGBRecomp and four omegakatana92 projects. Not run here.
CMake and Ninja
Required both
Build tools. gbrecomp writes a CMake project, and Ninja compiles it.
Path A
WSL: `sudo apt install build-essential cmake ninja-build`. Windows: `pacman -S mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-ninja` in MSYS2gb-recompiled README (CMake 3.20+, Ninja) read 2026-11-13; Ubuntu noble and MSYS2 package pages checked 2026-11-13
SDL2 development files
Required both
The window, sound and controller library the runtime uses.
Path A
WSL: `sudo apt install libsdl2-dev`. Windows: `pacman -S mingw-w64-ucrt-x86_64-SDL2` in MSYS2gb-recompiled README; MSYS2 package page (SDL2 2.32.10) and Ubuntu noble page read 2026-11-13
MSYS2 (UCRT64 GCC)
Helpful Windows
A Windows build shell with GCC. Use it to build the Windows version of your recomp.
Path A
Run the installer from msys2.org, then `pacman -S mingw-w64-ucrt-x86_64-gcc` in the UCRT64 shellmsys2.org read 2026-11-13; TetrisGBRecomp builds with msys2 GCC
Ghidra 11.3.2
Helpful Windows
A free disassembler and decompiler. With GhidraBoy it reads banked Game Boy ROMs. Use 11.3.2, not the newest Ghidra, because the Game Boy add-on stops at 11.4.2 and GhidraMCP 1.4 is built for 11.3.2.
Path A Path B
Install a 64-bit JDK 21. Download `ghidra_11.3.2_PUBLIC_20250415.zip` from the Ghidra 11.3.2 release page and unzip it11.3.2 release assets and README (JDK 21) read 2026-11-13. Newest Ghidra is 12.2 (2026-10-22). mstan/gbrecompiled GHIDRA_SETUP.md uses Ghidra with GhidraBoy.
GhidraBoy
Helpful Windows
A Ghidra add-on for the SM83 CPU. It loads banked ROMs and names the hardware registers.
Path A Path B
Download `ghidra_11.3.2_PUBLIC_20250830_GhidraBoy.zip` from the GhidraBoy releases page. In Ghidra: File, Install Extensions, plus button, pick the zip, restartREADME and release 20250830 read 2026-11-13: repo is archived; supports Ghidra 11.1 to 11.4.2, including 11.3.2; used by mstan/gbrecompiled (TetrisGBRecomp engine)
GhidraMCP
Helpful Windows
An MCP server that lets Claude ask Ghidra for listings, names and cross-references. MCP is the way Claude Code talks to outside tools.
Path A Path B
For Ghidra 11.3.2, use release 1.4: download `GhidraMCP-release-1-4.zip` (it holds the Ghidra plugin and `bridge_mcp_ghidra.py`), install the plugin like GhidraBoy, run `pip install mcp==1.5.0 requests==2.32.3`, then `claude mcp add ghidra -- python <ABSOLUTE_PATH>/bridge_mcp_ghidra.py --ghidra-server http://127.0.0.1:8080/`. Release 2.0 and its `uvx` command need Ghidra 12.1.4, which GhidraBoy does not list as supportedREADME at tag 1.4 and at 2.0, extension.properties at 1.4 (ghidraVersion=11.3.2), requirements.txt and releases read 2026-11-13. The Claude Code command is built from the 1.4 README's bridge arguments and was not tested. mstan/gbrecompiled .mcp.json points Claude at a Ghidra MCP server.
PyBoy
Helpful both
A Game Boy emulator you can drive from Python. Use it for traces, and as a reference for RAM values.
Path A Path B
`pip install pyboy` (in a virtual environment)README and PyPI (2.9.0, Python 3.9+) read 2026-11-13; used by gb-recompiled trace tools and by sml2-rs
SameBoy
Helpful Windows
A very accurate emulator with a text debugger. It has breakpoints, watchpoints and a disassembler.
Path A Path B
Download `sameboy_winsdl_v1.0.5.zip` from the releases page and unzip itREADME and v1.0.5 release read 2026-11-13; gb-recompiled AGENTS.md names SameBoy as the second hardware reference
BGB
Helpful Windows
A Windows emulator with a strong debugger. It loads .sym files, so you see your labels while you step.
Path B
Download the zip from bgb.bircd.org and unzip itbgb.bircd.org read 2026-11-13 (version 1.6.7, Windows and Wine); LADX-Disassembly README points to it
RGBDS 1.0.4
Required both
The Game Boy assembler, linker, header fixer and graphics converter (rgbasm, rgblink, rgbfix, rgbgfx). It rebuilds the ROM from your assembly.
Path B
WSL: download `rgbds-linux-x86_64.tar.xz`, then `mkdir rgbds && tar xf rgbds-linux-x86_64.tar.xz -C rgbds && cd rgbds && sudo ./install.sh`, then check `rgbasm -V`. Windows: unzip `rgbds-win64.zip` into a folder and add that folder to `PATH`Install pages and v1.0.4 release (2026-09-22) read 2026-11-13; pret/pokered INSTALL.md asks for rgbds 1.0.4
mgbdis
Required both
A Python disassembler for Game Boy ROMs. It writes RGBDS files and a makefile that rebuild the ROM.
Path B
`git clone https://github.com/mattcurrie/mgbdis` (needs Python 3.6+ and RGBDS 0.8+)README and mgbdis.py options read 2026-11-13: a second run into the same folder needs --overwrite; the written makefile calls rgbasm, rgblink, rgbfix and rgbgfx and needs make, so run it in WSL
Rust (rustup and cargo)
Helpful both
A language and build tool for the port. Six Golden Coins rewrote its game in Rust.
Path B
WSL: `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`. Windows: run `rustup-init.exe` from rustup.rsrustup.rs read 2026-11-13; Six Golden Coins card (cargo workspace, MSVC toolchain on Windows)

Skills and add-ons

Read any skill before you install it. A skill is a set of instructions that Claude will follow. See Tools and Skills for the full list and safety notes.

GhidraMCP

MCP server

Claude can ask Ghidra what an address really does. The Tetris engine fork makes this its first rule before any crash work.

With Ghidra 11.3.2 and GhidraBoy: install the plugin from `GhidraMCP-release-1-4.zip`, run `pip install mcp==1.5.0 requests==2.32.3`, then `claude mcp add ghidra -- python <ABSOLUTE_PATH>/bridge_mcp_ghidra.py --ghidra-server http://127.0.0.1:8080/`. The 2.0 release and its `uvx` command need Ghidra 12.1.4. Not tested here.

static-recomp-scope-plan

skills.sh

It makes you write down the exact ROM, the scenes to test and the pass marks first. That fits Path A step 1.

npx skills add bgyss/switchrecomp --skill static-recomp-scope-plan -a claude-code

ghidra-headless

skills.sh

It runs Ghidra with no window and saves functions and strings to files. Use it when you do not want an MCP server. It needs GhidraBoy for Game Boy ROMs.

npx skills add trailofbits/skills-curated --skill ghidra-headless -a claude-code

engine-reimplementation

skills.sh

A table of ways to bring a game to new systems, with effort and checks. Read it before you choose how to port in Path B.

npx skills add madpai/game-decomp-compendium --skill engine-reimplementation -a claude-code

verification-before-completion

skills.sh

Claude may not say done without fresh proof. Here that proof is make compare, a zero-fallback log, or a passing route.

npx skills add obra/superpowers --skill verification-before-completion -a claude-code

using-git-worktrees

skills.sh

Keeps each bank worker in its own copy of the repo. Its setup step may run installs, so watch it the first time.

npx skills add obra/superpowers --skill using-git-worktrees -a claude-code

handoff

skills.sh

Writes a short note so a fresh session can carry on. Tell it to save the note inside your project, not in a temp folder.

npx skills add mattpocock/skills --skill handoff -a claude-code

gb-fallback-harvest (write your own)

write-your-own

This is the loop every Game Boy recomp ran by hand. A skill makes each run the same, with the same proof.

A `.claude/skills/gb-fallback-harvest/SKILL.md` that: 1) replays every file in `tests/routes/` with `--log-frame-fallbacks`; 2) runs `summarize_interpreter_log.py`; 3) for each new address, asks Ghidra for the listing; 4) writes proven code addresses to the entry-point list and data or RAM addresses to `notes/map.md`; 5) regenerates and replays. Rule: never add an address without a Ghidra listing.

gb-routine-slice (write your own)

write-your-own

Each port worker then sees one routine, not the whole disassembly. Six Golden Coins used this to keep worker context small.

A `.claude/skills/gb-routine-slice/SKILL.md` plus `tools/slice.py`. The script takes `--addr BANK:ADDR`, follows jumps, jump tables and bank switches in the RGBDS files, and writes `tasks/<addr>.md`. It must print `Slice status: COMPLETE` or list what it could not follow.

Claude setup for this system

Cut Game Boy work by bank and address. On Path A, one unit is one fallback address or one bug, with a recorded input file that shows it. On Path B, one unit is one routine from the ledger. Every unit has one check: a zero-fallback replay, a passing differential run, or make compare. Keep the ROM outside the repo and pass its absolute path.

Which model and effort for each job

The model and effort names come from one shared table, so they stay the same on every guide. See Claude Setup for the reasons.

JobWhat it means on this systemMax 20x (now called Ultra)Max 5x (now called Max)
Plan the projectPin the exact ROM revision by hash. Look for a disassembly, a .sym file, or an existing recomp. Write SCOPE.md.Fable 5.2
effort high
One session. This choice shapes months of work.
Opus 5.5
effort high
Use Fable 5.2 for this one session if you have weekly room.
Set up the projectBuild gbrecomp or RGBDS, write tools/check.sh or make compare, and set up .gitignore before any ROM is near the repo.Opus 5.5
effort medium
Sonnet 5.5
effort medium
Study the game fileFind jump tables, rst dispatchers, the bank-switch routine and code copied to RAM. Build the routine ledger from metadata and traces.Opus 5.5
effort high
Opus 5.5
effort medium
Raise to high for function edges and data layouts. A mistake there spreads.
Bulk unitsFallback addresses with clear Ghidra proof. Easy routines to name on Path B. One per worker, with make compare after each.Sonnet 5.5
effort medium
Haiku 5.5 for the plainest units.
Sonnet 5.5
effort medium
Fewer workers at once. Haiku 5.5 for the plainest units.
Hard unitsRoutines that mix code and data, self-modifying code, and units that failed three times in bulk.Fable 5.2
effort high
Go to xhigh only after a failed try at high.
Opus 5.5
effort high
Send only the last few that still fail to Fable 5.2.
Build the runtimePPU, sound, timer and MBC behavior in the runtime. Super Game Boy extras. Pan Docs first, SameBoy second.Opus 5.5
effort high
Opus 5.5
effort medium
Raise to high for timing and graphics bugs.
Find a bugWrong frames, hangs and timing bugs. Prove the cause with a recorded input, a state dump and a differential run before any fix.Opus 5.5
effort high
After two failed tries with full evidence, move to Fable 5.2.
Opus 5.5
effort high
One bug at a time.
Check the workA fresh session replays all routes, reruns make compare, and looks for edited expected files, stubs and generated-code edits.Opus 5.5
effort medium
Always a new session, never the one that did the work.
Sonnet 5.5
effort high
Always a new session, never the one that did the work.
Keep the recordsUpdate PROGRESS.md, the ledger counts, notes/findings.md and the parking lot after each batch.Haiku 5.5
effort medium
Haiku 5.5
effort medium

How many sessions at once

Max 20x (now called Ultra)

Path A: 2 to 3 sessions at once, each on its own bug or fallback in its own worktree. The ROM is small, but one runtime file is shared, so keep one writer per file. Path B: 4 to 6 bank workers plus one lead session. Merge often and rerun make compare after each merge.

Max 5x (now called Max)

Path A: 1 session, sometimes 2. Path B: 2 bank workers plus the lead. Send the hard units to one session at a time, and batch docs updates at the end of the day.

Lines for this project's CLAUDE.md

Add to CLAUDE.md
- Read `SCOPE.md` and `PROGRESS.md` at the start of every session.
- Never edit generated C under `output/`. Fix the recompiler, the config or the runtime, then regenerate.
- Never read a generated file whole. Grep for the bank and address, then read a few lines.
- Ghidra before guessing. Paste the listing for any address you make a claim about.
- Name every function as bank:address, for example `03:47f2`. The same address in two banks is two functions.
- Only add an entry point that executed in a trace or is proven code in Ghidra. Data decoded as code is a failure.
- The ROM lives at `<ABSOLUTE_PATH_TO_ROM>`. Never copy it into the repo or a commit.
- The one check is `bash tools/check.sh` (Path A) or `make compare` (Path B). No pasted output means not done.
- Do not edit `*.sha1`, `tests/routes/*.json` or the check scripts. Ask me first.
- In a worktree, use absolute paths for the ROM and the tools. Gitignored files are not copied in.
- Write side issues in `notes/parking-lot.md` and dead ends in `notes/findings.md`. Do not act on them.
- Start every report with DONE, PARTIAL or BLOCKED.

Keep the context small

  • Point Claude at *_metadata.json for function names and addresses, not at generated C.
  • Give Claude one route's fallback lines, not the whole log. Logs grow fast.
  • Pass a Ghidra address, not a pasted wall of assembly. Let the MCP server fetch it.
  • On Path B, give each worker one bank file and the ledger rows for that bank only.
  • Add a Read deny rule for generated C, such as Read(./output/**/*.c). Do not deny logs/ or the metadata file, since prompts need them. Read those with grep or a script.
  • Clear the chat after each unit. The ledger and findings file carry the state.

More prompts for this system

Each step above has its own prompt. These extra prompts cover the rest of the work. Fill in the parts in <ANGLE_BRACKETS>.

Scope and feasibility

Before any work, to choose Path A, Path B or both for one game.

Prompt for Claude
GOAL: Tell me if <GAME> (<REVISION>, SHA-1 <SHA1>) suits Path A, Path B, or both, and draft SCOPE.md.
READ FIRST: the ROM header at `<ABSOLUTE_PATH_TO_ROM>` (bytes $0100-$014F only), https://pret.github.io/, https://github.com/arcanite24/gb-recompiled
FENCE: Create only `SCOPE.md` and `notes/prior-work.md`. No code. Do not copy the ROM.
CHECK: Done means SCOPE.md lists ROM size, MBC type, Game Boy Color or Super Game Boy flags, prior work with links, chosen path, first milestone with its check, and an out-of-scope list.
BUDGET: 45 minutes.
IF BLOCKED: Stop. Say what you could not check.
OTHER PROBLEMS: Write them in `notes/parking-lot.md`.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: header fields. 3) Files changed. 4) Risks you see. 5) New parking-lot items.

A good answer: A one-page SCOPE.md with the hash, the MBC, links to any disassembly, and a plain risk list. It says when the game needs Super Game Boy or Color support.

Map the binary

After setup, to build the ledger both paths use.

Prompt for Claude
GOAL: Build `ledger/functions.csv` from `<PATH_TO>_metadata.json` and `notes/map.md`.
READ FIRST: `<PATH_TO>_metadata.json` (use a script, do not read it whole), `notes/map.md`.
FENCE: Edit only `ledger/functions.csv` and `tools/make_ledger.py`.
CHECK: Run `python3 tools/make_ledger.py`. Done means one row per function with bank, address, size, name, status, and the row count equals the metadata count.
BUDGET: 3 failed tries.
IF BLOCKED: Stop. Tell me which fields are missing.
OTHER PROBLEMS: Write them in `notes/parking-lot.md`.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: both counts. 3) Files changed. 4) Odd entries. 5) New parking-lot items.

A good answer: A CSV with matching counts, built by a script you can rerun. Odd entries, like functions at every byte of bank 0, are flagged, not hidden.

Unit loop: one fallback address (Path A)

For each interpreter fallback in a route replay.

Prompt for Claude
GOAL: Remove the fallback at <BANK:ADDRESS>.
READ FIRST: `notes/map.md`, the fallback summary lines for <BANK:ADDRESS>.
FENCE: Edit only the entry-point list and `notes/map.md`. Never edit generated C.
CHECK: Run `bash tools/check.sh`. Replay `logs/<ROUTE>.input` with `--headless --limit-frames <N> --log-file logs/interp.log --log-frame-fallbacks`. Run `python3 gb-recompiled/tools/summarize_interpreter_log.py logs/interp.log`. Done means <BANK:ADDRESS> no longer appears.
BUDGET: 3 tries or 30 minutes.
IF BLOCKED: Stop. If it is RAM code or data, say so with the Ghidra listing.
OTHER PROBLEMS: Write them in `notes/parking-lot.md`.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: before and after summary. 3) Files changed. 4) Fallbacks left. 5) New parking-lot items.

A good answer: A Ghidra listing that proves the code, one added entry point, and a summary without that address.

Unit loop: one routine (Path B)

For each raw routine in the ledger.

Prompt for Claude
GOAL: Name and document routine <BANK:ADDRESS>.
READ FIRST: the ledger row, the routine's lines in `<BANK_FILE>.asm`, `notes/ram-map.md`.
FENCE: Edit only those lines, `ram.asm`, `notes/ram-map.md`, and the ledger row.
CHECK: Run `make compare`. Done means OK and the row says `named`.
BUDGET: 3 failed compares, then mark it `hard`.
IF BLOCKED: Stop. Say what you could not explain.
OTHER PROBLEMS: Write them in `notes/parking-lot.md`.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: compare output. 3) Files changed. 4) Unsure names. 5) New parking-lot items.

A good answer: Clear names, a short comment on what the routine does, no byte changes, and make compare OK.

Batch dispatch

In the lead session, to hand out the next batch of units.

Prompt for Claude
GOAL: Start <N> workers, one per unit, from the top of the ledger.
READ FIRST: `ledger/functions.csv` (status column only), `PROGRESS.md`.
FENCE: Do not edit code yourself. Give each worker its own worktree, one bank file, and the unit-loop card with its unit filled in.
CHECK: Done means every worker returned DONE, PARTIAL or BLOCKED, and `make compare` (or `bash tools/check.sh`) passes on the merged branch.
BUDGET: Stop the batch if two workers fail on the same cause.
IF BLOCKED: Stop. Tell me the shared cause.
OTHER PROBLEMS: Collect workers' parking-lot items in `notes/parking-lot.md`.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the merged check output. 3) Units done, partial, blocked. 4) What is next. 5) New parking-lot items.

A good answer: A short table of units and outcomes, and a passing check after the merge, not just in each worktree.

Debug with evidence

When a frame is wrong, the game hangs, or sound drifts.

Prompt for Claude
GOAL: Prove the cause of <BUG>. Do not fix it yet.
READ FIRST: `logs/<ROUTE>.input`, `logs/<STATE>.json`, `notes/findings.md`.
FENCE: Edit only `notes/findings.md`. You may add one temporary log line, and you must remove it after.
CHECK: Done means a cause with an address, a register or memory value, and a replay that shows it every time.
BUDGET: 60 minutes or 2 wrong theories.
IF BLOCKED: Stop. List what you ruled out and why.
OTHER PROBLEMS: Write them in `notes/parking-lot.md`.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the replay output. 3) Files changed. 4) Cause in one sentence. 5) New parking-lot items.

A good answer: A cause tied to an address and a value, a replay that shows it, and no code change yet.

Verify and hunt for cheating

In a fresh session after any batch of claimed work.

Prompt for Claude
GOAL: Check that the work in commits <RANGE> is real.
READ FIRST: `git log --stat <RANGE>`, `PROGRESS.md`.
FENCE: Read only. Do not fix anything.
CHECK: Rerun `bash tools/check.sh`, `bash tools/regress.sh` and `make compare` as they apply. Look for edits to generated C, to `*.sha1` or route files, to the check scripts, for stubs that return early, and for entry points with no proof.
BUDGET: 45 minutes.
IF BLOCKED: Stop. Tell me what you could not rerun.
OTHER PROBLEMS: Write them in `notes/parking-lot.md`.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the check outputs. 3) Each suspicious change with file and line. 4) Verdict per commit. 5) New parking-lot items.

A good answer: Fresh check outputs and a per-commit verdict. Any edit to an expected file or generated code is named.

Status report

At the end of a day, or when you return after a break.

Prompt for Claude
GOAL: Give me the project status from files only.
READ FIRST: `PROGRESS.md`, `ledger/functions.csv` (counts by status), `notes/parking-lot.md`.
FENCE: Read only.
CHECK: Run `bash tools/check.sh` or `make compare` and paste the last lines.
BUDGET: 10 minutes.
IF BLOCKED: Stop. Say which file is missing.
REPORT: 1) Check output. 2) Counts by status. 3) Fallbacks or routines left. 4) Open blockers. 5) Parking-lot items waiting for me.

A good answer: Numbers from the ledger and a fresh check result. No guesses.

Session handoff

Before you close a session or switch plans.

Prompt for Claude
GOAL: Write what the next session needs to continue.
READ FIRST: this session's changes (`git diff --stat`), `PROGRESS.md`.
FENCE: Edit only `PROGRESS.md` and `notes/findings.md`.
CHECK: Done means PROGRESS.md has: the last check output, the unit in progress, the next 3 units, dead ends tried, and exact commands to resume.
BUDGET: 10 minutes.
IF BLOCKED: Stop and say what you do not know.
OTHER PROBLEMS: Write them in `notes/parking-lot.md`.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Proof: the new PROGRESS.md section. 3) Files changed.

A good answer: A short section a new session can follow without the chat history.

Blocked or cannot deliver

When a unit keeps failing, or you suspect it cannot be done.

Prompt for Claude
GOAL: Give me a plain answer on whether <UNIT> can be done now.
READ FIRST: `notes/findings.md` entries for <UNIT>.
FENCE: Read only. No new attempts.
CHECK: Done means you name what blocks it, the evidence, and 2 or 3 options with cost.
BUDGET: 15 minutes.
IF BLOCKED: Say "I do not know yet" and what would tell us.
REPORT: 1) BLOCKED or NOT BLOCKED. 2) Proof. 3) Options with cost. 4) Your pick and why.

A good answer: A plain yes or no, with evidence, like code run from RAM or a missing hardware feature, and real options.

Scope change request

When Claude wants to leave the fence, like adding widescreen or touching the runtime.

Prompt for Claude
GOAL: Ask me before you change scope.
READ FIRST: `SCOPE.md`.
FENCE: Do not make the change. Write the request only, in `notes/scope-requests.md`.
CHECK: Done means the request names the change, why it is needed, files it touches, the risk to the state-hash tests, and how to undo it.
BUDGET: 10 minutes.
IF BLOCKED: Stop and ask me.
REPORT: 1) The request. 2) What you will do if I say no.

A good answer: A short request you can approve or refuse. No code changed.

Keep Claude on task

These are the detours Claude tends to take on this system, and the rule that stops each one. The full method is on Stay on Task.

The detourThe rule to give Claude
Claude patches the generated C to make a bug go away. The next regenerate wipes it out.Never edit files under output/. Fix the recompiler, the config or the runtime, then regenerate. Add a hook that blocks edits there.
Claude adds guessed entry points so the fallback count drops. Data then turns into fake code.Add an entry point only with a trace hit or a Ghidra listing that proves it is code. Paste the proof in the report.
Claude decodes SM83 bytes by hand or guesses what a routine does.Ghidra before guessing. If the Ghidra MCP server does not answer, stop and say so.
Claude reads whole generated bank files for context and fills its window.Grep for the bank and address. Read at most 60 lines around it.
Claude writes a game-specific hack, like a fake event, to get past a hang.No per-game hacks or stubs in the runtime without my approval. Find the hardware cause first.
Claude edits an expected state file or hash so a test turns green.Never edit *.sha1, tests/routes/*.json or check scripts. Ask me first, with the reason.
On a port, Claude bulk-translates assembly line by line into Rust or C.One routine per ticket, written by hand from the slice, with a byte test that fails on revert.

Problems other projects hit

The repo cannot be rebuilt. Generated C files were deleted, and no regenerate command was written down.

Fix: Keep the recompiler version, the exact command and the config in the repo. Pin the recompiler as a submodule.

Seen in: Battle Arena Toshinden GB Recomp, Kirby's Dream Land Recomp, Kirby's Pinball Land: Recomp, Super Mario Land 3: Wario Land — Recomp

Static analysis misses code reached through jump tables, rst calls, or code copied to RAM, like the OAM DMA routine.

Fix: Keep the fallback interpreter on. Log fallbacks during real play, then add proven addresses as entry points. Main gbrecomp runs RAM code on its interpreter. The Tetris fork declares it in its config as an hram_overlay.

Seen in: TetrisGBRecomp, DK94 Recomp, WarioBlast Recomp

Random input mostly reaches menus and early stages. Later code stays unfound.

Fix: Record a real playthrough with --record-input and harvest from that too.

Seen in: WarioBlast Recomp

A release shipped with the wrong expected CRC32 baked in, so it refused every ROM.

Fix: Test the packaged build from a clean folder with the real ROM before you publish. Keep the hash in one place.

Seen in: TetrisGBRecomp

A Windows release failed on other PCs because SDL loads a DLL by name, and the packager missed it.

Fix: Build and test from a clean PATH, and run the zip on a PC without MSYS2.

Seen in: TetrisGBRecomp

Generated code or ROM-derived files were committed by mistake. They stay in git history.

Fix: Put *.gb, *.gbc, output/ and build folders in .gitignore before the first commit. Scan releases for ROM bytes.

Seen in: Battle Arena Toshinden GB Recomp, Super Mario Land 3: Wario Land — Recomp, Bigodao

Widening the view for widescreen changed when enemies spawned. Doors and enemies went missing.

Fix: Keep extras render-only. Draw more of the level, but leave game logic alone, so state-hash tests still pass.

Seen in: Bigodao, Six Golden Coins

Game controllers are not visible to Linux programs under WSL.

Fix: Build and play the Windows version. Use WSL for building and headless tests.

Seen in: DK94 Recomp, WarioBlast Recomp

GhidraBoy is archived and supports Ghidra only up to 11.4.2. The newest GhidraMCP wants Ghidra 12.1.4.

Fix: Install Ghidra 11.3.2 for Game Boy work. GhidraBoy supports it, and GhidraMCP 1.4 is built for it. Use the ghidra-headless skill if the MCP plugin will not load there.

Seen in: TetrisGBRecomp

How long it takes

Max 20x (now called Ultra)Max 5x (now called Max)One person, no AIHow sure
Path A: running on PC1 to 5 weeks2 to 12 weeks6 to 26 weeksmedium confidence
Path B: full decomp4 to 9 months8 months to 2 years2 to 6 yearslow confidence

Read this first

These numbers assume one medium game and one person giving 10 to 15 hours a week. Path A is medium confidence. Three dated AI projects agree on days to weeks, and one person released five gbrecomp builds in six days. But most public histories hide earlier work. Only Bigodao shows its full history, from first commit to release in 4 days. Path B is low confidence. No AI project here built a disassembly from zero with dates. The Path B range mixes the pre-agent disassemblies above with one AI port that began from a finished disassembly. The no-AI Path A range is a guess from the steps, since no pre-agent Game Boy recomp was reviewed.

What makes it faster or slower

  • How well gbrecomp handles the game. Plain games boot in a day. Games with odd jump tables or RAM code need many harvest rounds.
  • Whether a byte-matching disassembly already exists. With one, Path B starts at the port and drops to weeks.
  • ROM size and MBC type. A 32 KB game has one bank. A 512 KB game has 32 banks to map and name.
  • Extras like widescreen, Super Game Boy sound or Color support. Each adds runtime work and new tests.
  • Your review time. Each unit needs a look at its proof, and that is your 10 to 15 hours a week.

The facts behind these numbers

ProjectWhat happenedLink
BigodaoFirst commit 2026-10-01. First release 2026-10-05. 135 commits to 2026-11-04. 1 contributor. AI use declared by the developer.source
TetrisGBRecompFirst commit and first release 2026-04-01. Latest release 2026-08-17. 1 contributor. Commits carry Claude co-author trailers. Built on mstan's fork of gb-recompiled, made 2026-04-01 from history that starts 2026-01-03.source
WarioBlast RecompCreated, built and released on 2026-10-28, reusing the DK94 Recomp engine. 3 commits with Claude co-author trailers.source
Kirby's Dream Land RecompRepo created 2026-08-25, release 2026-08-26 with gbrecomp output. 1 contributor. AI use not stated.source
omegakatana92 recomps (5 repos)One person released five Game Boy recomps between 2026-08-25 and 2026-08-30: Toshinden and Super Mario Land 3 (08-25), Kirby's Dream Land and Kirby's Pinball Land (08-26), Kirby's Dream Land 2 (08-30). Four show gbrecomp output. None says what works or was tested.source
Six Golden Coins (sml2-rs)First commit 2026-10-13. First release 2026-10-27. v0.3.1 on 2026-11-13 after 880 commits. 1 contributor with agent files. Started from an existing disassembly.source
gb-recompiledFirst commit 2026-01-03. v0.0.1 on 2026-01-12. v0.1.0 on 2026-08-03. 5 contributors.source
pret/pokeredFirst commit 2010-01-05. 78 contributors and 2,839 commits by 2026-11-13. A pre-agent, many-person disassembly.source
Link's Awakening DX DisassemblyFirst commit 2014-06-28. 39 contributors and 2,525 commits. Still getting commits in 2026 (last push 2026-09-25).source
Wario Land disassembly (Kak2X/wl)One person. First commit 2021-05-16. Builds a bit-perfect ROM. 69 commits.source

Projects reviewed (12)

All 12 Game Boy projects on RecompLauncher with a GitHub repo were reviewed. The catalog lists 13. The 13th, Blue's Alphabet Book, is a Game Boy Color game and was left out. None came from outside RecompLauncher.

What each project teaches

G1R Deluxe

Pokemon Red

Top rated on RecompLauncherreimplementationplayable
LÖVE 11.xLuaJITpret/pokered disassemblyPython + Pillow

Started: 2026-07. First release: 2026-07. Code: Lua.

AI: yes: AIDisclosure.md says about 7 commits were AI-assisted and reviewed by people

Lesson: A finished disassembly can be the spec for a new engine. Each ported script names its source file, and headless tests run real game logic.

AM2RLauncher

Metroid II: Return of Samus

Top rated on RecompLauncherotherin progress
.NETxdelta3GTK3 / WPF

Started: 2021-03. First release: 2021-03. Code: C#.

AI: none stated; the catalog's AI flag was set by the store, and its AGENTS.md refuses autonomous agent contributions Agent files: AGENTS.md.

Lesson: This patches a PC fan remake, not the Game Boy ROM. Its AGENTS.md shows that some projects reject agent-driven pull requests.

Bigodao

Wario Land: Super Mario Land 3

Top rated on RecompLauncherstatic recompplayable
gb-recompiledKak2X/wl disassemblyCMake + NinjaSDL2OpenGLMinGW-w64

Started: 2026-10. First release: 2026-10. Code: C and C++.

AI: yes: AI use for code declared by the developer to the catalog

Lesson: Keep edits to generated C as a replayable patch map keyed by address. Then regenerating never loses your changes.

Six Golden Coins

Super Mario Land 2: 6 Golden Coins

Top rated on RecompLauncherport of a decompplayable
Rust (cargo)RGBDS disassembly (froggestspirit/marioland2)PyBoyWGPUPython slicer scripts

Started: 2026-10. First release: 2026-10. Code: Rust.

AI: yes: AGENTS.md, ORCHESTRATION.md and PORTING.md describe a supervisor and porter agent workflow Agent files: AGENTS.md, ORCHESTRATION.md, PORTING.md, docs/agent-prompts.md.

Lesson: This is the Path B model on Game Boy. One routine per ticket, a sliced task file, and a byte test that must fail if the line is reverted.

Kirby's Dream Land Recomp

Kirby's Dream Land

Top rated on RecompLauncherstatic recompplayable
gb-recompiledCMakeSDL2Dear ImGui

Started: 2026-08. First release: 2026-08. Code: C.

AI: none stated

Lesson: gbrecomp output builds on its own, so a release can come in a day. But without the command and config, nobody else can rebuild it.

TetrisGBRecomp

Tetris

Top rated on RecompLauncherstatic recompplayable
gb-recompiled (mstan fork)recomp-uiMSYS2 GCCCMake + NinjaSDL2Ghidra

Started: 2026-04. First release: 2026-04. Code: C.

AI: yes: commits carry Claude co-author trailers; rules come from the engine's CLAUDE.md

Lesson: A game repo can be tiny: a config, a list of harvested entry points and a hooks file. Play, harvest fallbacks, regenerate, until a run logs zero.

Super Mario Land 3: Wario Land — Recomp

Wario Land: Super Mario Land 3

Top rated on RecompLauncherstatic recompplayable
gb-recompiledCMake + NinjaMinGW ClangSDL2Dear ImGui

Started: 2026-08. First release: 2026-08. Code: C.

AI: none stated

Lesson: A broken .gitignore let a whole build folder into git. Check your ignore file before the first commit.

DK94 Recomp

Donkey Kong

Top rated on RecompLauncherstatic recompplayable
own SM83-to-C recompilerTinyCC 0.9.27CMake + NinjaPython 3.11SDL2MinGW-w64

Started: 2026-10. First release: 2026-10. Code: C.

AI: none stated; catalog flag set by the store

Lesson: Build the recompiler and the interpreter from one opcode table. Then per-frame state hashes on random seeds become a cheap, strong test.

Battle Arena Toshinden GB Recomp

Battle Arena Toshinden

Top rated on RecompLauncherstatic recompplayable
gb-recompiledCMakeSDL2Dear ImGui

Started: 2026-08. First release: 2026-08. Code: C.

AI: none stated

Lesson: Its metadata shows functions at nearly every byte of bank 0. That hints at a blind code scan, so check the function list.

Kirby's Pinball Land: Recomp

Kirby's Pinball Land

Top rated on RecompLauncherstatic recompplayable
gb-recompiledCMakeSDL2Dear ImGui

Started: 2026-08. First release: 2026-08. Code: C.

AI: none stated

Lesson: A 256 KB ROM became 37 function files and 13 dispatch files. That gives you a size estimate before you start.

Kirby's Dream Land 2 Recomp

Kirby's Dream Land 2

Top rated on RecompLauncherstatic recompstalled
unknown

Started: 2026-08. First release: 2026-08. Code: none published.

AI: none stated

Lesson: The repo holds only a licence and a release zip. There is nothing to learn from or rebuild, so publish your config and steps.

WarioBlast Recomp

Wario Blast Featuring Bomberman!

Top rated on RecompLauncherstatic recompplayable
own recompiler from DK94 RecompTinyCC 0.9.27CMake + NinjaSDL2MinGW-w64

Started: 2026-10. First release: 2026-10. Code: C.

AI: yes: all three commits carry a Claude co-author trailer

Lesson: Moving the engine to a new game was mostly rewriting one hints file. Put every game-specific fact in one small file.

What we could not check

  • No AI-assisted Game Boy disassembly built from zero, with dates, was found. The Path B times are an estimate.
  • Several repos were released on their first day. Their real work hours are unknown.
  • Nothing in this guide was run here. No ROM was used. Commands and flags were checked against the tools' docs and source code only.
  • Ghidra 11.3.2 with GhidraBoy and GhidraMCP 1.4 together was not tested. The version match comes from their files. The claude mcp add command for 1.4 is built from its README and was not run.
  • That --dump-frames writes files in --headless mode was read from the runtime source, not seen in a run.
  • Whether --differential exits with an error code on a mismatch was not checked. Read its output.
  • A community port of GhidraBoy to Ghidra 12.1.2 exists (ptthess/GhidraBoy-12.1.2-port). It was not checked.
  • Whether any commercial Game Boy game was written in C was not checked. This guide assumes assembly, as the official kit was an assembler.
  • The --harvest flag used by TetrisGBRecomp is in the mstan/gbrecompiled fork. It was not confirmed in the main gb-recompiled tool.
  • The tools/check.sh, tools/regress.sh, make compare and slicer scripts in the steps are scripts you write. Their names are suggestions.
  • Game Boy emulator MCP servers exist on GitHub, such as mcp-gameboy. None was used by a reviewed project, and none was checked.
  • The MSYS2 package names for CMake and Ninja were checked as pages only. They were not installed here.

Sources