Skip to the page
It's Decomplicated
Many, 1971

Arcade decomp guide

Every board differs, but MAME runs the real code, so you can check your work frame by frame.

What this system is like

Arcade is not one system. It is hundreds of boards from Sega, Namco, Konami, SNK, Midway and others. Each board has its own main chip, sound chip and graphics chips. The 12 projects reviewed here use nine different main chips. So first find out which board your game runs on.

The good news is MAME. MAME is a free emulator that runs almost every board. Its code also shows how each chip behaves. Most strong projects here use MAME as the answer key. It runs the original code and your code with the same inputs, then compares each frame. Others check against a CPU interpreter or the Supermodel emulator instead.

Path A gets the game running on a PC. Most projects use static recompilation: a tool turns the game's machine code into C. A small interpreter runs any code the tool missed and checks the rest. For Neo Geo games, a recompiler toolkit already exists.

Path B turns the game into readable C. Byte matching is rare here, because many older games were written in assembly. So most projects check each function against MAME instead. Only newer boards with a known compiler, like Triforce, allow a true matching decomp.

Hundreds of boards, not one system

Every board has its own chips and memory map. A tool for Sega System 32 does nothing for a Namco game. Your first job is to name the board and its main chip. MAME's driver file for the board tells you both.

MAME is your answer key

MAME runs the original code on almost every board. The cheviman ports run MAME's CPU cores beside their own C. Both play the same input script and write a hash for every frame. A hash is a short fingerprint of memory or a picture. The first frame that differs points to the bug.

Small programs, many chips

Older arcade programs are small. TMNT has 2,439 functions and OutRunners has 762. But a board may have three or more chips with code: a main chip, a sound chip and a math chip. Each one needs its own translation.

Byte matching is rare

Many older games were written in assembly, so no compiler can rebuild them. The diff tool objdiff also has no support for the 68000, V60 or i960. So most Path B projects check behavior against MAME, not bytes. Triforce is the exception: Mario Kart Arcade GP2 is being matched byte for byte.

The ROM is the game

Machine-made C comes from the game's code, so it belongs to the game's owner. The best projects keep it out of git. They build it on the player's PC from the player's own ROM set. Some even run a check that no program holds ROM bytes.

Two paths

Path A

Get it running on PC

A recompiler turns each routine of the main program into C. A runtime stands in for the board: video chips, sound chips, inputs and timers. A built-in interpreter, often Musashi for the 68000, runs code the recompiler missed. The same interpreter replays every block and compares the results. You fix one mismatch at a time, found by per-frame hashes against MAME or the interpreter.

Go to the steps

Path B

Full decomp for porting

You turn every function into readable C that does exactly what the original does. Since most arcade games cannot be byte matched, the check is behavior. MAME's CPU core runs the original, your C runs beside it, and every frame's state, picture and sound must match. Names and types live in a text file, and a decompiler writes the C from it. When it all matches, you put the board behind an interface and port it.

Go to the steps

Path A: Get it running on PC

A recompiler turns each routine of the main program into C. A runtime stands in for the board: video chips, sound chips, inputs and timers. A built-in interpreter, often Musashi for the 68000, runs code the recompiler missed. The same interpreter replays every block and compares the results. You fix one mismatch at a time, found by per-frame hashes against MAME or the interpreter.

Method: static recompilation, checked against an interpreter and MAME

Pick this first, for any board. It is the fastest way to a running game. If your game runs on a Neo Geo, start from neogeorecomp. If it runs on Model 3 or Triforce, study SpikeOut Recomp or OpenGP first.

  1. Scope the game and find its board

    You pick one game, one MAME set name and one revision. You find the board, its main chip and its sound chips. Then you look for prior work, because arcade has several toolkits and rewrites already. The result is a one-page SCOPE.md you approve.

    • Find the set name and board in MAME. Run mame -listfull <SET> and mame -listsource <SET> to see the game name and its driver file.
    • Open that driver file under src/mame/ on GitHub. Its top comment and its machine setup name the CPUs and chips.
    • Check your ROM files: mame -verifyroms <SET>. Write down each file's CRC32 from the zip.
    • Search for prior work: neogeorecomp (Neo Geo), arcade-decomp (System 32, Multi 32, Konami 68000), Supermodel (Model 3), CannonBall (OutRun), OpenGP (Triforce).
    • Write SCOPE.md with lines that start Board:, CPUs:, Set:, Technique: and Prior work:. Add the milestone, its check, and what is out of scope.
    • Read it yourself. When you agree, add a line that starts Approved: with the date. Only you write that line.
    Prompt for Claude
    GOAL: Draft SCOPE.md for <GAME>, MAME set <SET>, so I can approve one technique.
    READ FIRST: notes/mame-listsource.txt, notes/verifyroms.txt, the MAME driver file <DRIVER_PATH> (read only its top comment and machine setup).
    FENCE: Edit only SCOPE.md and notes/. Do not download ROMs, BIOS files or game data. Do not start any code.
    CHECK: Run `findstr /b /c:"Board:" SCOPE.md && findstr /b /c:"CPUs:" SCOPE.md && findstr /b /c:"Set:" SCOPE.md && findstr /b /c:"Technique:" SCOPE.md && findstr /b /c:"Prior work:" SCOPE.md`. Done means all five lines print and the command exits 0. The CPUs line gives each CPU's role. The Technique line gives one reason against each other technique.
    BUDGET: Stop after 45 minutes of work.
    IF BLOCKED: Stop. Do not work around it. If the board has no MAME driver or the set fails verification, say so plainly and stop.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) The technique in one line, then the evidence. 3) Files changed. 4) Open questions. 5) New parking-lot items.
    Done whenThe findstr chain in the prompt exits 0 on SCOPE.md, and findstr /b /c:"Approved:" SCOPE.md finds the line you added after reading it.

    Proof this works: OutRunners Port, KOF'98 Recomp, https://docs.mamedev.org/commandline/commandline-all.html

  2. Set up the repo and the one check

    You make a repo that holds only your own code. Your ROM set lives in a rom/ folder that git ignores. You write a script that checks the ROM by hash, and one check command that Claude runs after every change.

    • Install Visual Studio Build Tools with the C++ workload, CMake 3.20 or newer, SDL2, Python 3.10 or newer, and Git.
    • For a Neo Geo game, clone the toolkit as a submodule: git submodule add https://github.com/sp00nznet/neogeorecomp.
    • Add rom/, build/ and build/generated/ to .gitignore. Generated C never goes in git.
    • Write tools/verify_rom.py. It checks the CRC32 and SHA-1 of every chip file and refuses any other revision.
    • Write check.cmd. It runs cmake --build build --config Release, then ctest --test-dir build -C Release --output-on-failure, then the golden run.
    • Write CLAUDE.md, PROGRESS.md and notes/parking-lot.md.
    Prompt for Claude
    GOAL: Make `check.cmd` build the project and run every check in one command.
    READ FIRST: SCOPE.md, CLAUDE.md, the README of <TOOLKIT> (Getting Started only).
    FENCE: Edit only CMakeLists.txt, check.cmd, .gitignore and tools/. Never copy ROM files into the repo. Do not add features, refactors or tools I did not ask for.
    CHECK: Run `check.cmd`. Done means it exits 0 on a clean clone, and exits non-zero after you add a deliberate compile error. Run `python tools/verify_rom.py --rom-dir <ABSOLUTE_ROM_DIR>` and paste its output.
    BUDGET: Stop after 3 failed tries at the same error.
    IF BLOCKED: Stop. Do not work around it. Tell me what blocked you, what you tried, and what you need from me.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste both check outputs and the ROM check. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whencheck.cmd passes on a clean clone, fails on a planted error, and verify_rom.py passes on your ROM set.

    Proof this works: KOF'98 Recomp, tmnt-port, https://github.com/sp00nznet/neogeorecomp

  3. Build the reference and the input scripts

    Before any recompiling, you build the answer key. A reference runs the original code with the same inputs every time. You write small input scripts that reach each part of the game. Each run writes a hash for every frame.

    • Pick a reference. For the 68000, link Musashi as an interpreter. For other chips, use MAME itself, or MAME's CPU core inside your own runner.
    • To record with MAME, write a Lua script and run mame <SET> -autoboot_script tools/capture.lua. Use emu.add_machine_frame_notifier to save a hash of work RAM each frame.
    • Write input scripts in tests/controls/: coin and start, attract mode, one level, one boss. Use RAM pokes to start a later level.
    • Save the reference hashes for each script in build/reference/.
    • Run each script twice and confirm both runs give the same hashes. If not, find the random seed or timer first.
    Prompt for Claude
    GOAL: Make a reference runner that plays tests/controls/<SCRIPT>.txt on the original <SET> code and writes one state hash per frame.
    READ FIRST: SCOPE.md, https://docs.mamedev.org/luascript/index.html, https://docs.mamedev.org/luascript/ref-common.html (emu.add_machine_frame_notifier), tests/controls/README.md.
    FENCE: Edit only tools/reference/ and tests/controls/. ROM files and MAME's own files are read-only. Do not start the recompiler.
    CHECK: Run the reference twice on the same script, writing build\reference\<SCRIPT>-1.txt and build\reference\<SCRIPT>-2.txt. Then run `fc /b build\reference\<SCRIPT>-1.txt build\reference\<SCRIPT>-2.txt`. Done means `fc` finds no differences, and a changed input line changes the hashes.
    BUDGET: Stop after 4 failed tries, or after 60 minutes with no new frame matching.
    IF BLOCKED: Stop. Do not work around it. If the runs differ, report the first differing frame and stop.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the `fc` or `cmp` output of the two runs. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whenfc /b finds no differences between two runs of the same script, and a changed input line changes the hash file.

    Proof this works: tmnt-port, The House of the Dead: ReWrithe, Super-Hang-On-Ultimate

  4. Map the program and its code

    You find every routine in the main program. Static search from the reset and interrupt vectors finds only part of it. A pointer scan and a profile run find the rest. The map goes into a ledger file with a status column.

    • Load the main program into Ghidra. Pick the right chip and base address from the MAME driver.
    • Follow code from the vectors and jump tables. Then scan memory for values that look like code pointers.
    • Run each input script in a profile build that logs every entry point the interpreter had to run. neogeorecomp games do this with --dump-misses.
    • Write ledger/functions.tsv: address, size, kind (game, sound driver, copied to RAM), status.
    • Mark code that the game copies to RAM at boot. A static tool cannot see it.
    • Write tools/check_ledger.py. It prints every miss address that falls in no ledger row, then exits 1 if there are any.
    Prompt for Claude
    GOAL: Write ledger/functions.tsv for the <CPU> main program of <SET>, with every routine found so far.
    READ FIRST: SCOPE.md, build/profile/misses.txt, the Ghidra project <GHIDRA_PROJECT> (through the MCP server if it is up).
    FENCE: Edit only ledger/, notes/map.md and tools/check_ledger.py. Do not rename anything in Ghidra yet. Do not write C.
    CHECK: Run `python tools/check_ledger.py ledger/functions.tsv build/profile/misses.txt`. Done means it prints 0 missing and exits 0. The ledger has address, size, kind and status columns, and its row count is in notes/map.md.
    BUDGET: Stop after 90 minutes.
    IF BLOCKED: Stop. Do not work around it. If the Ghidra MCP server is down, stop and ask. Do not guess code from memory.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Row counts by kind, and the miss check result. 3) Files changed. 4) Areas still unclear. 5) New parking-lot items.
    Done whenpython tools/check_ledger.py ledger/functions.tsv build/profile/misses.txt prints 0 missing and exits 0.

    Proof this works: KOF'98 Recomp, SpikeOut Recomp, The House of the Dead: ReWrithe

  5. First light: recompile and boot

    You run the recompiler over the whole main program and link it with the runtime. Missing code falls back to the interpreter, so the game can boot early. The goal is a window showing the first frame, then attract mode.

    • Generate the C into build/generated/. For a Neo Geo game: cmake -S . -B build -D<GAME>_ROM_DIR=rom, then cmake --build build --config Release.
    • Stub nothing quietly. A missing chip register should log its address and stop.
    • Write tools/golden.cmd. It runs the game headless for a set number of frames with an input script and saves a screenshot.
    • Turn on the verify mode. Every recompiled block is replayed in the interpreter and compared: <GAME> --headless --verify --frames 1801 --input tests/coin_start.txt.
    Prompt for Claude
    GOAL: Build the recompiled <SET> and reach the first attract-mode frame with no person.
    READ FIRST: SCOPE.md, ledger/functions.tsv, the recompiler docs <RECOMP_DOCS>.
    FENCE: Edit only runtime/, src/ and tools/golden.cmd. Never edit build/generated/; change the recompiler input and regenerate. No stub may return a fake value.
    CHECK: Run `tools\golden.cmd`. Done means it saves the frame <N> screenshot, exits 0, and the verify line reports 0 mismatches.
    BUDGET: Stop after 5 failed builds, or 90 minutes with no new frame reached.
    IF BLOCKED: Stop. Do not work around it. Report the last log lines and the address that stopped the run.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the golden run output and the verify line. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whentools\golden.cmd reaches the attract-mode frame, saves the screenshot, and the verify line says 0 mismatches.

    Proof this works: KOF'98 Recomp, https://github.com/sp00nznet/neogeorecomp

  6. Fix one mismatch at a time

    Now you grind. Each unit is one mismatch: a frame where your hash differs from the reference. Claude finds the first differing frame and the first differing byte. Then it finds which code wrote that byte, and fixes the cause.

    • Run every input script on both sides and compare the hash files. The first differing frame is the bug's frame.
    • Dump RAM at that frame on both sides. Find the first differing byte and the code that wrote it.
    • Fix the recompiler or the runtime, never the generated C. Then rerun every script, not just the one that failed.
    • Record each fix in PROGRESS.md with its cause and the frame it fixed.
    Prompt for Claude
    GOAL: Make tests/controls/<SCRIPT>.txt match the reference past frame <FRAME>.
    READ FIRST: CLAUDE.md, PROGRESS.md, build/diff/<SCRIPT>.txt, notes/findings.md.
    FENCE: Edit only the recompiler source in tools/recomp/ and runtime/. Never edit build/generated/, the reference hashes, or the check scripts.
    CHECK: Run `check.cmd`. Done means every script in tests/controls/ matches the reference hashes, including <SCRIPT> past frame <FRAME>.
    BUDGET: Stop after 3 failed fixes, or 60 minutes with no new matching frame.
    IF BLOCKED: Stop. Do not work around it. Give me the first differing frame, the byte, the code that wrote it, and your best cause.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the check summary. 3) Files changed. 4) The proven cause in one sentence. 5) New parking-lot items.
    Done whenEvery input script matches the reference hashes, and PROGRESS.md names the cause of the fix.

    Proof this works: SpikeOut Recomp, Super-Hang-On-Ultimate, Namco 22 Decompile

  7. Finish the board: video, sound and input

    You replace the debug output with real video, sound and controls. Build each chip as its own library and test it alone. Check the video against MAME's picture and the sound against MAME's samples, before you judge the game.

    • Port each video chip's drawing rules from MAME's source. Keep the copyright notice and name the source file.
    • Use ymfm for Yamaha FM chips such as the YM2151, YM2610 and YM3438.
    • Use SDL2 or SDL3 for the window, sound and game pads.
    • Write a picture hash and a sound hash for every frame. Compare both against the reference. Add --video and --sound switches to check.cmd for this.
    • Pace frames by the clock if the screen ignores vsync.
    Prompt for Claude
    GOAL: Make the <CHIP> stand-in match MAME's picture (or sound) for tests/controls/<SCRIPT>.txt.
    READ FIRST: CLAUDE.md, the MAME source file <MAME_FILE> for this chip, runtime/<CHIP>.c, build/diff/<SCRIPT>-video.txt.
    FENCE: Edit only runtime/<CHIP>.c and its header. Keep MAME's notice in any code you adapt. Do not change game logic or the reference.
    CHECK: Run `check.cmd --video --sound`. Done means every frame's picture hash and sound hash match for <SCRIPT>, and all older scripts still pass.
    BUDGET: Stop after 4 failed tries, or 90 minutes with no new matching frame.
    IF BLOCKED: Stop. Do not work around it. Save both frames as BMP files and tell me what differs.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the check summary. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whencheck.cmd --video --sound exits 0, so picture and sound hashes match the reference for every script.

    Proof this works: segasonic-port, tmnt-port, https://github.com/aaronsgiles/ymfm

  8. Harden and package it

    You lock in your progress. Every input script becomes a regression test. You prove no ROM data is in the repo or the program. The player's PC builds the game from their own ROM set.

    • Run every script on a clean clone. Add a long soak run of 5 minutes or more.
    • Add a check that fails if any ROM-derived file is tracked by git.
    • Add a check that no executable holds a stretch of ROM bytes.
    • Build release packages with CI on clean machines. CI has no ROM, so game tests stay local.
    • Keep extras like widescreen behind a switch that is off by default, so the plain build still matches.
    Prompt for Claude
    GOAL: Make a clean clone pass every check, and prove no ROM data ships.
    READ FIRST: CLAUDE.md, PROGRESS.md, tests/controls/, .github/workflows/.
    FENCE: Edit only tools/, tests/ and .github/workflows/. Do not change game behavior or reference hashes.
    CHECK: On a fresh clone, run `check.cmd`, the soak run, and `python tools/check_game_data.py`. Done means all three pass, and the game-data check fails when you stage a test file named rom/fake.bin.
    BUDGET: Stop after 3 failed tries at the same error.
    IF BLOCKED: Stop. Do not work around it. Tell me what blocked you, what you tried, and what you need from me.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste all three outputs and the planted failure. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whenA fresh clone passes every script and the soak run, and the game-data check fails on a planted ROM file.

    Proof this works: OpenGP, tmnt-port, KOF'98 Recomp

Path B: Full decomp for porting

You turn every function into readable C that does exactly what the original does. Since most arcade games cannot be byte matched, the check is behavior. MAME's CPU core runs the original, your C runs beside it, and every frame's state, picture and sound must match. Names and types live in a text file, and a decompiler writes the C from it. When it all matches, you put the board behind an interface and port it.

Method: non-matching decompilation checked frame by frame against MAME (matching only where the compiler is known, as on Triforce)

Pick this after Path A works, or when you want the game on other systems. It suits small games on the boards arcade-decomp covers today: Sega System 32, Sega Multi 32 and Konami 68000 boards. On Triforce, pick true matching with decomp-toolkit instead.

  1. Choose matching or behavior checks

    You decide how each function will be proven. If you know the original compiler and can run it, you can match bytes. If not, you prove behavior against MAME. Write the choice and the reason in SCOPE.md.

    • Look for a compiler mark in the program. On Triforce, mkgp2-decomp reads mw_comment_version to guess CodeWarrior 2.7.
    • If the code looks hand-written in assembly, plan for behavior checks. CannonBall's author found OutRun was 68000 and Z80 assembler.
    • Check if arcade-decomp supports your chips today: V60, V70, 68000 and Z80.
    • Check if objdiff supports your chip: PowerPC, SuperH, MIPS and x86 yes; 68000, V60 and i960 no.
    • Write the check for each kind of unit into SCOPE.md, on lines that start Check:. Start notes/compiler.md with a line Compiler: that names it or says unknown.
    Prompt for Claude
    GOAL: Decide, with evidence, if <SET> can be byte matched or must be checked by behavior.
    READ FIRST: SCOPE.md, notes/map.md, the first 200 lines of the Ghidra listing at <ENTRY_ADDRESS>, https://github.com/cheviman/arcade-decomp, https://github.com/encounter/objdiff.
    FENCE: Edit only SCOPE.md and notes/compiler.md. Do not download any compiler. Do not write C.
    CHECK: Run `findstr /b /c:"Compiler:" notes\compiler.md && findstr /b /c:"Check:" SCOPE.md`. Done means both print and the command exits 0. The Compiler line names the compiler or says unknown, with the evidence and its addresses below it. SCOPE.md has one Check line for each unit type.
    BUDGET: Stop after 60 minutes.
    IF BLOCKED: Stop. Do not work around it. If you cannot tell, say unknown. Do not guess a compiler.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Matching or behavior, in one line, then the evidence. 3) Files changed. 4) Open questions. 5) New parking-lot items.
    Done whenfindstr /b /c:"Compiler:" notes\compiler.md && findstr /b /c:"Check:" SCOPE.md exits 0.

    Proof this works: https://github.com/naari3/mkgp2-decomp, https://github.com/djyt/cannonball, OutRunners Port

  2. Set up the decomp repo

    You build a repo where text files hold your knowledge and a script writes the C. Names, types and comments go in symbols.txt. The ROM stays outside git. Assets are cut from the ROM and must rebuild it byte for byte.

    • For a 68000, V60 or Z80 game, add the shared core: git submodule add https://github.com/cheviman/arcade-decomp tools/core.
    • Write tools/game_profile.py to tell the core your CPU, set name and memory layout.
    • For Triforce, start from dtk-template, run python configure.py, then ninja.
    • Write tools/verify_rom.py and tools/extract_assets.py --check. The check rebuilds the chips from the assets and compares bytes.
    • Write check.cmd and CLAUDE.md.
    Prompt for Claude
    GOAL: Set up the decomp repo for <SET> so one command builds and checks it.
    READ FIRST: SCOPE.md, the arcade-decomp README sections 'A game's profile' and 'Using it in a game'.
    FENCE: Edit only tools/game_profile.py, tools/*.py wrappers, CMakeLists.txt, check.cmd and .gitignore. Never commit ROM files or generated C. Do not edit tools/core/.
    CHECK: Run `python tools/verify_rom.py`, `python tools/extract_assets.py --check` and `check.cmd`. Done means all three pass on a clean clone.
    BUDGET: Stop after 3 failed tries at the same error.
    IF BLOCKED: Stop. Do not work around it. Tell me what blocked you, what you tried, and what you need from me.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste all three outputs. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whenverify_rom.py, extract_assets.py --check and check.cmd all pass on a clean clone.

    Proof this works: tmnt-port, segasonic-port, https://github.com/cheviman/arcade-decomp

  3. Build the reference and the scenarios

    You need a judge for every function. The reference runs the original program on MAME's CPU core against a model of the board. Your C runs the same input scripts. Both write hashes of state, picture and sound for every frame.

    • Use the core's reference if it fits: s32ref for System 32 and Multi 32, kref for Konami 68000 boards.
    • Otherwise, capture in MAME. Run mame <SET> -debug or a Lua script to save registers and RAM at a routine's entry and return.
    • Write scenarios that reach every area and boss. Use RAM pokes to start late areas.
    • Record which addresses each scenario ran. That tells you which scenarios test which function.
    Prompt for Claude
    GOAL: Make the reference play every script in tests/controls/ and write per-frame hashes and executed addresses.
    READ FIRST: SCOPE.md, tools/core/<FAMILY>/reference/, https://docs.mamedev.org/debugger/execution.html.
    FENCE: Edit only tools/reference/ and tests/controls/. MAME files, ROM files and tools/core/ are read-only.
    CHECK: Run the reference twice on all scripts, into build\reference\run1\ and build\reference\run2\. Then run `fc /b build\reference\run1\*.txt build\reference\run2\*.txt`. Done means `fc` finds no differences, and each script has an executed-address list.
    BUDGET: Stop after 4 failed tries, or 60 minutes with no progress.
    IF BLOCKED: Stop. Do not work around it. If two runs differ, report the first differing frame.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Scenario count, frame count and the repeat check. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whenfc /b finds no differences between the two runs, and every scenario has a list of the addresses it ran.

    Proof this works: tmnt-port, OutRunners Port, The House of the Dead: ReWrithe

  4. Map every byte and check the disassembler

    You classify every byte of the program as code, data or fill. Before you trust a disassembler, you check it against MAME's at every offset. Then the static analysis must find all the code the reference ran.

    • Compare your disassembler with MAME's at every byte offset of the program ROM. The core has a script for each CPU: compare_with_mame.py (V60), compare_z80_with_mame.py (Z80) and compare_m68k_with_mame.py (68000).
    • Run python tools/coverage.py to classify every byte.
    • Put names, types and comments in symbols.txt. Give the evidence for each name.
    • Write docs/unreachable.txt: each piece of code no scenario runs, with a reason.
    • Build ledger/functions.tsv with a status column: raw, decompiled, named, proven.
    Prompt for Claude
    GOAL: Prove the disassembler for <CPU> matches MAME's and classify every byte of the <SET> program.
    READ FIRST: CLAUDE.md, tools/core/<CPU>/, build/reference/executed.txt.
    FENCE: Edit only symbols.txt, docs/unreachable.txt and ledger/. Do not edit tools/core/ or src/.
    CHECK: Run the core's compare script for <CPU> (`compare_with_mame.py`, `compare_z80_with_mame.py` or `compare_m68k_with_mame.py` under tools/core/), then `python tools/coverage.py`, then `python tools/check_scenarios.py`. Done means 0 differences at every offset, every byte is classified, and every executed address is inside a known function.
    BUDGET: Stop after 90 minutes.
    IF BLOCKED: Stop. Do not work around it. List the first 10 offsets that differ from MAME and stop.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste both summaries. 3) Files changed. 4) Unclear areas. 5) New parking-lot items.
    Done whenThe disassembler matches MAME's at every offset, every byte is classified, and every executed address is in a known function.

    Proof this works: segasonic-port, tmnt-port, OutRunners Port

  5. First light: one unit proven

    You prove the whole chain on one small unit. With behavior checks, start from a translation scaffold: one C line per instruction that already passes the scenarios. With matching, get one small function to an exact match.

    • Behavior route: build the scaffold with tools/recompile.py and run python tools/check_scenarios.py.
    • Then write the readable C for one small function with python tools/decompile.py, and check again.
    • Matching route: pick one small function, write its C, run ninja, and diff it in objdiff.
    • Break the function on purpose and confirm the check fails. Then fix it back.
    Prompt for Claude
    GOAL: Prove one small function, <FUNCTION> at <ADDRESS>, end to end.
    READ FIRST: CLAUDE.md, symbols.txt, the reference trace for <ADDRESS>.
    FENCE: Edit only symbols.txt (and the one source file for <FUNCTION> if matching). Never edit generated C by hand. Do not touch other functions.
    CHECK: Run `python tools/check_scenarios.py --video --sound` (or `ninja` plus objdiff for matching). Done means it passes, and fails when you change one constant in <FUNCTION> on purpose.
    BUDGET: Stop after 5 tries.
    IF BLOCKED: Stop. Do not work around it. Paste the first difference and stop.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the passing check and the planted failure. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whenOne function passes its check, and a planted change makes the check fail.

    Proof this works: OutRunners Port, https://github.com/naari3/mkgp2-decomp

  6. Decompile function by function

    Now you grind through the ledger. Each unit is one function. Claude adds names and types to symbols.txt, runs the decompiler, and checks the scenarios that ran that function. Many workers can run at once, each on a different file.

    • Pick the next functions from the ledger, smallest and most-called first.
    • Edit symbols.txt, then run python tools/decompile.py. Never edit src/ by hand.
    • Rerun only the scenarios that touched the change: python tools/select_scenarios.py --run.
    • Track readability with python tools/noise_report.py against tools/noise_baseline.txt. A rising count fails.
    • Mark each function proven in the ledger only after its scenarios pass.
    Prompt for Claude
    GOAL: Make <FUNCTION> at <ADDRESS> readable and proven: real names, real types, no CPU leftovers.
    READ FIRST: CLAUDE.md, ledger/functions.tsv row for <ADDRESS>, symbols.txt, the current C in src/<FILE>.c (read only).
    FENCE: Edit only symbols.txt entries for <FUNCTION> and the data it touches. Never edit src/ by hand. Do not touch functions another worker owns.
    CHECK: Run `python tools/decompile.py`, then `python tools/select_scenarios.py --run`, then `python tools/noise_report.py`. Done means the selected scenarios pass and the noise count does not rise.
    BUDGET: Stop after 5 tries without progress.
    IF BLOCKED: Stop. Do not work around it. Name the first differing frame or the noise line that will not go away.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the scenario and noise summaries. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whenEvery ledger row is proven: its scenarios pass and the noise report is at or below the baseline.

    Proof this works: tmnt-port, OutRunners Port, https://github.com/cheviman/arcade-decomp

  7. Work the hard tail

    Some code fights back. It may be code no scenario reaches, jumps that cross in ways C loops cannot show, or math chips with odd rounding. Each hard unit gets a proven answer or a written reason.

    • Reach rare code with poked scenarios. Put the proof that the real game never gets there in the script's header.
    • For crossed jumps, allow a control flag and record why in the ledger.
    • Model math chips exactly. The House of the Dead had to copy the coprocessor's square root and the PC's 24-bit float math.
    • Work on one routine at a time. Capture its registers and RAM at entry and return in MAME. Then run your C on the same entry state.
    Prompt for Claude
    GOAL: Prove <FUNCTION> at <ADDRESS>, which failed in bulk work, or give a proven reason it cannot be expressed as plain C.
    READ FIRST: CLAUDE.md, the ledger row and its failed-tries note, notes/findings.md, the MAME capture for <ADDRESS>.
    FENCE: Edit only symbols.txt for <FUNCTION> and notes/findings.md. Do not change the reference, the scenarios or tools/core/.
    CHECK: Run the routine compare for <ADDRESS> and `python tools/check_scenarios.py`. Done means 0 differences, or a written cause with addresses that a second session can reproduce.
    BUDGET: Stop after 6 tries that each test a different idea.
    IF BLOCKED: Stop. Do not work around it. Never call it impossible without the exact differing values.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the compare output. 3) Files changed. 4) The cause in one sentence. 5) New parking-lot items.
    Done whenpython tools/check_scenarios.py passes, and each hard row in ledger/functions.tsv says proven or points to a cause with addresses in notes/findings.md.

    Proof this works: The House of the Dead: ReWrithe, tmnt-port, segasonic-port

  8. Harden the whole-game check

    You make sure no old proof breaks. Every scenario runs on a clean clone. The structure of every function is checked against the program's jumps. A big-endian build runs the same scenarios.

    • Run python tools/check_scenarios.py --video --sound on a clean clone.
    • Run python tools/check_structure.py to check every function's ifs and loops against the program's jumps.
    • Run the big-endian check under qemu-ppc in WSL with python tools/big_endian_scenarios.py.
    • Store the last verified state in build/verified/ (or name a commit), so select_scenarios.py knows what changed.
    Prompt for Claude
    GOAL: Make the full check suite pass on a clean clone, including the big-endian build.
    READ FIRST: CLAUDE.md, PROGRESS.md, the arcade-decomp README section 'What is here' (select_scenarios.py and big_endian_scenarios.py).
    FENCE: Edit only tools/ wrappers, CMakeLists.txt and check.cmd. Do not change src/, symbols.txt or the reference.
    CHECK: On a fresh clone, run `python tools/check_scenarios.py --video --sound`, `python tools/check_structure.py`, `python tools/noise_report.py` and `python tools/big_endian_scenarios.py`. Done means all four pass, and a planted constant change in one function makes check_scenarios fail.
    BUDGET: Stop after 3 failed tries at the same error.
    IF BLOCKED: Stop. Do not work around it. Tell me what blocked you, what you tried, and what you need from me.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste all four summaries and the planted failure. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whenAll four checks pass on a fresh clone, and a planted change fails the scenario check.

    Proof this works: OutRunners Port, tmnt-port, https://github.com/cheviman/arcade-decomp

  9. Port it behind a platform layer

    Now the C is proven, so you can move it. Put the window, sound and input behind a small interface. Build for the new system. Keep the faithful arcade build next to any changed version, so both stay checkable.

    • Make one folder per front end: ports/sdl2, ports/headless, and one for each new system.
    • List every function the new version replaces in one file, such as console/replaced.txt. The arcade build keeps the originals.
    • Fix 64-bit and byte-order problems with sanitizers: -fsanitize=alignment or AddressSanitizer.
    • Build device packages on the player's computer from their own ROM. Never share them.
    • Write ports/<TARGET>/check.cmd. It runs every scenario on the new system's headless build and compares each frame hash with the reference. The core's big_endian_scenarios.py is a model for this.
    Prompt for Claude
    GOAL: Build <SET> for <TARGET_SYSTEM> and pass the same scenarios there.
    READ FIRST: CLAUDE.md, ports/PLAN.md, ports/sdl2/, console/replaced.txt.
    FENCE: Edit only ports/<TARGET>/ and the platform interface header. Do not change src/ or symbols.txt. Do not add features I did not ask for.
    CHECK: Run `ports\<TARGET>\check.cmd`, then `check.cmd`. Done means the first reports every frame hash matching the reference on all scenarios, and the desktop build still passes `check.cmd`.
    BUDGET: Stop after 4 failed builds at the same error.
    IF BLOCKED: Stop. Do not work around it. Tell me what blocked you, what you tried, and what you need from me.
    OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste both check summaries. 3) Files changed. 4) What is left. 5) New parking-lot items.
    Done whenports\<TARGET>\check.cmd and check.cmd both exit 0.

    Proof this works: tmnt-port, OutRunners Port, segasonic-port

Tools you need

ToolWhat it doesHow to get itHow we know
MAME
Required Windows
The emulator for almost every arcade board. Its debugger traces code, and Lua scripts can save RAM and registers each frame. Its source shows how each chip works.
Path A Path B
Download `mame0289b_x64.exe` from the MAME release page and run it. It unpacks to a folder. Start a game with `mame <SET> -debug`.MAME release page, command-line, debugger and Lua docs (read 2026-11-13): version 0.289, file mame0289b_x64.exe, -debug, -listfull, -listsource, -verifyroms, -aviwrite, -autoboot_script, the trace command, and emu.add_machine_frame_notifier (Lua reference page). Used by: Namco 22 Decompile and The House of the Dead: ReWrithe as the reference, and the three cheviman ports through MAME's CPU cores. Most other projects take MAME ROM sets as input.
Ghidra
Helpful Windows
A free disassembler and decompiler. It lists functions, shows C-like code and runs scripts with no window. For a chip it lacks, you write a processor module, as The House of the Dead did for the i960.
Path A Path B
Install JDK 25 64-bit. Download the `ghidra_<version>_PUBLIC_<date>.zip` release, extract it, and run `ghidraRun.bat`. For `GhidraMCP`, use the Ghidra version its release names (12.1.4 today).Ghidra README and latest release Ghidra_12.2_build, 2026-10-22 (read 2026-11-13). Used by: Namco 22 Decompile, The House of the Dead: ReWrithe (with its own i960 module), OpenGP's name sources.
arcade-decomp
Required both
Shared tools that decompile arcade programs into C with no CPU left in it. It has V60, V70, 68000 and Z80 frontends, references that run MAME's cores, and frame-by-frame checks.
Path B Path A
Add it to your game repo as a submodule: `git submodule add https://github.com/cheviman/arcade-decomp tools/core`. A clone made without it needs `git submodule update --init`. The games built on it ask for Python 3.10+, CMake 3.20+ and a C11 and C++17 compiler.arcade-decomp README and repo data (read 2026-11-13): submodule commands, BSD-3-Clause, created 2026-10-25, last push 2026-11-13, frontends for V60, V70, 68000 and Z80, references s32ref and kref. The README lists no version needs; Python, CMake and compiler versions come from the tmnt-port and OutRunners Port cards. Used by: segasonic-port, OutRunners Port, tmnt-port. Only for its listed CPUs and board families.
neogeorecomp
Helpful both
A static recompilation toolkit for Neo Geo games. Its m68krecomp turns the 68000 program into C, and its runtime models the Neo Geo board. It has a --verify mode against Musashi.
Path A
`git clone --recurse-submodules https://github.com/sp00nznet/neogeorecomp`, then `cmake -S . -B build`, `cmake --build build --config Release`, `ctest --test-dir build -C Release --output-on-failure`.neogeorecomp README (read 2026-11-13): v0.2.0 alpha, Windows (MSVC 2022) and Linux verified with games, MIT. Used by: KOF'98 Recomp (through a fork).
Musashi
Helpful both
A small 68000 family emulator in C. Projects use it as the fallback for code the recompiler missed, and as the oracle that checks each recompiled block.
Path A
Add it as a submodule: `git submodule add https://github.com/kstenerud/Musashi ext/musashi`. Toolkits like `neogeorecomp` already include it.Musashi README (read 2026-11-13): version 4.10, 68000 to 68040, MIT-style licence. Used by: Super-Hang-On-Ultimate, KOF'98 Recomp, The House of the Dead: ReWrithe (sound board).
Supermodel
Helpful Windows
An emulator for Sega Model 3. SpikeOut Recomp uses it as its first hardware reference, and draws the same 3D frame dump in both to compare.
Path A Path B
Download a Windows build from the Supermodel releases page on GitHub. Only needed for Model 3 games.Supermodel README and latest release v0.4-20261113 (read 2026-11-13): Windows, Linux and macOS builds on GitHub. Used by: SpikeOut Recomp.
decomp-toolkit (dtk)
Helpful Windows
A GameCube and Wii toolkit that also fits Triforce games. dtk dol split config.yml target splits main.dol into objects. A dtk-template project keeps its settings in config.yml, symbols.txt and splits.txt.
Path A Path B
Download the Windows binary from the releases page, or let a `dtk-template` project fetch a pinned copy with `python configure.py`.decomp-toolkit README (dol split section), release v1.8.4 with dtk-windows-x86_64.exe, and dtk-template README and configure.py, which pins dtk_tag (read 2026-11-13). Used by: OpenGP, mkgp2-decomp. Only for Triforce among arcade boards.
objdiff
Helpful Windows
A diff tool that compares your compiled function with the original, byte by byte. It supports PowerPC, SuperH, MIPS and x86, but not the 68000, V60 or i960.
Path B
Download `objdiff-windows-x86_64.exe` from the latest release. The CLI is on the same releases page.objdiff README and release v3.8.3 (read 2026-11-13). Used by: mkgp2-decomp (matching skill names objdiff). Only for boards whose chip it supports.
Visual Studio Build Tools and CMake
Required Windows
The C and C++ compiler for Windows, and the build system every reviewed project uses. Most projects build with cmake -S . -B build and cmake --build build --config Release.
Path A Path B
Install Build Tools for Visual Studio from the Visual Studio downloads page, with the C++ workload. Install CMake 3.20 or newer with the Windows `.msi` from cmake.org.Build steps in the cards for tmnt-port, segasonic-port, KOF'98 Recomp and The House of the Dead: ReWrithe (MSVC with CMake). The cmake.org download page (Windows x86_64 .msi) and visualstudio.microsoft.com/downloads (Build Tools) were read 2026-11-13. The reviewed projects name Visual Studio 2022; the page now offers a newer Build Tools.
Python 3 and Git
Required Windows
Python runs every helper script here: ROM checks, decompilers, scenario checks and configure.py. Git holds your code and pulls in toolkits as submodules.
Path A Path B
Install Python 3.10 or newer from python.org and add it to `PATH`. Install Git for Windows from git-scm.com.neogeorecomp README (Git, read 2026-11-13), dtk-template docs/dependencies.md (Python on PATH, read 2026-11-13), and the tmnt-port, OutRunners Port and segasonic-port cards (Python 3.10+). Both download pages answered on 2026-11-13.
Ninja
Helpful Windows
A small, fast build runner. A dtk-template matching project builds with ninja after python configure.py.
Path B
`pip install ninja`, or download it from the Ninja releases page and add it to `PATH`. Only needed for the Triforce matching route.dtk-template docs/dependencies.md (read 2026-11-13) and the mkgp2-decomp README (python configure.py then ninja).
QEMU user mode and a PowerPC GCC in WSL
Helpful WSL/Linux
qemu-ppc runs a 32-bit PowerPC Linux program on your PC. The big-endian check builds the headless game for PowerPC and runs every scenario under it, to catch byte-order bugs before a port.
Path B
In WSL Ubuntu: `sudo apt install qemu-user gcc-powerpc-linux-gnu`.outrunners-decomp README (read 2026-11-13) names the Debian and Ubuntu packages gcc-powerpc-linux-gnu and qemu-user. The arcade-decomp README says big_endian_scenarios.py uses qemu-ppc through WSL on Windows. The apt line itself was not run.
llvm-mingw
Helpful Windows
A Clang compiler for Windows. Use it when a project needs GCC-style features that MSVC lacks, such as weak symbols for function overrides.
Path A
Download `llvm-mingw-20261104-ucrt-x86_64.zip` from the releases page and unzip it to `C:\llvm-mingw`.llvm-mingw latest release 20261104 with the ucrt x86_64 zip (read 2026-11-13). Used by: Super-Hang-On-Ultimate (build.ps1 -Toolchain C:\llvm-mingw), OpenGP's installer.
MinGW-w64 GCC in WSL
Helpful WSL/Linux
GCC that builds Windows programs from Linux. Some arcade projects build only with GCC, or need a 32-bit Windows program.
Path A
In WSL Ubuntu: `sudo apt install gcc-mingw-w64-i686 make python3` for 32-bit. Namco 22 Decompile uses `x86_64-w64-mingw32-gcc` for 64-bit builds.Build steps in the VCThunder and Namco 22 Decompile cards (checked 2026-11-13). The mingw-w64.org page answered on 2026-11-13, but the install line comes from the VCThunder card, not from that page. Both projects also name an MSYS2 shell as another way.
SDL2 and SDL3
Required both
A library for the window, sound and game pads. SDL2 is most common here. SDL3 adds the SDL_GPU API that OpenGP and SpikeOut use for Vulkan and Metal.
Path A Path B
On Windows, unpack `SDL2-devel-2.32.10-VC.zip` from the SDL releases page. tmnt-port looks for it in `build/downloads/sdl2/`. In WSL: `sudo apt install libsdl2-dev`.SDL releases (read 2026-11-13): latest release-3.4.20 on 2026-11-03; newest SDL2 is release-2.32.10 with SDL2-devel-2.32.10-VC.zip. Setup path from the tmnt-port card. Used by: 11 of 12 reviewed projects.
ymfm
Helpful both
BSD-licensed cores for Yamaha FM sound chips. It covers the YM2151, YM2610, YM2612 and YM3438 found on many arcade boards.
Path A Path B
Add it as a submodule: `git submodule add https://github.com/aaronsgiles/ymfm ext/ymfm`. It needs only a C++14 compiler.ymfm README (read 2026-11-13): chip list and C++14 note. Used by: KOF'98 Recomp, tmnt-port, segasonic-port, OutRunners Port.

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

Lets Claude list, decompile and rename functions in your open Ghidra project. The mkgp2-decomp maintainer works through a Ghidra MCP bridge. Use it for the map step on any board Ghidra supports.

Install `uv`. In Ghidra 12.1.4, use File, Install Extensions to add the `ghidra_12.1.4_PUBLIC_<date>_GhidraMCP.zip` from the latest release, and restart. Then run `claude mcp add ghidra -- uvx --from git+https://github.com/LaurieWired/GhidraMCP ghidra-mcp --ghidra-server http://127.0.0.1:8080/`.

gamedecomp-library

skills.sh

Searches a list of about 790 decomp and reverse engineering projects. Use it once in the scope step, because arcade has many scattered toolkits. Use with care: its scripts download data.

npx skills add madpai/game-decomp-compendium --skill gamedecomp-library -a claude-code

static-recomp-scope-plan

skills.sh

Makes you write down what correct means before work starts: the exact set, the scenes to test, and the numbers to hit. That is your SCOPE.md.

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

ghidra-headless

skills.sh

Runs Ghidra with no window and saves functions and code to files. Use it when you want no MCP server. Set GHIDRA_HOME yourself on Windows.

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

static-recomp-av-compare

skills.sh

Scores your port's video and sound against recordings, scene by scene. Record the reference in MAME with -aviwrite. Its script paths need a fix for Claude Code.

npx skills add bgyss/switchrecomp --skill static-recomp-av-compare -a claude-code

native-platform-porting

skills.sh

Guides the port step of Path B. It warns Claude not to hide a small emulator inside the port, which matters when your C still reads board memory by address.

npx skills add lemiur/game-decompilation-skill-for-claude --skill native-platform-porting -a claude-code

verification-before-completion

skills.sh

Claude may not say done without running the check and showing it. On arcade, that means the hash compare output, not a screenshot that looks right.

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

systematic-debugging

skills.sh

No fix until the cause is found, and a rethink after three failed fixes. It fits the first-differing-frame hunt in Path A.

npx skills add obra/superpowers --skill systematic-debugging -a claude-code

handoff

skills.sh

Writes a short note so a fresh session can carry on. Tell it to save inside your repo, not the temp folder. SpikeOut Recomp keeps the same kind of note in docs/handoff.md.

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

fix-one-frame-diff

write-your-own

This is the Path A unit loop as a skill. Every reviewed recomp found bugs this way, from SpikeOut's onepc-diff.ps1 to Super Hang-On's per-frame hashes.

A project skill in `.claude/skills/fix-one-frame-diff/SKILL.md`. It takes a script name. It runs both sides, finds the first differing frame and byte, dumps RAM there, names the code that wrote the byte, and stops. It fixes nothing until you approve the cause. It lists the files it may edit.

prove-one-function

write-your-own

This is the Path B unit loop as a skill. It keeps every worker on the same steps and the same check.

A project skill in `.claude/skills/prove-one-function/SKILL.md`. It takes an address. It edits only `symbols.txt`, runs `tools/decompile.py`, runs `select_scenarios.py --run` and `noise_report.py`, and writes the result to the ledger. Model its layout on mkgp2-decomp's `.claude/skills/mkgp2-match/SKILL.md`.

Claude setup for this system

For Path A, one unit is one mismatch: the first frame where your hash differs from the reference. Each unit ends with every input script matching. For Path B, one unit is one function at one address. Each unit ends with its scenarios passing and the noise count not rising. Chip stand-ins are their own units, checked against MAME's picture or sound. The ledger, not the chat, says what is next.

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 projectName the board, the chips, the MAME set and revision. Search for toolkits and rewrites. Choose matching or behavior checks. 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 projectWrite verify_rom.py, the asset extractor with its --check, check.cmd, and the reference runner with its input scripts.Opus 5.5
effort medium
Sonnet 5.5
effort medium
Study the game fileMap every routine from the vectors, pointer scans and profile runs. Check the disassembler against MAME's. Fill symbols.txt with names and evidence.Opus 5.5
effort high
Opus 5.5
effort medium
Raise to high for function edges and data layouts. A mistake there spreads.
Bulk unitsProve many small functions, one per worker, through symbols.txt and the scenarios. In Path A, fix simple missing chip registers.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 unitsCrossed jumps, code no scenario reaches, math chips with odd rounding, and code the game copies to RAM. Each gets proof or a written cause.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 runtimeWrite the board in C: video chips, sound chips, inputs, timers and protection chips. Each one is checked against MAME by itself.Opus 5.5
effort high
Opus 5.5
effort medium
Raise to high for timing and graphics bugs.
Find a bugFind the first differing frame, then the first differing byte, then the code that wrote it. Prove the cause 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 reruns all scenarios on a clean clone and reads the diff. It hunts for edited hashes, skipped scenarios and edits to generated C.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, docs/unreachable.txt and notes/findings.md after each batch.Haiku 5.5
effort medium
Haiku 5.5
effort medium

How many sessions at once

Max 20x (now called Ultra)

Run one lead session and three to five workers, each in its own git worktree. In Path B, give each worker its own source file of functions. In Path A, give each worker one mismatch in a different part of the runtime. The House of the Dead project ran two or three sessions at a time and saw the weekly limit drain three times as fast. Run one verify session after each batch.

Max 5x (now called Max)

Run one lead session and one worker. Spend hard and debug jobs on the hours you watch. Start bulk batches at night, one function per worker. Scenario runs are slow, so let only one session run the full check at a time.

Lines for this project's CLAUDE.md

Add to CLAUDE.md
- Read SCOPE.md and PROGRESS.md at the start of every session.
- Run `check.cmd` after every change. If it fails, the task is not done.
- Never edit `build/generated/` or `src/`. Change `symbols.txt` or the generator, then regenerate.
- ROM files, reference hashes, `tests/controls/` and `tools/core/` are read-only.
- Never commit ROM data or anything made from it, including recompiled code.
- Prove every same-output claim with hashes. Never judge a frame by eye.
- Hardware reference order: MAME first, then <SECOND_REFERENCE>. Keep the copyright notice of any code you adapt.
- No stub may return a fake value. A missing register or call stops the run and prints its address.
- Enhancements default to off. The plain arcade build must still match the reference.
- Every run and every wait has a time limit. Stop a batch at its first failure.
- In a worktree, use the absolute path to the ROM folder: <ABSOLUTE_ROM_DIR>.
- Change only what was asked. Write other problems in notes/parking-lot.md and do not fix them.
- Commit only when I say so. Stage files by name, never with `git add -A`.

Keep the context small

  • Give Claude one address, one ledger row and the first differing frame, not a whole trace.
  • Never paste a MAME trace log. Let a subagent read it and return the first 20 lines that matter.
  • Keep CLAUDE.md under one page. Point to docs/hardware-notes.md and notes/findings.md by name.
  • Clear the chat after each unit. The ledger and PROGRESS.md carry the state.
  • Run local sessions for game work. A cloud session starts from a fresh clone and cannot see your ROM files.

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 learn which board the game uses and which path fits.

Prompt for Claude
GOAL: Tell me if <GAME> (MAME set <SET>) can be brought to PC, and by which technique.
READ FIRST: notes/mame-listsource.txt, notes/verifyroms.txt, the MAME driver <DRIVER_PATH> (top comment and machine setup only), notes/prior-work.md.
FENCE: Edit only SCOPE.md and notes/. Do not download ROMs, BIOS files or tools.
CHECK: Run `findstr /b /c:"Board:" SCOPE.md && findstr /b /c:"CPUs:" SCOPE.md && findstr /b /c:"Protection:" SCOPE.md && findstr /b /c:"Technique:" SCOPE.md && findstr /b /c:"Prior work:" SCOPE.md`. Done means all five lines print and it exits 0. CPUs gives each role and the video and sound chips. Protection says none or names the chip. Technique gives one reason against each other technique.
BUDGET: Stop after 60 minutes.
IF BLOCKED: If the board has no working MAME driver, or the set is encrypted with no known key, stop and say so plainly.
OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Your recommendation in one line, then the evidence. 3) Files changed. 4) Open questions. 5) New parking-lot items.

A good answer: DONE, then one technique. It cites the driver lines that name the chips, and lists toolkits like neogeorecomp or arcade-decomp if they fit.

Map the binary

After setup, to build the function ledger for the main program.

Prompt for Claude
GOAL: Build ledger/functions.tsv for the <CPU> program of <SET>.
READ FIRST: SCOPE.md, the Ghidra project <GHIDRA_PROJECT>, build/profile/misses.txt, build/reference/executed.txt.
FENCE: Edit only ledger/, notes/map.md and tools/check_ledger.py. Do not write C. Do not rename symbols in Ghidra yet.
CHECK: Run `python tools/check_ledger.py ledger/functions.tsv build/profile/misses.txt build/reference/executed.txt`. Done means it prints 0 missing and exits 0. Each row has address, size, kind and status. notes/map.md gives the row count by kind.
BUDGET: Stop after 90 minutes.
IF BLOCKED: If the Ghidra MCP server is down, stop and ask. Do not guess code from memory.
OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Counts and the executed-address check. 3) Files changed. 4) Unclear areas. 5) New parking-lot items.

A good answer: DONE with counts by kind. Zero executed addresses fall outside a row. Code copied to RAM is marked as its own kind.

Unit loop: fix one frame mismatch (Path A)

During the Path A grind, once per mismatch.

Prompt for Claude
GOAL: Make tests/controls/<SCRIPT>.txt match the reference past frame <FRAME>.
READ FIRST: CLAUDE.md, PROGRESS.md, build/diff/<SCRIPT>.txt, notes/findings.md.
FENCE: Edit only tools/recomp/ and runtime/. Never edit build/generated/, reference hashes or check scripts.
CHECK: Run `check.cmd`. Done means every script in tests/controls/ matches, and <SCRIPT> passes frame <FRAME>.
BUDGET: Stop after 3 failed fixes or 60 minutes.
IF BLOCKED: Stop. Give me the first differing frame, the byte, the code that wrote it, and your best cause.
OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the check summary. 3) Files changed. 4) The proven cause. 5) New parking-lot items.

A good answer: DONE with the check summary pasted. The cause names an address and a chip register or an instruction, and the fix is in the recompiler or runtime.

Unit loop: prove one function (Path B)

During the Path B grind, once per function.

Prompt for Claude
GOAL: Make <FUNCTION> at <ADDRESS> readable and proven.
READ FIRST: CLAUDE.md, the ledger row for <ADDRESS>, symbols.txt, src/<FILE>.c (read only).
FENCE: Edit only the symbols.txt entries for <FUNCTION> and the data it reads. Never edit src/ by hand.
CHECK: Run `python tools/decompile.py`, `python tools/select_scenarios.py --run` and `python tools/noise_report.py`. Done means the scenarios pass and the noise count does not rise.
BUDGET: Stop after 5 tries without progress.
IF BLOCKED: Stop. Name the first differing frame or the noise line that stays.
OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the scenario and noise summaries. 3) Files changed. 4) What is left. 5) New parking-lot items.

A good answer: DONE, with real names and types added, the selected scenarios passing, and the noise count the same or lower.

Batch dispatch

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

Prompt for Claude
GOAL: Start <N> workers on the next <N> units from ledger/functions.tsv.
READ FIRST: CLAUDE.md, PROGRESS.md, ledger/functions.tsv, notes/parking-lot.md.
FENCE: Edit only ledger/claims.tsv. Each worker gets its own worktree under .claude/worktrees/ and one source file nobody else owns. Do not do unit work yourself.
CHECK: After the batch, merge each worker's branch one at a time and run `check.cmd` after each merge. Done means every merged unit passes on the merged branch.
BUDGET: Stop the batch at its first failed merge.
IF BLOCKED: Stop. Do not work around it. Tell me which merge failed and why.
OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) A table of unit, worker, result. 3) Files changed. 4) Units to retry as hard jobs. 5) New parking-lot items.

A good answer: A table with one row per unit. Each merged unit passed the check after its own merge. Failed units are listed for the hard queue.

Debug with evidence

When the game crashes, hangs or draws wrong and the cause is not known.

Prompt for Claude
GOAL: Find the proven cause of <SYMPTOM> in tests/controls/<SCRIPT>.txt. Do not fix it yet.
READ FIRST: CLAUDE.md, the last 20 lines of build/logs/<SCRIPT>.log, build/diff/<SCRIPT>.txt.
FENCE: Edit only notes/findings.md and temporary files in build/tmp/. No code changes.
CHECK: Run `check.cmd` twice. Done means both runs report the same first differing frame, and notes/findings.md names that frame, the first differing byte or register, and the instruction that caused it, with addresses.
BUDGET: Stop after 60 minutes.
IF BLOCKED: Stop. Tell me what you ruled out and what you need next, such as a new MAME capture.
OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) The cause in one sentence, then the evidence. 3) Files changed. 4) A proposed fix for me to approve. 5) New parking-lot items.

A good answer: One cause with a frame number, an address and the value on each side. No code was changed.

Verify and hunt for cheating

After every batch, in a fresh session that did not do the work.

Prompt for Claude
GOAL: Check that the units claimed in PROGRESS.md since <COMMIT> are real.
READ FIRST: CLAUDE.md, `git diff <COMMIT>..HEAD --stat`, PROGRESS.md.
FENCE: Read only. Do not fix anything.
CHECK: On a fresh clone, run `check.cmd` and the full scenario check. Then look for edited reference hashes, removed or shortened scenarios, edited generated C, stubs that return fixed values, enhancements turned on by default, and edits outside each unit's fence.
BUDGET: Stop after 60 minutes.
IF BLOCKED: Stop. Tell me what you could not check and why.
OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
REPORT: 1) PASS or FAIL. 2) Paste the check outputs. 3) Each problem with file and line. 4) Claims you could not confirm. 5) New parking-lot items.

A good answer: PASS or FAIL with pasted outputs. Every problem names a file and line. Nothing was edited.

Status report

Once a week, or before you plan the next batch.

Prompt for Claude
GOAL: Report project status with numbers from the ledger.
READ FIRST: PROGRESS.md, ledger/functions.tsv, tests/controls/, notes/parking-lot.md.
FENCE: Read only. No prose padding.
CHECK: Get each count with a command, such as `findstr /c:"proven" ledger\functions.tsv | find /c /v ""`, and get the scenario count from `check.cmd`. Done means every number has the file or command beside it.
BUDGET: Stop after 15 minutes.
IF BLOCKED: Stop. Say which number you could not get.
REPORT: 1) Units done, in progress and blocked, by kind. 2) Scenarios passing out of total. 3) The noise count or mismatch count against last week. 4) The top three blockers. 5) Parking-lot items for me to decide.

A good answer: Short lists of numbers, each with its source. No claims without a file or command behind them.

Session handoff

At the end of a session, or when the context is getting full.

Prompt for Claude
GOAL: Write what the next session needs into the repo files.
READ FIRST: PROGRESS.md, notes/findings.md, the current task card.
FENCE: Edit only PROGRESS.md, notes/findings.md and docs/handoff.md.
CHECK: Run `findstr /b /c:"Current unit:" docs\handoff.md && findstr /b /c:"Next step:" docs\handoff.md && findstr /b /c:"Starting prompt:" docs\handoff.md`. Done means all three print. The file also holds the last check output and what was tried and failed.
BUDGET: Stop after 15 minutes.
IF BLOCKED: Stop. Say what you could not record.
OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) The next step in one line. 3) Files changed.

A good answer: A handoff file a fresh session can follow alone. It names dead ends, so no one retries them.

Blocked or cannot deliver

When Claude keeps trying the same thing, or says something should work.

Prompt for Claude
GOAL: Give me a plain answer on <TASK>: can it be done now, and how?
READ FIRST: the last task card, its report, notes/findings.md.
FENCE: Read only. Do not try again.
CHECK: Run `check.cmd` once and paste its last 20 lines. Do not change any file first. Your answer is one of DONE, PARTIAL or BLOCKED, with that output as proof. 'Should work' is not an answer.
BUDGET: Stop after 15 minutes.
IF BLOCKED: Say exactly what is missing: a MAME capture, a chip document, a ROM revision, or my decision.
OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) What cannot be done and why. 3) Two or three options, each with its cost in time. 4) Your pick and one reason.

A good answer: BLOCKED or PARTIAL in the first word, then a clear reason and two or three costed options.

Scope change request

When a task needs Claude to leave its fence, such as changing the reference or a toolkit.

Prompt for Claude
GOAL: Ask me before you change anything outside your fence for <TASK>.
READ FIRST: SCOPE.md, the current task card.
FENCE: Change nothing until I answer. Read only.
CHECK: Run `git status --short`. Done means it lists no file you changed, and your request names the files you want to change, why, what could break, and the check that proves it did not.
BUDGET: Stop after 10 minutes.
IF BLOCKED: Stop and wait for my answer.
OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them.
REPORT: 1) The change you want, in one line. 2) The files. 3) The risk. 4) The check that proves it safe. 5) What you will do if I say no.

A good answer: A short request that names files and a check. No files were changed before the owner said yes.

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 edits the generated C in build/generated/ or src/ to make a frame match.Generated C is never edited by hand. Change symbols.txt, the recompiler or the runtime, then regenerate. Block both folders with a hook.
Claude says a picture looks right and calls the unit done.Prove every same-output claim with hashes from a run you pasted. A screenshot is never proof.
Claude adds a stub that returns a fixed value, so the game gets past a chip check or protection chip.No stub may return a fake value. Model the chip from MAME's code, or stop the run and print the address.
Claude turns on widescreen or another extra by default while fixing something else.Enhancements default to off and sit behind a switch. The plain build must match the reference.
Claude copies ROM files or extracted assets into the repo, or into a worktree, to make a test run.Never commit ROM data or anything made from it. Use the absolute ROM path. A git check fails on any ROM-derived file.
A test loop waits forever for a string that never appears, and burns hours.Every run and every wait has a time limit. A batch stops at its first failure. Check the build is new before trusting a result.
Claude cleans up or refactors nearby code while fixing one mismatch.Change only what was asked. Write other problems in notes/parking-lot.md and do not fix them.

Problems other projects hit

Static search finds only part of the code. In SpikeOut, descent from the reset vector found about a quarter of it.

Fix: Add a pointer scan, make each instruction after a call an entry point, and run profile builds that log interpreter misses.

Seen in: SpikeOut Recomp, KOF'98 Recomp, The House of the Dead: ReWrithe

The game copies code to RAM at boot and runs it there. A static recompiler cannot see that code.

Fix: Let the interpreter run it, and mark it as its own kind in the ledger. KOF'98 interprets about 11.7 million instructions at start-up this way.

Seen in: KOF'98 Recomp

A CMake build with no build type was slow. Namco 22 ran about 1.8 times slower at -O0.

Fix: Force a default build type such as Release in CMakeLists.txt.

Seen in: Namco 22 Decompile, OutRunners Port

Translated C broke when built without -fno-strict-aliasing or -fwrapv, and clang rejected it.

Fix: Build translated code with GCC and both flags. Check the optimised build against -O0 with reference frames.

Seen in: Namco 22 Decompile

Comparing whole frames was the wrong cut for a game with a math coprocessor. Routines run mid-frame, and the chip's state is not in RAM.

Fix: Capture registers and RAM at each routine's entry and return in MAME, and prove routines one at a time.

Seen in: The House of the Dead: ReWrithe

MAME renamed chip files between versions, and merged sets put chips in other folders. ROM loading broke.

Fix: Find each chip by CRC32 and size inside the zip, not by file name.

Seen in: Namco 22 Decompile, CannonBall DX

The test tool and the shipped game ran network play in different ways. Tests passed on code players never ran.

Fix: Put every step in shared code that both the headless runner and the window use.

Seen in: SpikeOut Recomp

Some games need a protection or security chip. SegaSonic has an FD1149 chip, and Initial D needs a .pic dump.

Fix: Model the chip from MAME's notes, or require the player's own dump. List the chip in SCOPE.md on day one.

Seen in: segasonic-port, Initial D Arcade Stage 3 Recompiled

Two course files went missing because disc file names were cut short. The game read a null table and drew rainbow textures.

Fix: Check extracted disc names against the short-name limit of the disc format before you blame the renderer.

Seen in: Initial D Arcade Stage 3 Recompiled

Cloning without submodules leaves out tools/core and lan/, so tools fail or multiplayer says NO NETWORK.

Fix: Clone with --recursive, or run git submodule update --init.

Seen in: OutRunners Port, segasonic-port

How long it takes

Max 20x (now called Ultra)Max 5x (now called Max)One person, no AIHow sure
Path A: running on PC4 to 12 weeks10 to 30 weeks1 to 3 yearsmedium confidence
Path B: full decomp3 to 9 months7 to 22 months2 to 6 yearslow confidence

Read this first

These numbers assume one medium arcade game and one person who gives 10 to 15 hours a week. Three dated AI projects reached a first release two to six weeks after their first public commit. KOF'98 took one day from its new repo, but on a toolkit begun seven months earlier. Their authors were skilled, worked more hours, and often hid earlier work. So the ranges are wider than the raw dates. The Path B numbers rest on only two projects with stated AI use, so their confidence is low. A small 68000 game with a toolkit can be much faster. A 3D board with no toolkit can be much slower.

What makes it faster or slower

  • The board. A 68000 game with a toolkit is much faster than a 3D board with no toolkit.
  • How many chips run code. Each sound chip, math chip or I/O chip needs its own translation.
  • Protection and encryption. A security chip can block a project until someone models it.
  • Whether MAME emulates the board well. A weak MAME driver means no good answer key.
  • Program size. TMNT has 2,439 functions and OutRunners 762, while 3D games have thousands more.
  • For Path B, the compiler. Assembly games need behavior checks, which need many scenarios to cover the code.

The facts behind these numbers

ProjectWhat happenedLink
SpikeOut Recomp (Model 3)First commit 2026-10-19. First release 2026-11-05. Two contributors. Claude Code is a co-author on every commit.source
OpenGP (Triforce)First commit 2026-09-23. First public release 2026-11-02, after internal releases. Three contributors. Most code written by Claude Code.source
VCThunder (Midway, x86)Repo created 2026-08-19, first commit 2026-09-04, first release 2026-10-15. README says a few hundred hours, built with Claude.source
KOF'98 Recomp (Neo Geo)Repo created 2026-10-18, first release 2026-10-19, on the neogeorecomp toolkit whose repo was created 2026-03-21. Claude Code credited.source
The House of the Dead: ReWrithe (Model 2)MAME recordings dated 2026-10-07. Whole game playable at release 2026-11-01. Planned as 12 sessions, two or three at a time. Claude credited.source
tmntarcade-decomp (Konami 68000)Repo created 2026-10-29. By 2026-11-04 the README says all 2,439 functions decompiled and matching 18 scenarios. Built on a shared toolkit. The port's plan credits an agent.source
outrunners-decomp (Multi 32)First commit 2026-10-20. At review on 2026-11-13, 643 of 762 functions (84.4%) were free of CPU leftovers. AI use not stated.source
mkgp2-decomp (Triforce, matching)Repo created 2026-05-17. 94.61% of code matched on 2026-11-13, after 4,534 commits by three contributors with Claude and Codex agents.source
CannonBall (OutRun, no AI)Part-time hand port. A 2012-08-02 post says decompiling began three years earlier. The release post lists 1 year 10 months to convert the decompiled code to C++. Tag v0.02 marks a commit from 2012-09-30.source
Initial D Arcade Stage 3 Recompiled (NAOMI 2)Repo created 2026-08-16. First release 2026-09-01. One contributor. AI use not stated.source

Projects reviewed (12)

We took the top-starred project for each of the 12 most-starred arcade games on RecompLauncher. The catalog lists 24 arcade projects for 23 games, and the store flags 17 for AI use. For Path B we also read naari3/mkgp2-decomp from outside the catalog.

What each project teaches

Namco 22 Decompile

Namco 2x Systems (13 games)

Top rated on RecompLauncherstatic recompplayable
GhidraMAMEown CPU-to-C translatorsgccMinGW-w64CMake

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

AI: catalog flag only (set by the store); the repo says nothing about AI

Lesson: One shared engine can carry many games on one board. Translate sound and DSP chips at build time from the player's ROM, and check each against its interpreter.

Initial D Arcade Stage 3 Recompiled

Initial D Arcade Stage 3

Top rated on RecompLauncherstatic recompin progress
own SH-4 translator in PythonCMakeC++17VulkanXInput

Started: 2026-08. First release: 2026-09. Code: C++ and Python.

AI: none stated

Lesson: Tie every claim to one exact build hash, and keep a ledger of what is shown versus what is guessed. The public repo cannot build the game itself.

The House of the Dead: ReWrithe

The House of the Dead

Top rated on RecompLaunchernon-matching decompplayable
Ghidra with own i960 moduleMAME 0.289 with Lua capturesCMakeMSVCSDL3OpenGL

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

AI: yes: README says Claude assisted with reverse engineering and rewriting; parallel worker sessions on claude/* branches

Lesson: Prove routines one call at a time with MAME captures of entry and return state. Mark every unproven routine UNVERIFIED so a script can list them.

OutRunners Port

OutRunners

Top rated on RecompLauncherport of a decompplayable
arcade-decomps32ref (MAME V60 core)CMakeMSVC, GCC, ClangSDL2ymfm

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

AI: none stated

Lesson: Start with a one-line-per-instruction scaffold that already matches MAME, then grow readable C from it. A counted noise baseline keeps readability from sliding back.

CannonBall DX

OutRun

Top rated on RecompLaunchermod of a portplayable
CMake presetsMSVCvcpkgSDL2miniz

Started: 2012-09. First release: 2026-08. Code: C++.

AI: yes: README says the fork's extra work had help from ChatGPT and Claude

Lesson: If a mature rewrite of your game exists, build on it instead of starting over. Find ROM files by CRC32, not by name.

tmnt-port

Teenage Mutant Ninja Turtles

Top rated on RecompLauncherport of a decompplayable
arcade-decompkref (MAME 68000 and Z80 cores)CMakeMSVC, GCC, ClangSDL2ymfm

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

AI: yes: console/PLAN.md credits two fixes to an agent's work, checked by its diff; no agent files

Lesson: Build the reference first, then write scenarios that reach every area and boss. Keep the arcade build untouched and list each replaced function in one file.

VCThunder

Hydro Thunder; Offroad Thunder

Top rated on RecompLauncherotherplayable
i686-w64-mingw32-gccGNU makePython 3SDL3own Glide rasteriser

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

AI: yes: README says it began as a personal challenge to see how far Claude could be used to vibe code it

Lesson: When the board's chip is x86, you may not need to decompile. Run the original code in place and replace only the kernel, graphics and I/O around it.

OpenGP

Mario Kart Arcade GP

Top rated on RecompLauncherstatic recompplayable
gekkorecompdecomp-toolkitclang-clllvm-mingwCMake with NinjaSDL3 GPU

Started: 2026-09. First release: 2026-11. Code: C++.

AI: yes: README 'Made with AI' says most code and docs are written by Claude through Claude Code

Lesson: Import names instead of inventing them: from a signature database, from a sister game's decomp, and from identical code in the sister game.

SpikeOut Recomp

SpikeOut: Final Edition

Top rated on RecompLauncherstatic recompplayable
ppcrecomp (own)LLVM 18.1.8 ORC JITSupermodelgamerunCMake with NinjaSDL3

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

AI: yes: README says Claude Code is a contributor to every commit; CLAUDE.md and docs/handoff.md hold the rules Agent files: CLAUDE.md.

Lesson: Count cycles at build time so every run is bit-identical. That one choice makes hash proofs, replays, save states and rollback netplay possible.

SegaSonic the Hedgehog: Native Port

SegaSonic the Hedgehog

Top rated on RecompLauncherport of a decompplayable
arcade-decomps32ref (MAME V60 core)CMakeMSVC, GCC, ClangSDL2ymfm

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

AI: catalog flag only (set by the store); the repos do not mention AI

Lesson: Make coverage a goal. Count which instructions the scenarios run, and write down why each unrun piece of code never runs.

KOF'98 Recomp

The King of Fighters '98

Top rated on RecompLauncherstatic recompplayable
neogeorecomp (m68krecomp)MusashiCMakeVisual Studio 2022SDL2ymfm

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

AI: yes: README credits Claude Code as AI pair programmer; every change tested by the owner

Lesson: Start from an existing toolkit and its sample game. Require the --verify mismatch count, here 0 over 12.1 million blocks, in every pull request.

Super-Hang-On-Ultimate

Super Hang-On

Top rated on RecompLauncherstatic recompplayable
own 68000-to-C recompiler (recomp.py)Musashillvm-mingwDirect3D 11SDL2

Started: 2026-11. First release: 2026-11. Code: C, Objective-C and Python.

AI: none stated

Lesson: Reuse the interpreter's own instruction handlers in the recompiler. Then a per-frame hash of all RAM and registers can prove the two are identical.

What we could not check

  • How AI was used in most projects. Only SpikeOut Recomp publishes its agent rules. The others give one README line or nothing.
  • Whether Namco 22 Decompile, SegaSonic or Super Hang-On used AI. The store flags two of them, but the repos say nothing.
  • The name and code of Namco 22 Decompile's main CPU translator. Only its output is public.
  • The original compiler for any reviewed V60, i960, SH-4, Model 3 or Namco game. No project names one.
  • That most 1980s arcade games were written in assembly. We confirmed it only for OutRun, from the CannonBall README.
  • The mkgp2-decomp compiler. Its README calls CodeWarrior 2.7 a guess still to be re-checked.
  • The total hours behind any project. Most hide early work, and only VCThunder gives a rough figure.
  • A reported Sonic the Fighters decomp from May 2025. The news page returned an error, so we could not read it.
  • The MinGW-w64 apt install line. It comes from the VCThunder card, not from mingw-w64.org.
  • That the static-recomp-av-compare skill works with MAME's -aviwrite recordings. We did not test it.
  • The command-line arguments of arcade-decomp's scripts. Its README names each script and some switches (--video, --sound, --run, --big-endian), but no full usage. No script was run here.
  • Which JDK Ghidra 12.1.4 needs for GhidraMCP. The Ghidra README read here is for 12.2, which asks for JDK 25.
  • That check_ledger.py, golden.cmd, check.cmd switches and ports/<TARGET>/check.cmd work as described. They are scripts you write; no reviewed project ships them under these names.
  • None of the commands in this guide were run on a real game here. They come from tool docs and project READMEs.
  • The 1971 date. It comes from the site's shared platform table, not from a source we read.

Sources