PC (DOS and Windows) decomp guide
The game already runs on x86, so the hard parts are Windows calls and old compilers.
What this system is like
An old PC game already runs on the same kind of chip as your PC. So you do not need to copy a console. The work is about Windows. Old games call DirectDraw, Direct3D and DirectSound in ways new Windows breaks. Many are 32-bit only, and some use copy protection.
Path A gets the game to run as a fresh, native program. The method most new projects use is static recompilation. A tool turns each function of the .exe into C. Then you write a small layer for the Windows and DirectX calls. pcrecomp, Black Ops II Recompiled and the Road Rash port all work this way.
Path B rebuilds the game as real source code. If the game was built with old Visual C++, you can match it byte for byte. The tool reccmp checks each function against the original .exe. LEGO Island is complete, and its build makes all three game files byte for byte. Carmageddon and Colin McRae Rally 2.0 are on their way.
Almost all of the work runs on Windows. You need WSL only for a few tools and for a Linux build. Many famous PC projects are not decomps at all. They are new engines, or games whose makers released the source. Check for those first.
Same chip as your PC
The game's code is already x86. So no part of the job is about copying a strange CPU. The hard parts are floating point details, 32-bit pointers and old Windows calls.
Windows is the console
On other systems the runtime stands in for the hardware. On PC it stands in for old Windows and DirectX. pcrecomp can forward calls to real Windows, so a first boot can come early.
Old Visual C++ can be matched
reccmp checks each rebuilt function against the original .exe. Its README names old Visual C++ such as 4.20, and CMR2Decomp uses it with Visual C++ 6. LEGO Island's build makes all three of its files byte for byte.
Symbols sometimes leak
Some PC games shipped with debug files. Space Cadet Pinball has a public PDB (a debug symbol file) from Microsoft. Carmageddon had Watcom symbols left on its Splat Pack expansion CD. The Devilution team used a symbol file from Diablo's PlayStation port.
Copy protection can block you
Some disc and store copies are encrypted or wrapped. A recompiler cannot read encrypted code. The Need for Speed project could not use the protected .exe from its own discs.
Many famous projects are not decomps
OpenRA, OpenMW and OpenRCT2 are new engines that load the old data. Warzone 2100's makers released its source in 2004. Look for these before you start, because they may already do what you want.
Two paths
Get it running on PC
The game already runs on x86, so here running means a clean native build. A lifter turns each function into C. You link that C to a runtime that answers the Windows and DirectX calls. Then you fix one crash or one missing call at a time. A recorded replay that matches the original is the final proof.
Full decomp for porting
You write C or C++ that the original Visual C++ turns into the same bytes. reccmp scores each function against the retail .exe. When every function matches, you have true source. Then you move the Windows parts behind an interface and port it. If the compiler is too new to match, you fall back to a non-matching decomp checked by tests.
Path A: Get it running on PC
The game already runs on x86, so here running means a clean native build. A lifter turns each function into C. You link that C to a runtime that answers the Windows and DirectX calls. Then you fix one crash or one missing call at a time. A recorded replay that matches the original is the final proof.
Method: static recompilation
Pick this when you want the game to run well on Windows 11 soon. It also suits games built with a compiler reccmp cannot match yet.
Scope the game and check for prior work
You pick one exact
.exeand record its hash. Then you look for work that already exists. Released source, a new engine or a finished decomp can save you months. You also check for copy protection and leftover symbols.- Install Python, Git and
pcrecompfirst (see the tools list). Below,<PCRECOMP>means the folder where you clonedpcrecomp. - In PowerShell, run
Get-FileHash <GAME>.exeand save the SHA-256 inSCOPE.md. - Search GitHub for the game name plus
decomp,recompandsource port. Read each project'sCONTRIBUTING.mdandAGENTS.mdbefore you use it. - Run
python <PCRECOMP>/tools/pe/analyze_sections.py <GAME>.exe. It flags SafeDisc, SecuROM, UPX and other packers. - If the file is protected, stop. Use a DRM-free edition you own, such as a GOG copy, or pick another game.
- Look for symbols: a
.pdb, a.mapfile, a debug build, a demo, or a port to another system. - Write
SCOPE.md: the goal, the hash, the technique, the first milestone, and what Claude must never edit.
Prompt for ClaudeGOAL: Draft SCOPE.md for a native PC rebuild of <GAME>, version <VERSION>. READ FIRST: The output of `Get-FileHash <GAME_DIR>\<GAME>.exe` and `python <PCRECOMP>/tools/pe/analyze_sections.py <GAME_DIR>\<GAME>.exe`. My notes in notes/prior-work.md. FENCE: Edit only SCOPE.md and notes/prior-work.md. The game folder is read-only. Do not download any game files, keys or compilers. CHECK: Run `Select-String -Path SCOPE.md -Pattern '<SHA256>'`. Done means it prints the hash line, and SCOPE.md also names the copy protection result, every prior project with its URL and AI policy, the technique, and the first milestone with its check. BUDGET: Stop after 45 minutes of searching. IF BLOCKED: If the exe is encrypted or packed, stop and tell me. Do not look for ways to remove the protection. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the hash and the protection result. 3) Files changed. 4) Open questions for me. 5) New parking-lot items.
Done whenSelect-String -Path SCOPE.md -Pattern '<SHA256>'finds the hash, the file holds the protection result and the prior-work list, and you approved it.Proof this works: Warzone 2100, nfs-most-wanted-mac, https://github.com/sp00nznet/pcrecomp
- Install Python, Git and
Set up the repo and the one check
You make a repo that holds only your own code. The game files stay in a folder outside it. Then you write one check command that Claude runs after every change.
- Install Visual Studio 2022 with the
Desktop development with C++workload. It includesCMake. - If you have not yet, run
git clone https://github.com/sp00nznet/pcrecomp, thenpip install capstone pefile lief unicorn cryptography, the line in its README. - Copy
templates/CMakeLists.txt.templateandtemplates/.gitignore.templatefrompcrecompinto your repo. - Keep the game in a folder such as
D:\games\<GAME>. Addsrc/recomp/gen/to.gitignore, because lifted output never goes in git. - Write
check.cmd. It builds withcmake --build build, runspython <PCRECOMP>/tools/lift/difftest.py, then runs your own tests as you add them. difftest.pycompiles C withgcc,clangorcc, or with the compiler named inRECOMP_CC. Make sure one of them is on your path.- Write
CLAUDE.md,PROGRESS.mdandnotes/parking-lot.md.
Prompt for ClaudeGOAL: Make `check.cmd` build the project and run every check in one command. READ FIRST: SCOPE.md, CLAUDE.md, the pcrecomp README section 'Starting a New Project'. FENCE: Edit only CMakeLists.txt, check.cmd, .gitignore and tools/. Do not add features, refactors or tools I did not ask for. Never copy game files into the repo. CHECK: Run `check.cmd`. Done means it exits 0 on a clean clone, and exits non-zero after you add a deliberate compile error. 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. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whencheck.cmdpasses on a clean clone and fails when you break one file on purpose.Proof this works: OpenSC2K, https://github.com/sp00nznet/pcrecomp
- Install Visual Studio 2022 with the
Map the exe
You list every function, import and class in the game. You mark the C runtime and library code, so nobody lifts it by hand. You also count unusual instructions, so you know what the lifter must handle.
- Run
python <PCRECOMP>/tools/pe/pe_analyze.py <GAME>.exe --json config/pe_analysis.json. - Run
python <PCRECOMP>/tools/pe/extract_imports.py <GAME_DIR>to list every Windows call across the install. - Run
python <PCRECOMP>/tools/disasm/disasm32.py <GAME>.exe --output functions.json --pe-json config/pe_analysis.json. - On C++ games, run
python <PCRECOMP>/tools/cpp/rtti.py <GAME>.exe -o ledger/rtti.jsonto find classes and vtables (tables of method addresses). - If you have a
PDBor.map, score the list:python <PCRECOMP>/tools/disasm/score_recovery.py --reference <REFERENCE> --candidate functions.json.pdb_ref.pyandpdb2_ref.pyintools/pe/make a reference from a PDB. - Open the exe in Ghidra and compare its function list with yours. Fix the edges before you lift.
- Write
ledger/functions.tsvwith address, size, kind (game, CRT, library, thunk) and a status column. - Write
tools/progress.py. It counts ledger rows per kind and status, and exits non-zero if a row has no kind or status.
Prompt for ClaudeGOAL: Produce ledger/functions.tsv for <GAME>.exe with one row per function. READ FIRST: SCOPE.md, config/pe_analysis.json, functions.json. Use the Ghidra MCP server for cross-checks. FENCE: Edit only ledger/, notes/ and tools/progress.py. The exe and the Ghidra project's original bytes are read-only. CHECK: Run `python tools/progress.py`. If a PDB or MAP exists, also run `python <PCRECOMP>/tools/disasm/score_recovery.py --reference <REFERENCE> --candidate functions.json`. Done means progress.py exits 0 and you report precision and recall. BUDGET: Stop after 90 minutes, or after 3 failed tries to fix the same function edge. IF BLOCKED: If the Ghidra MCP server does not answer, stop and ask me. Do not guess addresses from memory. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the counts per kind and the score. 3) Files changed. 4) Functions with unsure edges. 5) New parking-lot items.
Done whenpython tools/progress.pyexits 0 with no row missing a kind or status, and the edge score is saved innotes/.Proof this works: Resident Evil PC Decomp, nfs-most-wanted-mac, https://github.com/sp00nznet/pcrecomp
- Run
Lift the code and test the lifter
The lifter turns every function into C. Claude never edits that C by hand. If it is wrong, you fix the lifter input and run it again. Two tests guard the lift.
difftest.pychecks the lifter on its own test cases. Your own test checks your game's functions.- From the
<PCRECOMP>folder, runpython -m tools <GAME_DIR>/<GAME>.exe --all --output <YOUR_REPO>/src/recomp/gen/. - Run
python <PCRECOMP>/tools/lift/difftest.py -v. It runs the lifter's built-in cases as C and inUnicorn, and compares every register, flag and written byte. - Write
tools/difftest_game.pyfor your game. Like the Need for Speed port'srecomp/difftest.py, it runs one lifted function and its original bytes inUnicornfrom the same state and compares. - Write any custom lift rules in your own
run_lift.py, as thepcrecompREADME says. - Record each lifter bug in
notes/findings.mdwith the instruction that caused it.
Prompt for ClaudeGOAL: Lift <GAME>.exe to C and make both lift tests pass. READ FIRST: SCOPE.md, ledger/functions.tsv, the pcrecomp README parts on lift32 and difftest. FENCE: Edit only run_lift.py, config/, tools/difftest_game.py and notes/. Never edit files in src/recomp/gen/; change the lifter input and regenerate instead. CHECK: Run `check.cmd`. Done means `python <PCRECOMP>/tools/lift/difftest.py -v` and `python tools/difftest_game.py` pass every case, and the lift reports 0 errors. BUDGET: Stop after 3 failed tries on the same instruction. IF BLOCKED: Stop. Name the instruction and address that fails, and what you tried. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste both test summaries and the lift error count. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whendifftest.py -vandtools/difftest_game.pyboth pass, and the lift log shows 0 lift errors.Proof this works: nfs-most-wanted-mac, Black Ops II Recompiled, https://github.com/sp00nznet/pcrecomp/blob/main/tools/lift/difftest.py
- From the
Boot to the first frame
You link the lifted C to a runtime and start it. On Windows, the
native32runtime forwards calls to real Windows. That gets you to a first frame fast. Any call that is not ready yet must stop the program with a clear error.- Use
runtime/recomp32and host it withruntime/native32frompcrecomp. - Build with
cmake --build buildand run the program from the game folder. - Make every missing function abort with its address. Never let it return a fake value.
- Write
tools/golden.cmd. It starts the game, waits a set time, and saves a screenshot and a log line. - Save the first good screenshot as the reference in
tests/golden/.
Prompt for ClaudeGOAL: Boot the recompiled <GAME> to its first frame on Windows 11. READ FIRST: SCOPE.md, PROGRESS.md, notes/findings.md, runtime/native32/native32.h and the pcrecomp README parts on native32. FENCE: Edit only runtime glue in src/host/ and tools/golden.cmd. Never edit src/recomp/gen/. No stub may return a made-up value; missing calls must abort with their address. CHECK: Run `check.cmd`. Done means tools/golden.cmd exits 0 and saves a screenshot of the first frame. BUDGET: Stop after 4 crashes with no new evidence, or 60 minutes with no progress. IF BLOCKED: Stop. Paste the last log lines and the crash address, and tell me what you need. 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 screenshot path. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whentools/golden.cmdstarts the game with no person, reaches the first frame, and saves the screenshot.Proof this works: Black Ops II Recompiled, https://github.com/sp00nznet/pcrecomp
- Use
Fix one crash or one call at a time
This is the long middle. Each session fixes one crash, one missing Windows call, or one wrong picture. Claude must prove the cause with a log or a trace before it changes code. Honest stubs matter, because a fake answer can break the game far away.
- Pick the next item from
PROGRESS.md. Give Claude only that item. - Replace a game function through a hook list by address, as
hooks.txtdoes in the Need for Speed port. - Copy the original's x87 settings. Direct3D 9 sets the FPU to 24-bit precision unless the game passes
D3DCREATE_FPU_PRESERVE. - Log every place where the program falls back or aborts, so the next gap is easy to find.
- Rerun
check.cmdand the golden run after every fix.
Prompt for ClaudeGOAL: Fix crash <CRASH_ID> at <ADDRESS> in <GAME>. READ FIRST: PROGRESS.md entry <CRASH_ID>, notes/findings.md, logs/<RUN>.log. Ask the Ghidra MCP server for the function at <ADDRESS>. FENCE: Edit only src/host/ and hooks.txt. Never edit src/recomp/gen/. Do not change any other crash, feature or file. CHECK: Run `check.cmd`. Done means the golden run passes and the run gets past <ADDRESS> with no new aborts. BUDGET: Stop after 3 failed fixes, or 45 minutes with no new evidence. IF BLOCKED: Stop. Do not add a stub that returns success. Tell me the cause you proved, what you tried, and what you need. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) The proven cause with the log lines, then the check output. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenThe crash is gone, the golden run passes, andPROGRESS.mdmarks the item done with its cause.Proof this works: Black Ops II Recompiled, nfs-most-wanted-mac, Roadrash
- Pick the next item from
Swap in a modern graphics and sound layer
Old DirectDraw and Direct3D calls break on new Windows. You put them behind one small interface. Then you draw with
SDL3or Direct3D 11 and play sound withSDL3. A frame hash proves the picture did not change.- List every DirectX call the game uses from the import table.
- Write one interface file, such as
src/port/gfx.h, and route all drawing calls through it. - Get
SDL3-devel-<VERSION>-VC.zipfrom the SDL releases page. Or, withvcpkg, runvcpkg new --application, thenvcpkg add port sdl3. - Save a hash of the back buffer (the picture before it hits the screen) for set frames.
- Compare those hashes with the reference frames from the old path.
Prompt for ClaudeGOAL: Draw <GAME> through src/port/gfx.h with the <BACKEND> backend. READ FIRST: SCOPE.md, notes/directx-calls.md, tests/golden/. FENCE: Edit only src/port/ and src/host/gfx*. Never edit src/recomp/gen/. Do not add new graphics features. CHECK: Run `check.cmd`. Done means the frame hashes for <FRAME_LIST> match the reference, and the golden run passes. BUDGET: Stop after 3 failed tries on the same draw call. IF BLOCKED: Stop. Name the call and the frame that differ, and show both images' paths. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the frame hash table. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenThe frame hashes match the reference andcheck.cmdpasses.Proof this works: Resident Evil PC Decomp, OpenCMR2, Roadrash, https://github.com/libsdl-org/SDL/releases, https://github.com/microsoft/vcpkg/tree/master/ports/sdl3
Harden with replays and package it
You record inputs and replay them in the original and in your build. The results must match frame for frame. Then you package the build without any game files.
- Record a set of inputs that play the attract mode and two levels.
- Replay them in the original game and in your build. Compare state or frames.
- Make every replay part of
check.cmd. Road Rash requires 14 matching replays before each release. - Run
python <PCRECOMP>/tools/audit_repo.py <YOUR_REPO>to find game material in git, even in old commits. - Ship a setup step that reads the user's own copy and checks its hash.
Prompt for ClaudeGOAL: Add replay tests for <GAME> and make them pass on a clean clone. READ FIRST: SCOPE.md, PROGRESS.md, tests/replays/README.md. FENCE: Edit only tests/, tools/ and check.cmd. Never change a recorded reference to make a test pass. CHECK: Run `check.cmd` on a fresh clone. Done means all <N> replays match the original and `python <PCRECOMP>/tools/audit_repo.py .` finds no game material. BUDGET: Stop after 3 failed tries on the same replay. IF BLOCKED: Stop. Tell me which replay differs, at which frame, and what you tried. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the replay table and the audit output. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenEvery replay matches on a clean clone and the repo audit finds no game files.Proof this works: Roadrash, OpenRCT2, OpenSC2K
Path B: Full decomp for porting
You write C or C++ that the original Visual C++ turns into the same bytes. reccmp scores each function against the retail .exe. When every function matches, you have true source. Then you move the Windows parts behind an interface and port it. If the compiler is too new to match, you fall back to a non-matching decomp checked by tests.
Method: matching decompilation
Pick this when you want the game on other systems, or want source you can trust. It works best for games built with Visual C++ 4.2 to 6.
Find the compiler and the symbols
Matching needs the exact compiler and its options. The Rich header inside the
.exerecords the Microsoft tools that built it. You also hunt for symbols, because names save weeks. Then you decide: matching or non-matching.- Run
Get-FileHash <GAME>.exeand save the SHA-256. - Read the Rich header with the
re-binary-reconskill or a PE tool. Note the Visual C++ version and build number. - Look for a
.pdb, a.map, a.SYMfile, a debug build, demos and ports. The Devilution team used a symbol file from Diablo's PlayStation port. - Check that
reccmpsupports the compiler. It handles old MSVC such as 4.20 today. - Write the compiler, flags, symbols and choice in
SCOPE.md.
Prompt for ClaudeGOAL: Draft SCOPE.md for a decomp of <GAME>.exe, version <VERSION>, and pick matching or non-matching. READ FIRST: The Rich header dump in notes/rich.txt, the reccmp README, notes/prior-work.md. FENCE: Edit only SCOPE.md and notes/. The game folder is read-only. Do not download compilers, symbols or game files. CHECK: Run `Select-String -Path SCOPE.md -Pattern '<SHA256>','<COMPILER>'`. Done means both are found, and SCOPE.md names the build number, the likely flags, every symbol source with its path, and a matching or non-matching choice with one reason. BUDGET: Stop after 45 minutes. IF BLOCKED: If the compiler cannot be identified, stop and say so. Do not guess a version. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the Rich header lines you used. 3) Files changed. 4) Open questions. 5) New parking-lot items.
Done whenSelect-String -Path SCOPE.md -Pattern '<SHA256>','<COMPILER>'finds both, the file names the flags, symbol sources and technique, and you approved it.Proof this works: DevilutionX, Dethrace, SpaceCadetPinball, https://github.com/pablocpas/CMR2Decomp
- Run
Set up the old compiler and reccmp
You build with the same old compiler the game used. It runs on Windows 11, so you do not need WSL here.
reccmpmakes the project files and the first comparison. The original.exestays outside the repo.- Get the original Visual C++ version from a copy you have the right to use. Keep it in a path with no spaces.
- Open
cmd, run itsBIN\VCVARS32.BAT x86, then runcmake <SRC> -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo. - Build with
nmake && nmake, as the LEGO Island README advises. - Make a Python 3.11 or newer virtual environment, as the
reccmpREADME advises. Then runpip install reccmp. - Run
reccmp-project create --originals <GAME_DIR>\<GAME>.exe --cmake-project. - Build into a
buildfolder. Run everyreccmp-command from there, becausereccmp-build.ymllives there. - Write
check.cmd: build,cd build, thenreccmp-reccmp --target <TARGET>. You add--diff base.jsonin step 4.
Prompt for ClaudeGOAL: Make `check.cmd` build <GAME> with <COMPILER> and print a reccmp report. READ FIRST: SCOPE.md, the reccmp README 'Fresh project' section, CLAUDE.md. FENCE: Edit only CMakeLists.txt, check.cmd, reccmp-project.yml and tools/. Never copy the original exe or the compiler into the repo. CHECK: Run `check.cmd`. Done means it builds and `reccmp-reccmp --target <TARGET>`, run in build/, prints a function list with scores. BUDGET: Stop after 3 failed tries at the same error. IF BLOCKED: Stop. Do not swap in a newer compiler. Tell me what failed and what you need. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the first 20 lines of the report. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whencheck.cmdbuilds with the old compiler andreccmpprints a score list.Proof this works: Dethrace, https://github.com/isledecomp/isle, https://github.com/isledecomp/reccmp
Map and triage every function
You list every function in the
.exeand sort it. Game code gets matched. C runtime, compiler glue and import thunks are marked out of scope. This keeps the done count honest.- Open the exe in Ghidra. Connect
GhidraMCPso Claude can list, decompile and rename. - Export the function list to
ledger/functions.tsvwith address, size, kind and status. - Mark CRT, exception handling and thunk functions as out of scope. The Resident Evil project set aside 290 CRT functions.
- Have Claude rename functions in Ghidra as it learns them, so the next session sees the names.
- Write
tools/progress.py. It counts done functions from the ledger and fails on a row with no kind or status.
Prompt for ClaudeGOAL: Build ledger/functions.tsv for <GAME>.exe and triage every function. READ FIRST: SCOPE.md. Use the Ghidra MCP server for the function list and names. FENCE: Edit only ledger/, notes/, tools/progress.py and names inside the Ghidra project. Do not write any C yet. CHECK: Run `python tools/progress.py`. Done means every function has a kind (game, CRT, SEH, thunk, library) and a status, and the totals add up to the Ghidra count. BUDGET: Stop after 90 minutes. IF BLOCKED: If the Ghidra MCP server is not reachable, stop and ask me. 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) Paste the totals per kind. 3) Files changed. 4) Unsure functions. 5) New parking-lot items.
Done whenpython tools/progress.pyprints a total equal to Ghidra's function count, and no row lacks a kind or status.Proof this works: Resident Evil PC Decomp, https://github.com/LaurieWired/GhidraMCP
- Open the exe in Ghidra. Connect
Match one function end to end
You prove the whole chain on one small function. Then you prove the check can fail. A check that never fails is not a check.
- Pick a small leaf function, one that calls nothing.
- Write it in C with the note
// FUNCTION: <TARGET> 0x<ADDRESS>above it. - Run
reccmp-reccmp --target <TARGET> --verbose 0x<ADDRESS>. It must show 100%. - Break one line on purpose and confirm the score drops. Then undo it.
- Save
reccmp-reccmp --target <TARGET> --json base.json --silentas the first baseline. - Add
--diff base.jsonto thereccmp-reccmpline incheck.cmd.
Prompt for ClaudeGOAL: Make <FUNCTION> at 0x<ADDRESS> match 100% in reccmp. READ FIRST: SCOPE.md, CLAUDE.md, the Ghidra decompile of 0x<ADDRESS>. FENCE: Edit only src/<FILE>.cpp, and only this function. Do not add inline assembly, naked functions or embedded bytes. CHECK: Run `reccmp-reccmp --target <TARGET> --verbose 0x<ADDRESS>`. Done means 100%, and a deliberate one-line break makes it drop. BUDGET: Stop after 10 tries with no gain. IF BLOCKED: Stop. Paste the best diff and say which lines still differ. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the 100% line and the failing-test line. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenOne function shows 100% inreccmp, and a deliberate break makes the score drop.Proof this works: Dethrace, https://github.com/isledecomp/reccmp
Run the matching loop in parallel
Now workers match functions one at a time, easy ones first. Each worker owns one file in its own git worktree. Every result is compared with the saved baseline, so a new match cannot break an old one.
- Sort the ledger by size and pick the smallest open functions first.
- Give each worker one function and its own worktree.
- Before editing, map the locals to stack slots, as Dethrace does with
get_stack_slots.py. - Change one thing at a time and rerun the diff. Undo any change that lowers the score.
- Merge only when
reccmp-reccmp --target <TARGET> --diff base.jsonshows no drops. Then save a new baseline.
Prompt for ClaudeGOAL: Match <FUNCTION> at 0x<ADDRESS> in <FILE>. READ FIRST: CLAUDE.md, ledger/functions.tsv row for 0x<ADDRESS>, notes/compiler-quirks.md, two matched functions near it. FENCE: Edit only the body of <FUNCTION> in src/<FILE>.cpp. Do not rename or add variables, change the signature, or touch any other function. No inline assembly, goto or volatile tricks. CHECK: Run `check.cmd`. Done means <FUNCTION> shows 100% and `--diff base.json` shows no other function dropped. BUDGET: Stop after 10 tries with no gain. Stop at once if the stack size differs. IF BLOCKED: Stop. Save the best attempt, paste its diff, and name the kind of difference left. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the score line and the diff summary. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenThe ledger shows the batch matched and--diff base.jsonshows no drops on the merged branch.Proof this works: Dethrace, https://github.com/pablocpas/CMR2Decomp, https://momo5502.com/posts/2026-10-09-game-decompilation/
Work the hard tail
Some functions resist. Before more tries, you find out why. Some diffs are compiler noise that no C can fix. Those get marked and parked, not forced.
- Run
reccmp-stackcmp --target <TARGET> 0x<ADDRESS>to compare stack layouts. - Use the
wall-identifierskill to name the cause before you spend more tries. - Check rounding rules. Visual C++ 6 with
/QIfistrounds float to int differently from a plain cast. - Mark x87 order diffs as compiler noise, as Dethrace's rule sheet does. Do not force them.
- Record each trick that worked in
notes/compiler-quirks.md.
Prompt for ClaudeGOAL: Find why <FUNCTION> at 0x<ADDRESS> stops at <SCORE>% and try the fix. READ FIRST: notes/compiler-quirks.md, the saved attempts in scratch/<FUNCTION>/, the output of `reccmp-stackcmp --target <TARGET> 0x<ADDRESS>`. FENCE: Edit only <FUNCTION> in src/<FILE>.cpp and notes/compiler-quirks.md. No inline assembly, pragmas or changes to the check. CHECK: Run `check.cmd`. Done means 100%, or a written cause backed by the exact differing instructions. BUDGET: Stop after 15 tries, or after 3 tries with no new idea. IF BLOCKED: Stop. Say whether it is compiler noise, a wrong type, or a wrong function edge, with proof. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the diff lines that remain. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenpython tools/progress.pyshows each hard function as matched, or parked with a written, proven cause.Proof this works: Dethrace, OpenCMR2
- Run
Harden the whole-binary check
One function's score is evidence. The whole binary is the verdict. You check data, vtables and the full file, and you run this on every change.
- Run
reccmp-datacmp --target <TARGET>andreccmp-vtable --target <TARGET>. - Generate a full report with
reccmp-reccmp --target <TARGET> --html report.html. - Run the full report in CI on every pull request. Dethrace posts it as a comment and warns on drops.
- Hash the check script and store the hash where Claude cannot edit it. Heumann's team kept it in a CI secret.
- Add differential tests that run original and rebuilt code side by side, as CMR2Decomp does.
Prompt for ClaudeGOAL: Make CI run the full reccmp report and fail on any drop. READ FIRST: CLAUDE.md, check.cmd, .github/workflows/. FENCE: Edit only .github/workflows/ and tools/ci/. Never change base.json, expected hashes or the scoring rules. CHECK: Run the workflow on a test branch. Done means it passes on main, and fails on a branch where you lowered one function on purpose. BUDGET: Stop after 3 failed CI runs on the same error. IF BLOCKED: Stop. Paste the CI log lines and say what you need. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Links to the passing and failing runs. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenCI passes on main, fails on a planted drop, anddatacmpandvtableshow no errors.Proof this works: Dethrace, https://github.com/isledecomp/isle, https://github.com/pablocpas/CMR2Decomp, https://momo5502.com/posts/2026-10-09-game-decompilation/
- Run
Port it behind a platform layer
You keep the matched code close to its source. Only functions that call Windows or DirectX get rewritten against a small interface. Then you build it for 64-bit and Linux. Physics and frames must still match the original.
- Keep the port in a separate repo or branch, as DevilutionX and OpenCMR2 do.
- Write
src/port/headers for graphics, audio, input, files and network. Mark every change with aPORT:comment. - In its own task, write
tests/check_platform_boundary.py. It fails if game code includeswindows.h, like the Resident Evil decomp's script. - Audit raw memory access for 32-bit pointer assumptions before the 64-bit build.
- In WSL, use Ubuntu 26.04 LTS:
wsl --install -d Ubuntu-26.04. Ubuntu 24.04 has nolibsdl3-devpackage. - In that Ubuntu, run
sudo apt install cmake libsdl3-dev, then build the Linux target withcmake. - Replay recorded inputs in the original and in the port. Compare state each tick.
Prompt for ClaudeGOAL: Move <SUBSYSTEM> calls in <GAME> behind src/port/<SUBSYSTEM>.h and build on <TARGET_OS>. READ FIRST: SCOPE.md, docs/ARCHITECTURE.md, ledger/platform-calls.tsv. FENCE: Edit only src/port/, src/platform/ and the functions listed for <SUBSYSTEM>. Mark each change in game code with `// PORT:`. Do not fix original game bugs. CHECK: Run `check.cmd` and `python tests/check_platform_boundary.py`. Done means both pass and the parity replay <REPLAY> matches the original bit for bit. BUDGET: Stop after 3 failed tries on the same call. IF BLOCKED: Stop. Name the call and the first tick that differs. 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 parity result. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenThe port builds on the new system, the boundary check passes, and the parity replay matches.Proof this works: OpenCMR2, DevilutionX, Resident Evil PC Decomp, https://github.com/isledecomp/isle, https://packages.ubuntu.com/search?keywords=libsdl3-dev&searchon=names&suite=all§ion=all
Tools you need
| Tool | What it does | How to get it | How we know |
|---|---|---|---|
| Python Required both | Runs pcrecomp, reccmp and your check scripts. reccmp needs Python 3.11 or newer.Path A Path B | Get the Python install manager from python.org/downloads. Then run `py install 3.13`. | Python docs 'Using Python on Windows' (read 2026-11-13). Version floor from reccmp 0.1.9 on PyPI (needs 3.11 or newer). The pcrecomp README needs 3.10 or newer. |
| Git Required both | Clones the tools and keeps your history. Parallel workers each get a git worktree. Path A Path B | `winget install --id Git.Git -e --source winget` | git-scm.com Windows install page (read 2026-11-13). |
| uv Helpful both | A Python tool runner. GhidraMCP starts its server with uvx.Path A Path B | `winget install --id=astral-sh.uv -e` | uv install docs (read 2026-11-13). GhidraMCP README asks for uv. |
| WSL with Ubuntu 26.04 LTS Helpful Windows | A Linux system inside Windows. You need it for Remill and for the Linux build of a port.Path A Path B | In PowerShell as admin, run `wsl --install -d Ubuntu-26.04`, then restart. | Microsoft WSL install docs (read 2026-11-13). wsl --list --online showed Ubuntu-26.04 here on 2026-11-13. packages.ubuntu.com lists libsdl3-dev for 26.04 LTS and later only. |
| Ghidra Required Windows | A free disassembler and decompiler. It lists functions, shows C-like code and runs scripts with no window. Path A Path B | Install JDK 25 64-bit. Download the `ghidra_<version>_PUBLIC_<date>.zip` release, extract it, and run `ghidraRun.bat`. If you will use `GhidraMCP`, pick 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: Resident Evil PC Decomp, Black Ops II Recompiled, nfs-most-wanted-mac, SpaceCadetPinball. |
| GhidraMCP Helpful Windows | An MCP server that lets Claude ask Ghidra to list, decompile and rename functions. Path A Path B | Install Ghidra 12.1.4 and `uv`. In Ghidra, use File, Install Extensions, click `+`, and pick `ghidra_12.1.4_PUBLIC_<date>_GhidraMCP.zip` from the release. Restart Ghidra and enable `GhidraMCPPlugin` under File, Configure, Developer. Then run `claude mcp add ghidra -- uvx --from git+https://github.com/LaurieWired/GhidraMCP ghidra-mcp --ghidra-server http://127.0.0.1:8080/`. | GhidraMCP README and release 2.0, 2026-10-10 (read 2026-11-13). The README names Ghidra 12.1.4 for the plugin. Used by: Resident Evil PC Decomp (a Ghidra MCP server, project not named). |
| pcrecomp Required both | A toolbox for old PC programs. It reads PE files, finds functions, lifts x86 to C, tests the lift, and gives runtimes for Windows and Linux. Path A | `git clone https://github.com/sp00nznet/pcrecomp` then `pip install capstone pefile lief unicorn cryptography`. Needs Python 3.10+, CMake 3.20+ and Visual Studio 2022. | pcrecomp README (read 2026-11-13): MIT, created 2026-02-27, lists 64 game projects. The pip line is its README's own. Its DRM tools are not used in this guide. |
| Capstone Required both | A disassembly library. The lifters use it to decode x86 instructions. Path A Path B | `pip install capstone` | Repo page read 2026-11-13; install line from the pcrecomp README. Used by: Black Ops II Recompiled, nfs-most-wanted-mac, Resident Evil PC Decomp. |
| Unicorn Required both | A CPU emulator. It runs the original bytes so a test can compare them with the lifted C. Path A | `pip install unicorn` | Repo page read 2026-11-13 (GPL-2.0); install line from the pcrecomp README. Used by: nfs-most-wanted-mac, Black Ops II Recompiled. |
| Remill Helpful WSL/Linux | Lifts x86 machine code to LLVM bitcode, so clang can compile it for another chip.Path A | In WSL: `git clone https://github.com/lifting-bits/remill` and `cd remill`. Then run `cmake -G Ninja -S dependencies -B dependencies/build` and `cmake --build dependencies/build`. Then run `cmake -G Ninja -B build -DCMAKE_PREFIX_PATH:PATH=$(pwd)/dependencies/install -DCMAKE_BUILD_TYPE=Release` and `cmake --build build`. | Remill README (read 2026-11-13): supported on Linux, works on macOS, Windows is experimental. Needs CMake 3.21+, Ninja, LLVM and Clang 15+. Latest release v6.0.1. Used by: Black Ops II Recompiled (v6.0.1 with five patches). |
| reccmp Required both | Compares each rebuilt function, global and vtable with the original .exe and gives a match score.Path B | Make a Python 3.11 or newer virtual environment, then run `pip install reccmp`. | reccmp README (read 2026-11-13): supports 32-bit x86 C++ from old MSVC such as 4.20; newer MSVC in progress; run its tools where reccmp-build.yml is. PyPI: version 0.1.9 needs Python 3.11 or newer. Used by: Dethrace, CMR2Decomp, LEGO Island. |
| The game's original Visual C++ Required Windows | The exact old compiler that built the game. Matching is not possible without it. Path B | Use a copy you have the right to use. Put it in a path with no spaces and run its `BIN\VCVARS32.BAT x86` before building. | LEGO Island README build section (read 2026-11-13) uses Visual C++ 4.2 and warns it fails on paths with spaces. CMR2Decomp README uses Visual C++ 6.0 SP3. Dethrace runs MSVC 4.20 under Wine in Docker. |
| Visual Studio 2022 Required Windows | The modern Microsoft compiler and IDE. You use it for the runtime, the port and the tests. Path A Path B | Install the `Desktop development with C++` workload with `C++ CMake tools for Windows` and the `Windows SDK`. | Workload names from the DevilutionX card; required by the pcrecomp README. Used by: Resident Evil PC Decomp, Heretic2R, SpaceCadetPinball. |
| CMake Required both | Writes the build files for your compiler, so one setup builds on Windows and Linux. Path A Path B | Comes with the Visual Studio C++ workload. In WSL run `sudo apt install cmake`. | LEGO Island README says Visual Studio's C++ workload often includes it. Used by: nearly every card, including Dethrace, OpenCMR2 and DevilutionX. |
| SDL3 Helpful both | A library for windows, input, sound and GPU drawing on many systems. Ports use it to replace DirectX. Path A Path B | On Windows, download `SDL3-devel-<VERSION>-VC.zip` from the SDL releases page, or add the `sdl3` port with `vcpkg`. In WSL Ubuntu 26.04, run `sudo apt install libsdl3-dev`. Ubuntu 24.04 has no such package. | SDL release-3.4.20 assets and vcpkg ports/sdl3 (3.4.20) read 2026-11-13. packages.ubuntu.com lists libsdl3-dev for 26.04 LTS and later only. Used by: OpenCMR2 (SDL 3.4 and the SDL GPU API), CorsixTH, Heretic2R. |
| vcpkg Helpful Windows | A package manager for C and C++ libraries on Windows. Path A Path B | `git clone https://github.com/microsoft/vcpkg`, then `cd vcpkg; .\bootstrap-vcpkg.bat`, then set `VCPKG_ROOT`. | vcpkg README and Microsoft's vcpkg get-started page (read 2026-11-13). It has an sdl3 port. Used by: Sonic Mania Decompilation, Warzone 2100, DevilutionX, CorsixTH. |
| objdiff Helpful both | A desktop diff tool for decomp projects. It shows one function's assembly side by side with yours. Path B | Download `objdiff-windows-x86_64.exe` from the releases page. | objdiff README (read 2026-11-13) lists x86 and x86_64 (PC). Release v3.8.3 has the Windows exe. No reviewed PC project used it; they used reccmp. |
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.
pcrecomp
Teaches Claude the pcrecomp tools and tells it to check every flag against the tool's code. Use with care: it also covers SafeDisc tools, which may be illegal where you live.
npx skills add dohmboy64bit/pcrecomp-skill --skill pcrecomp -a claude-code
re-binary-recon
Small Python scripts that read a Windows .exe. They find the compiler, list C++ classes, and link debug text to code. That is your scope step.
npx skills add madpai/game-decomp-compendium --skill re-binary-recon -a claude-code
x86-cpp-reversing
A six-step method to rebuild the C++ classes of a 32-bit game. Each finding must point to a real instruction. It refuses 64-bit files.
npx skills add gavmor/x86-cpp-reversing-skill --skill x86-cpp-reversing -a claude-code
decompile-to-matching-c-cpp
Rules for writing C that builds to the same bytes, with an x86 section. It bans fake matches such as inline assembly.
npx skills add xsyetopz/skills --skill decompile-to-matching-c-cpp -a claude-code
wall-identifier
Names why a function will not match before more tries are spent. Each cause gets its own next step.
npx skills add lemiur/game-decompilation-skill-for-claude --skill wall-identifier -a claude-code
ghidra-headless
Runs Ghidra with no window and saves functions, code and strings to files. Use it if the MCP server is unstable. On Windows it needs Git Bash and GHIDRA_HOME.
npx skills add trailofbits/skills-curated --skill ghidra-headless -a claude-code
verification-before-completion
Claude may not say a job is done without fresh proof from the check. That stops the false DONE reports seen in PC projects.
npx skills add obra/superpowers --skill verification-before-completion -a claude-code
matcher
A method for matching one function. Claude gathers proof first and tries one idea at a time. Its examples use Visual C++ on x86. Install the other lemiur skills with it, because they call each other.
npx skills add lemiur/game-decompilation-skill-for-claude --skill matcher -a claude-code
systematic-debugging
No fix until the cause is found. After three failed fixes, Claude must stop and rethink. That fits Path A's crash grind.
npx skills add obra/superpowers --skill systematic-debugging -a claude-code
GhidraMCP
Lets Claude list, decompile and rename functions in your Ghidra project. The Resident Evil decomp's AGENTS.md sends its agent through a Ghidra MCP server for this.
claude mcp add ghidra -- uvx --from git+https://github.com/LaurieWired/GhidraMCP ghidra-mcp --ghidra-server http://127.0.0.1:8080/
match-one-function-reccmp
This copies Dethrace's agent rule sheet into a skill. Every worker then matches the same way.
A project skill in `.claude/skills/match-one-function/SKILL.md`. It takes an address. It maps stack slots first, edits only that function body, runs `reccmp-reccmp --target <TARGET> --verbose <ADDRESS>` after each change, undoes any drop, and stops if the stack size differs. It ends with a DONE, PARTIAL or BLOCKED report.
fix-one-crash-recomp
Path A's grind is many small crash fixes. A skill keeps the evidence-first order the same in every session.
A project skill in `.claude/skills/fix-one-crash/SKILL.md`. It runs the golden run, reads the last log lines and the abort address, asks Ghidra for that function, writes the proven cause to `notes/findings.md`, and only then edits `src/host/`. It never edits `src/recomp/gen/`.
Claude setup for this system
For Path A, one unit is one crash, one missing Windows call, or one wrong frame. Each unit ends with the golden run and the replays passing. For Path B, one unit is one function at one address. Each unit ends with reccmp showing 100% and no drop against base.json. 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.
| Job | What it means on this system | Max 20x (now called Ultra) | Max 5x (now called Max) |
|---|---|---|---|
| Plan the project | Hash the exe, read the Rich header, check for copy protection, and search for released source, new engines and decomps. Write SCOPE.md. | Fable 5.2 effort highOne session. This choice shapes months of work. | Opus 5.5 effort highUse Fable 5.2 for this one session if you have weekly room. |
| Set up the project | Install pcrecomp or the old Visual C++ and reccmp. Write check.cmd, the golden run and CLAUDE.md. | Opus 5.5 effort medium | Sonnet 5.5 effort medium |
| Study the game file | Build the function ledger from Ghidra and disasm32.py. Fix function edges, find classes from RTTI, and mark CRT and library code. | Opus 5.5 effort high | Opus 5.5 effort mediumRaise to high for function edges and data layouts. A mistake there spreads. |
| Bulk units | Match small game functions one at a time with reccmp. In Path A, fill simple Windows calls that follow a known pattern. | Sonnet 5.5 effort mediumHaiku 5.5 for the plainest units. | Sonnet 5.5 effort mediumFewer workers at once. Haiku 5.5 for the plainest units. |
| Hard units | Functions stuck below 100%: stack layout, float rounding, x87 order. In Path A, lifter bugs that the differential test finds. | Fable 5.2 effort highGo to xhigh only after a failed try at high. | Opus 5.5 effort highSend only the last few that still fail to Fable 5.2. |
| Build the runtime | Write the layer for Windows and DirectX calls, then the SDL3 or Direct3D 11 backend for graphics, sound and input. | Opus 5.5 effort high | Opus 5.5 effort mediumRaise to high for timing and graphics bugs. |
| Find a bug | Find why the build crashes or draws wrong, from logs, the abort address and frame hashes. Prove the cause before any fix. | Opus 5.5 effort highAfter two failed tries with full evidence, move to Fable 5.2. | Opus 5.5 effort highOne bug at a time. |
| Check the work | A fresh session reruns check.cmd, reads the diff, and hunts for edited baselines, fake stubs and edits to generated code. | Opus 5.5 effort mediumAlways a new session, never the one that did the work. | Sonnet 5.5 effort highAlways a new session, never the one that did the work. |
| Keep the records | Update PROGRESS.md, the ledger counts, notes/findings.md and notes/compiler-quirks.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 four to six workers, each in its own git worktree. In Path B, give each worker its own source file. In Path A, give each worker one crash or one Windows call in a different file. Run one verify session after each batch.
Max 5x (now called Max)
Run one lead session and one or two workers. Spend the hard and debug jobs on the hours you watch. Start bulk matching batches at night, one function per worker.
Lines for this project's 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. - Run every `reccmp-` command from the `build` folder. Run `pcrecomp` scripts from `<PCRECOMP>`. - Never edit files in `src/recomp/gen/`. Change the lifter input and regenerate. - The game folder, the original exe and `base.json` are read-only. - Match only the function named in the task. Do not rename variables or change its signature. - No inline assembly, naked functions, embedded bytes, goto or volatile tricks to force a match. - No stub may return success. A missing call aborts and prints its address. - If the Ghidra MCP server is down, stop and ask. Do not guess code from memory. - Comment every function with its original address: `// FUNCTION: <TARGET> 0x<ADDRESS>`. - Never state that a check passed unless you ran it and pasted the output. - In a worktree, use absolute paths to the game folder and the compiler. - Write side ideas and other bugs in notes/parking-lot.md. Do not act on them.
Keep the context small
- Give Claude one address and the ledger row, not a whole Ghidra export.
- Let a subagent read big decompiler output and return a short summary.
- Keep
CLAUDE.mdunder one page and point tonotes/compiler-quirks.mdby name. - Paste the last 20 log lines of a crash, not the whole log.
- Clear the chat after each unit. The ledger carries 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 between a recomp, a matching decomp, or using an existing project.
GOAL: Tell me if <GAME> (<EXE>, SHA-256 <HASH>) can be rebuilt, and by which technique. READ FIRST: notes/rich.txt, the output of `python <PCRECOMP>/tools/pe/analyze_sections.py <EXE>`, notes/prior-work.md. FENCE: Edit only SCOPE.md and notes/. Do not download game files, compilers or symbols. CHECK: Run `Select-String -Path SCOPE.md -Pattern '<HASH>'`. Done means it finds the hash, and SCOPE.md lists the compiler and build number, protection status, symbol sources, prior projects with URLs and AI policies, and a recommended technique with one reason against each other technique. BUDGET: Stop after 60 minutes. IF BLOCKED: If the exe is protected or the compiler is unknown, 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 recommended technique. It cites the Rich header line, the protection result and the prior projects.
Map the binary
After setup, to build the function ledger that every later task reads.
GOAL: Fill ledger/functions.tsv for <EXE> with address, size, kind and status for every function. READ FIRST: SCOPE.md, config/pe_analysis.json, functions.json. Use the Ghidra MCP server. FENCE: Edit only ledger/ and notes/. The exe is read-only. Do not write C. CHECK: Run `python tools/progress.py`. Done means the total equals Ghidra's function count and no row lacks a kind. BUDGET: Stop after 90 minutes. IF BLOCKED: If the counts do not agree, stop and list the addresses that differ. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the totals per kind. 3) Files changed. 4) Unsure rows. 5) New parking-lot items.
A good answer: DONE with totals per kind that add up to Ghidra's count, and a short list of unsure edges.
Unit loop: fix one crash (Path A)
For each crash or missing Windows call in the Path A grind.
GOAL: Make the recompiled <GAME> get past abort <ADDRESS> in run <RUN>. READ FIRST: PROGRESS.md item <ID>, the last 20 lines of logs/<RUN>.log, notes/findings.md. FENCE: Edit only src/host/ and hooks.txt. Never edit src/recomp/gen/. No stub may return a fake success. CHECK: Run `check.cmd`. Done means the golden run passes and the new run reaches <NEXT_POINT>. BUDGET: Stop after 3 failed fixes or 45 minutes with no new evidence. IF BLOCKED: Stop. Give the proven cause, or say the cause is not proven yet. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Cause with log lines, then check output. 3) Files changed. 4) What is left. 5) New parking-lot items.
A good answer: DONE, the cause in one sentence with the log lines that prove it, and the passing golden run.
Unit loop: match one function (Path B)
For each function in the Path B bulk loop.
GOAL: Make <FUNCTION> at 0x<ADDRESS> match 100%. READ FIRST: CLAUDE.md, the ledger row, notes/compiler-quirks.md, the Ghidra decompile of 0x<ADDRESS>. FENCE: Edit only the body of <FUNCTION> in src/<FILE>.cpp. No new variables, no signature change, no inline assembly. CHECK: Run `reccmp-reccmp --target <TARGET> --verbose 0x<ADDRESS>`, then `check.cmd`. Done means 100% and no drop against base.json. BUDGET: Stop after 10 tries with no gain. Stop at once if the stack size differs. IF BLOCKED: Stop. Keep the best attempt and paste its diff. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Score line and diff summary. 3) Files changed. 4) What is left. 5) New parking-lot items.
A good answer: DONE with the 100% line pasted, or PARTIAL with the best score and the exact lines that still differ.
Batch dispatch
In the lead session, to hand out the next set of units to workers.
GOAL: Start <N> workers on the next <N> open units from the ledger. READ FIRST: ledger/functions.tsv, PROGRESS.md, notes/parking-lot.md. FENCE: Edit only PROGRESS.md and the claim column of the ledger. Each worker gets its own git worktree and one unit in a different file. Do not do unit work yourself. CHECK: After all workers report, run `check.cmd` on the merged branch. Done means it passes and the ledger matches the reports. BUDGET: Stop after one batch. IF BLOCKED: If two units need the same file, run them one after the other and tell me. 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 and proof. 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 with DONE, PARTIAL or BLOCKED and pasted proof, then the merged check result.
Debug with evidence
When the build crashes, hangs or draws wrong and the cause is not known.
GOAL: Find the cause of <SYMPTOM> in <GAME>. Do not fix it yet. READ FIRST: logs/<RUN>.log, the frame hash table, notes/findings.md. FENCE: You may add temporary logging in src/host/ only. Remove it before you report. Do not change game behaviour. CHECK: Run `tools/golden.cmd` twice. Done means the bug appears both times, and a log line or trace shows the first wrong value and where it came from. BUDGET: Stop after 60 minutes or 5 runs with no new evidence. IF BLOCKED: Stop. List what you ruled out and the evidence for each. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) The cause, with the log lines. 3) Files changed. 4) The fix you would try. 5) New parking-lot items.
A good answer: A cause tied to one address and one value, proven by pasted log lines, with no code fix yet.
Verify and hunt for cheating
After every batch, in a brand new session that did none of the work.
GOAL: Check that the work in branch <BRANCH> is real. READ FIRST: `git diff main...<BRANCH>`, CLAUDE.md, SCOPE.md. FENCE: Read-only. Do not fix anything. Do not commit. CHECK: Run `check.cmd` yourself. Then look for edits to base.json, check.cmd, expected hashes or src/recomp/gen/; inline assembly; stubs that return success; disabled tests; and files outside the task fence. BUDGET: Stop after 45 minutes. IF BLOCKED: If you cannot run the check, say NOT ASSESSED, not PASS. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Your own check output. 3) Each finding with file and line. 4) A verdict: ACCEPT or REJECT. 5) New parking-lot items.
A good answer: The verifier's own check output, a list of findings with file and line, and a clear ACCEPT or REJECT.
Status report
At the end of a day or week, to see real progress.
GOAL: Report project status with numbers only. READ FIRST: ledger/functions.tsv, PROGRESS.md, the latest reccmp JSON or replay results. FENCE: Edit only notes/status-<DATE>.md. CHECK: Every number comes from a file or command you name. Run `python tools/progress.py` and paste it. BUDGET: Stop after 15 minutes. IF BLOCKED: If a number cannot be measured, write 'not measured'. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Matched or fixed count and percent, change since last report, open crashes, hard units. 3) Files changed. 4) Next three units. 5) New parking-lot items.
A good answer: A short table of counts and percents, each with its source, and no prose padding.
Session handoff
Before you stop for the day, or when a session's context is nearly full.
GOAL: Write down what the next session needs so it can continue from the files alone. READ FIRST: PROGRESS.md, notes/findings.md, `git status`. FENCE: Edit only PROGRESS.md and notes/handoff.md. Do not change code. CHECK: Run `check.cmd` and paste its last 20 lines into notes/handoff.md. Done means the note also lists the current unit, what was tried, dead ends, and the exact next command. BUDGET: Stop after 10 minutes. IF BLOCKED: If the last check output is missing, run `check.cmd` and paste it. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste notes/handoff.md. 3) Files changed. 4) What is left. 5) New parking-lot items.
A good answer: A handoff note that a fresh session can follow with no chat history, ending in one exact command.
Blocked or cannot deliver
When a task keeps failing and you need a plain answer.
GOAL: Tell me plainly whether <TASK> can be done, and if not, why. READ FIRST: The attempts in scratch/<TASK>/, notes/findings.md. FENCE: Read-only. Do not try again. CHECK: Run `check.cmd` once and paste the lines that fail. Done means your answer names the exact blocker, with that proof or a missing tool or file. BUDGET: Stop after 20 minutes. IF BLOCKED: Say 'I do not know yet' and list what would tell us. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) BLOCKED or PARTIAL. 2) The blocker and its proof. 3) Files changed (none). 4) Two or three options with cost and risk. 5) New parking-lot items.
A good answer: BLOCKED, one blocker with proof, and two or three options. No promise that it should work.
Scope change request
When Claude finds that the task needs a file or change outside its fence.
GOAL: Ask me before you leave the fence for <TASK>. READ FIRST: SCOPE.md, the task card for <TASK>. FENCE: Do not edit anything. Write only notes/scope-requests.md. CHECK: Run `git status --porcelain`. Done means it lists only notes/scope-requests.md, and the request names each file to change, why, the smallest change, and what could break. BUDGET: Stop after 10 minutes. IF BLOCKED: If you cannot name the smallest change, say so. OTHER PROBLEMS: Write them in notes/parking-lot.md. Do not fix them. REPORT: 1) PARTIAL. 2) The request text. 3) Files changed. 4) What waits on my answer. 5) New parking-lot items.
A good answer: A short request with file names and reasons, then a stop. No edits until you answer 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 detour | The rule to give Claude |
|---|---|
Claude edits the lifted C in src/recomp/gen/ to make a crash go away. | Generated code is never edited by hand. Change the lifter input or hooks.txt and regenerate. Block the folder with a hook. |
| Claude adds a stub that returns success, so a screen appears. The game then breaks far away. | No stub may return a fake value. A missing call aborts and prints its address. |
| Claude edits the check, the baseline or the expected hash to turn a red result green. | check.cmd, base.json and expected hashes are read-only. CI checks a stored hash of the check script. |
| Claude forces a match with inline assembly, naked functions or embedded bytes. | These are banned in CLAUDE.md. A clean non-match is better than a forced match. |
| Claude writes code from memory when the Ghidra server is down. | If the Ghidra MCP server does not answer, stop and ask. Do not guess code. |
| Claude says a fix works when only a person playing could know. | If you cannot test it, ask me to play it and report back. Never state that a check passed unless you ran it. |
| Claude looks for ways to strip copy protection from the exe. | Never work around copy protection. If the exe is protected, stop and tell me. |
| Claude puts Windows calls back into game code during a port. | Game code may not include windows.h. The boundary script runs in check.cmd. |
Problems other projects hit
Float results drift from the original. Direct3D quietly sets the x87 unit to 24-bit precision. Visual C++ 6 with /QIfist rounds float to int to nearest.
Fix: Copy the original's precision and rounding rules in the runtime. Test them with a parity replay, not by eye.
Seen in: nfs-most-wanted-mac, OpenCMR2, Black Ops II Recompiled
A wrong function start in the catalog drops a function. Hot code then runs in a slow fallback.
Fix: Check function edges against Ghidra and a PDB or MAP before you lift. Log every fallback address.
Seen in: Black Ops II Recompiled
A protected exe cannot be lifted as it is. The Need for Speed exe on the discs and in the 1.3 patch is protected.
Fix: Use a DRM-free edition you own, or pick another game. Do not try to remove the protection.
Seen in: nfs-most-wanted-mac
The old code clears or copies two globals as one block. The rebuilt build places them apart and memory breaks with no warning.
Fix: Write each global's original address down. Model such ranges as one struct.
Seen in: Resident Evil PC Decomp
Linker and optimizer settings change behaviour. Whole-program optimization broke a task switcher, and merged functions caused a gameplay bug.
Fix: Turn off /GL and /LTCG for such code. Use /OPT:NOICF when code compares function addresses.
Seen in: Resident Evil PC Decomp, Sonic Mania Decompilation
A 64-bit build breaks code that assumed 4-byte pointers. Running above 4 GB exposed more of these.
Fix: Audit every raw memory access. Keep a 32-bit build as the test reference.
Seen in: OpenCMR2, Dethrace
Some diffs cannot be fixed in C. x87 instruction order is the common case.
Fix: Mark them as compiler noise and stop. Fix the other diffs first.
Seen in: Dethrace
Reports claim success that is not real. One repo says 100% verified while its test list is unticked. Another retracted nearly 200 findings.
Fix: Accept only a check a machine can rerun, such as a hash, a score or a replay.
Seen in: Alone In The Dark: Re-Haunted, Black Ops II Recompiled
A store update changes the exe, and the build no longer accepts it.
Fix: Pin one exe by hash and say which version you support.
Seen in: Roadrash, nfs-most-wanted-mac
How long it takes
| Max 20x (now called Ultra) | Max 5x (now called Max) | One person, no AI | How sure | |
|---|---|---|---|---|
| Path A: running on PC | 6 to 16 weeks | 3.5 to 9 months | 1 to 3 years | low confidence |
| Path B: full decomp | 6 to 18 months | 14 months to 3.5 years | 3 to 8 years | low confidence |
Read this first
These numbers assume one medium commercial game and one person who gives 10 to 15 hours a week. Little dated evidence exists for AI work on PC. Most of it is from 2026, and several projects hide their early history. Two were team efforts or used more than one plan. Path B ends when every function has source that builds, as in CMR2Decomp. A full byte match can take longer. A small 1990s game can be much faster. A 2005 game with 50,000 functions can be much slower.
What makes it faster or slower
- Game size. A 1997 game has a few thousand functions. Need for Speed: Most Wanted (2005) has about 52,000.
- The compiler. Visual C++ 4.2 to 6 matches well with
reccmp. Newer compilers are not fully supported yet. - Symbols. A public PDB or a leaked symbol file saves weeks of naming.
- How many Windows and DirectX calls the game makes. Each one needs a working stand-in.
- Copy protection. A protected exe can stop the project before it starts.
- Whether a toolbox already has a runtime for that engine. Later games on
pcrecompcame up fast.
The facts behind these numbers
| Project | What happened | Link |
|---|---|---|
| Resident Evil PC Decomp | First commit 2026-05-28. Release 1.0.0 on 2026-09-08. Two contributors. Function-complete and playable. AGENTS.md drives a Ghidra MCP loop. | source |
| CMR2Decomp | First commit 2025-08-24. Heavily AI-assisted (Claude and Codex). All 3,364 functions have source. decomp.dev showed 56.34% byte exact on 2026-11-13. | source |
| OpenCMR2 | Port of CMR2Decomp. First commit 2026-10-09, first release 2026-10-13. Physics matched the original one day after the first commit. | source |
| Road Rash port | Static recomp. The README says 1.5 years of work, finished with LLM help. Repo created 2026-10-28, release 2026-10-30. One person. | source |
| Black Ops II Recompiled | Static recomp written with Claude Code. README says months of work by one person. Public repo 2026-11-03, release 2026-11-05. | source |
| Unnamed PC shooter (Heumann) | About 3 months. Started with 4 agents and ran 16 in the final weeks, on Max 20x plus a second subscription. 99% of functions present, 83% byte exact. | source |
| Crimsonland | Rewrite from a Ghidra decompile with an agent. About two weeks. | source |
| Red Alert 2 recomp (pcrecomp) | Repo created 2026-10-04, first release 2026-10-19, on a toolbox started in February 2026. | source |
| Sonic Mania Decompilation | No AI use stated. README says about 1.5 years. First commit 2020-02-13, release 2022-08-15, 14 contributors. | source |
| Dethrace | No AI use stated, but it has an agent rule sheet. First commit 2019-10-29, playable release 2022-09-21. Matching still in progress in 2026. | source |
| Heretic2R | No AI use stated. One person. First commit 2024-06-05, first release 2026-03-23. | source |
Projects reviewed (23)
We took the top project for each of the 12 most-starred PC games on RecompLauncher. We added three that their makers say used AI. We added eight more decomp and recomp projects. The catalog lists 263 PC projects for 250 games.
What each project teaches
OpenRA
Command & Conquer: Red Alert, Tiberian Dawn & Dune 2000
Started: 2007-06. First release: 2020-01. Code: C#.
AI: none stated (its AGENTS.md bans automated agents) Agent files: AGENTS.md.
Lesson: A new engine can bring a game back with no decomp. Read a repo's agent policy first; this one bans agents.
OpenRCT2
RollerCoaster Tycoon 2
Started: 2014-04. First release: 2014-12. Code: C++.
AI: none stated
Lesson: Recorded replays and file round-trip tests catch changes without a person playing.
Luanti
Luanti
Started: 2010-11. First release: 2021-02. Code: C++ and Lua.
AI: none stated (its AI policy limits AI code)
Lesson: Not a decomp. Its one-flag unit test run is a good model for a check command.
Cataclysm: Dark Days Ahead
Cataclysm: Dark Days Ahead
Started: 2010-10. First release: 2026-11. Code: C++.
AI: none stated (bans LLM content) Agent files: .github/copilot-instructions.md.
Lesson: Not a decomp. It bans all AI-made content, so check a project's rules before you send it work.
DevilutionX
Diablo
Started: 2018-06. First release: 2019-02. Code: C++.
AI: none stated
Lesson: Find every leftover hint first. The Rich header gave the compiler, and a PlayStation symbol file gave names.
OpenMW
The Elder Scrolls III: Morrowind
Started: 2008-06. First release: 2015-06. Code: C++.
AI: none stated
Lesson: Small command-line tools for each file format double as tests for the readers.
VCMI
Heroes of Might and Magic III
Started: 2007-05. First release: 2023-09. Code: C++.
AI: none stated (AI help allowed; agents may not open pull requests) Agent files: AGENTS.md, docs/AGENTS.md, lib/rmg/AGENTS.md, lib/rmg/modificators/AGENTS.md.
Lesson: A read-only review skill should mark what it did not check as NOT ASSESSED, never as a pass.
Super Tux Kart
SuperTuxKart
Started: 2007-05. First release: 2016-07. Code: C++.
AI: none stated
Lesson: Not a decomp. It shows how to keep large assets in a separate repo.
OpenSC2K
SimCity 2000
Started: 2025-06. First release: 2026-09. Code: Rust and GDScript.
AI: yes: README says it is developed with AI tools including LLMs Agent files: AGENTS.md.
Lesson: A golden set of SHA-256 hashes of outputs lets an agent change code without changing results.
SpaceCadetPinball
3D Pinball: Space Cadet
Started: 2020-10. First release: 2021-01. Code: C++.
AI: none stated
Lesson: A public PDB made a small game fast to decompile. A non-matching decomp cannot prove it kept every behaviour.
CorsixTH
Theme Hospital
Started: 2009-07. First release: 2020-06. Code: Lua and C++.
AI: none stated (AI help allowed with rules in AGENTS.md) Agent files: AGENTS.md.
Lesson: Its AGENTS.md says never claim a check passed that you did not run, and never weaken a test.
warzone2100
Warzone 2100
Started: 2005-01. First release: 2022-10. Code: C++.
AI: none stated
Lesson: The publisher released the source in 2004. Check for released source before any decomp.
Dethrace
Carmageddon
Started: 2019-10. First release: 2022-09. Code: C.
AI: none stated (has an agent rule sheet for matching) Agent files: reccmp/AGENTS.md.
Lesson: Its rule sheet is the model for Path B: one function, one edit at a time, undo any drop, and clear stop rules.
Sonic Mania Decompilation
Sonic Mania
Started: 2020-02. First release: 2022-08. Code: C.
AI: none stated
Lesson: The linker merged similar functions and broke gameplay until /OPT:NOICF was set.
Heretic2R
Heretic II
Started: 2024-06. First release: 2026-03. Code: C.
AI: none stated
Lesson: Start from any official source, then work in tiny commits, one function each.
Black Ops II Recompiled
Call of Duty: Black Ops II
Started: 2026-11. First release: 2026-11. Code: C++.
AI: yes: written with Claude Code (recompiler passes, runtime, tooling, docs); the author directed and tested
Lesson: Make the agent write its prediction before it reads a result, and trust the screen over the log.
Resident Evil PC Decomp
Resident Evil
Started: 2026-05. First release: 2026-09. Code: C++.
AI: not stated in README; a 35 KB AGENTS.md directs an agent through a Ghidra MCP server Agent files: AGENTS.md.
Lesson: Put each function's original address in a comment, and rename it in Ghidra so the next session sees the name.
Dune Dynasty
Dune II
Started: 2009-09. First release: 2023-07. Code: C.
AI: none stated
Lesson: Building on an existing reverse-engineered engine (OpenDUNE) saved redoing the hard part.
OpenCMR2
Colin McRae Rally 2.0
Started: 2026-10. First release: 2026-10. Code: C++.
AI: not stated for the port; upstream CMR2Decomp says it is heavily AI-assisted (Claude and Codex)
Lesson: Compare the port with the original by replaying the same inputs, field by field, with no tolerance.
nfs-most-wanted-mac
Need for Speed: Most Wanted
Started: 2026-10. First release: 2026-10. Code: C, Python and Objective-C.
AI: none stated
Lesson: Test the recompiler by running each function and the original bytes in Unicorn and comparing everything.
Alone In The Dark: Re-Haunted
Alone in the Dark
Started: 2026-03. First release: 2026-03. Code: C++.
AI: none stated (repo hints at AI tools but does not say)
Lesson: A report that says 100% verified is not proof. Only a check you can rerun counts.
NeoTS2
The Sims 2
Started: 2026-10. First release: 2026-10. Code: C++.
AI: yes: README says much of the code is written together with AI
Lesson: A tool that reads every game file and counts failures turns format work into a number Claude can raise.
Roadrash
Road Rash
Started: 2026-10. First release: 2026-10. Code: C (source not published).
AI: yes: developer says Claude helped with decompilation and recompilation
Lesson: Fourteen scripted race replays must match the original frame for frame before each release.
What we could not check
- No command in this guide was run here. Commands were read from each tool's README, docs or source on 2026-11-13.
- Few reviewed projects publish their agent setup. Dethrace and the Resident Evil decomp have rule sheets. OpenSC2K, CorsixTH and VCMI have
AGENTS.mdfiles, and CMR2Decomp has aCLAUDE.md. None publishes its prompts. - Which AI tool, if any, wrote the Resident Evil PC decomp is not stated. Only its AGENTS.md suggests it.
- pcrecomp's README does not say if AI was used. Its sister repo
xboxrecompsays it was built with Claude Code. - Road Rash and Black Ops II hide their early history, so their start dates are not known.
- The date LEGO Island reached 100% was not read.
tools/difftest_game.pyandtools/progress.pyare scripts you write. The Need for Speed port's game-level lift test is not in its public checkout.difftest.pyneedsgcc,clangorcc. Whether it works on Windows with only Visual Studio was not checked.py install 3.13follows the pattern in Python's docs. That exact version tag was not tried.- Whether
objdiffhandles old Visual C++ objects as well asreccmpwas not tested here. - Remill on native Windows is called experimental by its README. It was not tried here.
- The Rich header reference page (bytepointer.com) was down when the writer checked it.
- The time ranges come from few projects. Most are from 2026, and two were team efforts.
- GhidraMCP 2.0 names Ghidra 12.1.4. Whether it loads in Ghidra 12.2 was not checked.
Sources
- reccmp README
- pcrecomp README
- Ghidra README
- GhidraMCP README
- Remill README
- CMR2Decomp README
- CMR2Decomp progress on decomp.dev
- LEGO Island decompilation README
- Dethrace reccmp agent rules
- Resident Evil PC Decomp AGENTS.md
- Get-FileHash (PowerShell docs)
- PE format (Microsoft docs)
- 500+ Billion Tokens Later (Heumann)
- Resurrecting Crimsonland (banteg)
- Chromatron recompiled (Quesma)
- Black Ops II Recompiled README
- Need for Speed Most Wanted Mac ARCHITECTURE.md
- pcrecomp difftest.py source
- reccmp on PyPI
- libsdl3-dev in Ubuntu (packages.ubuntu.com)
- Install WSL (Microsoft docs)
- Using Python on Windows
- uv installation
- Git for Windows install
- SDL releases
- vcpkg sdl3 port
- objdiff README
- ReproBit (LEGO Island byte-for-byte builds)
- Select-String (PowerShell docs)