PlayStation Portable decomp guide
Many PSP games now run on PC. A full PSP decomp is still new ground.
What this system is like
The PSP is a busy system for recomp work right now. Two shared tools, PortableKit and PSPRecomp, turn a game's code into C++. A recomp is a tool that rewrites machine code as C or C++. More than twenty PSP games have recomp ports. Most of them came out in late 2026, and most used AI help.
The usual route to a PC build is short. You decrypt the game's main file. You run it under a slow stand-in for the CPU, called an interpreter, to see what is missing. Then you turn all the code into C++, build it, and fix one gap at a time.
A full decomp is much harder here. A decomp is readable C that builds back to the exact same bytes. PSP games used three compiler families, much C++ code, and often more than ten thousand functions. No PSP game is fully decompiled yet. One project matched about 41% of a game's code in four weeks with AI agents. That is the best sign so far.
Path A runs on Windows. Path B needs WSL, because the old compilers run there through wibo. Ghidra, PPSSPP and objdiff run on Windows for both paths.
The main file is locked
EBOOT.BIN on most discs is encrypted. You decrypt your own copy before any tool can read it. pspdecrypt or the PortableKit installer does this. A few games run from a plain BOOT.BIN instead.
Code hides in data files
Many PSP games load extra code while they run. These pieces are called overlays. In Monster Hunter Freedom Unite, 298 overlays held about 81% of the code. Each overlay needs its own recompile.
Calls go by number
A game calls system functions by a number called a NID. The runtime must know what each NID does. Your first gap list is simply the NIDs the game uses but the runtime lacks.
Two shared frameworks exist
PortableKit and PSPRecomp already turn PSP code into C++. A new port starts as a game profile on top. Both are early, and every new game finds gaps in them. Still, the reviewed ports took weeks, not months.
A vector unit and a fixed GPU
The VFPU does fast vector math with its own instructions. Ghidra and some recompilers handle it only in part. The GE has odd rules, like alpha used as stencil and 24-bit floats.
Three compiler families
Games were built with CodeWarrior, SNC or Sony's GCC. You must find the right one by test before matching. CodeWarrior and SNC are Windows programs that run in WSL through wibo. The psp-gcc kits are 32-bit Linux programs.
Two paths
Get it running on PC
You build a game profile on PortableKit. Its installer checks and decrypts your own disc. You run the game under its interpreter to list what is missing. Then psp_recomp writes the C++, and you fix one gap at a time. PSPRecomp also works, but it has no interpreter and no installer.
Full decomp for porting
You split each module with splat, find the original compiler by test, and match functions one by one. A match means the old compiler turns your C into the exact same bytes. The tools run in WSL. No PSP game is fully done yet, so this path is still being worked out.
Path A: Get it running on PC
You build a game profile on PortableKit. Its installer checks and decrypts your own disc. You run the game under its interpreter to list what is missing. Then psp_recomp writes the C++, and you fix one gap at a time. PSPRecomp also works, but it has no interpreter and no installer.
Method: static recompilation
Pick this first for any PSP game. Every working project reviewed here took this path. It gives a playable build in weeks.
Scope the game and survey the disc
You pick one game, one region and one version. You look for earlier work on it. Then you measure the disc so you know the risks before you write code.
- Note the disc ID, like
ULUS10160, fromPARAM.SFOorUMD_DATA.BIN. - Search RecompLauncher, the
PortableKitports table and GitHub for your game. Look for a recomp, a decomp or a sister game on the same engine. - Check if
PSP_GAME/SYSDIR/EBOOT.BINis encrypted or if a plainBOOT.BINexists. - List extra
.prxfiles and big data files that may hold overlays. - Play the game in
PPSSPPand note the frame rate and any odd features. - Have Claude write
SCOPE.md. You approve it.
Prompt for ClaudeGOAL: Write a draft SCOPE.md for a PC recomp of <GAME> (<DISC_ID>, version <VERSION>). READ FIRST: `notes/disc-listing.txt` (my file list of the disc), the `PortableKit` README, `docs/BRINGING_UP_A_GAME.md` in PortableKit. FENCE: Edit only `SCOPE.md` and `notes/survey.md`. Everything else is read-only. Do not write code, scripts or configs. CHECK: `SCOPE.md` has these headings: Goal, Game and hash, Technique, Prior work, Disc survey, Milestone 1 and its check, Out of scope, Never edit. Every claim in Prior work has a URL. BUDGET: Stop after 45 minutes of research. IF BLOCKED: Stop. Do not guess facts about the disc. List what you need me to look up. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not act on them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) The SCOPE.md headings filled. 3) Files changed. 4) Open questions for me. 5) New parking-lot items.
Done whenSCOPE.mdnames the disc ID, the executable hash, the framework and the first milestone, and you approved it.Proof this works: The 3rd Birthday Recomp (step 0 survey and bake-off), God of War PSP (feasibility study before code), MHForever (measured candidate recompilers first)
- Note the disc ID, like
Set up the framework and the repo
You build the framework alone first. It needs no game and takes minutes. Then you make your port repo with the framework as a git submodule. You add the one boot check and the guard against game files.
- Install Visual Studio 2022 with the C++ workload, CMake 3.20 or newer, Ninja and Python 3. A port also needs SDL3, the Vulkan SDK (it has
glslangValidator) and FFmpeg. - Run
git clone --recursive https://github.com/TeamGDB/PortableKit.gitand build it withcmake -S . -B out -G Ninja -DCMAKE_BUILD_TYPE=Release,cmake --build out -j2andctest --test-dir out --output-on-failure. On Windows, run these in a Visual Studio developer prompt. - Or use the Visual Studio generator. Then add
--config Releaseto the build and-C Releasetoctest. - The bundled FFmpeg needs
makeand a C compiler. Without them, pass-DPORTABLEKIT_FFMPEG=system, orOFFto drop music and movies. - In your own repo, add it with
git submodule add https://github.com/TeamGDB/PortableKit.git portablekit. - Write the profile in
host/<game>_profile.cpp. It holds only constants: disc ID, both hashes, decryption tag and key, load address and save folders. - Read each value off your own disc and its ELF headers, as
PROFILE_GUIDE.mdsays. Do not recall them. - Make
.gitignoredeny everything first, then allow your own folders. Add a pre-commit check that refuses game files and generated code. - Have Claude write
tools/boot_check.pywith--seconds N,--no-interpreterand--replay <FILE>. It runs the game with no window and no sound, kills it at the limit, and prints PASS or FAIL. - Write
CLAUDE.md,PROGRESS.mdandnotes/parking-lot.md.
Prompt for ClaudeGOAL: Make the port repo build with PortableKit as a submodule and one check command that runs. READ FIRST: `SCOPE.md`, `portablekit/README.md`, `portablekit/docs/PROFILE_GUIDE.md`, `portablekit/docs/BUILDING.md`. FENCE: Edit only `CMakeLists.txt`, `host/`, `config/`, `tools/boot_check.py`, `.gitignore`, `.githooks/`, `CLAUDE.md`, `PROGRESS.md`. `portablekit/` is read-only. Do not add features I did not ask for. CHECK: Run `cmake --build out -j2` then `ctest --test-dir out --output-on-failure`. Done means both exit 0, and `python tools/boot_check.py --help` lists `--seconds`, `--no-interpreter` and `--replay`. BUDGET: Stop after 3 failed builds with the same error, or 60 minutes. IF BLOCKED: Stop. Do not edit the submodule to make it build. Tell me the error, 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) Paste the last 20 lines of the build and test output. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whencmake --buildandctestexit 0 on a clean clone, and a test commit with a fake.isofile is refused.Proof this works: https://github.com/TeamGDB/PortableKit, Portable Ops Native (PortableKit as a submodule), MHForever (content guard as a pre-commit hook), Renegade Squadron PC (default-deny .gitignore)
- Install Visual Studio 2022 with the C++ workload, CMake 3.20 or newer, Ninja and Python 3. A port also needs SDL3, the Vulkan SDK (it has
Prepare and pin the executable
You turn your disc into a decrypted executable. You pin its hash so every later step uses the same bytes. A wrong key or version shows up here in seconds.
- With PortableKit, run
<Game>Native --install /path/to/your.iso --in-place. It checks the disc ID and theEBOOT.BINSHA-256, then decrypts. - Without it, decrypt
EBOOT.BINwithpspdecryptfrom its release zip. - If the disc has a plain ELF
BOOT.BIN, use that and skip decryption. - Put both hashes in the profile:
encrypted_executable_sha256forEBOOT.BINandexecutable_sha256for the decrypted file. - Keep the
.isoand the decrypted file outside the repo.
Prompt for ClaudeGOAL: Make the install step produce a decrypted executable whose SHA-256 matches the value pinned in the profile. READ FIRST: `SCOPE.md`, `host/<GAME>_profile.cpp`, `portablekit/docs/PROFILE_GUIDE.md`, `portablekit/docs/BRINGING_UP_A_GAME.md` step 2. FENCE: Edit only the identity, hash and decryption constants in `host/<GAME>_profile.cpp`. Never copy game files into the repo. Never print keys into logs or notes. CHECK: Run `<Game>Native --install <ISO_PATH> --in-place`. Done means it exits 0 with no disc ID, hash or key error. The installer checks the decrypted file against `executable_sha256` itself. BUDGET: Stop after 3 failed tries. IF BLOCKED: Stop. Do not search the web for keys or download any game file. Tell me which check failed and its exact message. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the install output. 3) Files changed. 4) What is left.
Done when<Game>Native --installexits 0. It has checked the disc ID, theEBOOT.BINhash and the decrypted file against the pinned hash.Proof this works: Yakumo (installer checks PARAM.SFO and the EBOOT.BIN SHA-256), Vice City Stories Recomp (refuses an ELF whose hash does not match), Sims 2 PSP Recomp (uses the plain BOOT.BIN)
- With PortableKit, run
Map the executable
You load the decrypted file into Ghidra to see functions, imports and overlays. You save a ledger of what the game needs. This is where you learn the size of the job.
- Install Ghidra 12.1.4 and the
ghidra-allegrexzip built for 12.1.4 withFile -> Install Extensions. Extensions must match the Ghidra version. - Import the decrypted file. Set
Image Baseto08804000. Run auto analysis. - In
PPSSPP, save a.symfile from theDebugmenu. Import it with thePpssppImportSymFilescript. Start Ghidra withsupport\pyghidraRun.baton Windows for this. - Run
portablekit/tools/ghidra/ExportPSPFunctions.javafrom the Script Manager. It writes a CSV of name, address and size. Add a status column. - List the imports by library. This is your list of system calls to support.
- Mark SDK and middleware functions so nobody works on them by hand.
- Find the function that loads overlays, if the game has them.
Prompt for ClaudeGOAL: Produce `ledger/functions.csv` and `ledger/imports.md` for <GAME>. READ FIRST: `SCOPE.md`, `notes/survey.md`, the Ghidra export at `<EXPORT_PATH>`. FENCE: Edit only files in `ledger/`. The Ghidra project and the game files are read-only. Do not rename anything in Ghidra unless I ask. CHECK: `ledger/functions.csv` has columns address, size, name, kind (game, sdk, middleware), status. Its row count equals the row count of the export at `<EXPORT_PATH>`. `ledger/imports.md` lists every import by library with its NID. BUDGET: Stop after 60 minutes. IF BLOCKED: Stop. Do not invent names or NIDs from memory. Tell me what is missing. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Counts: functions, SDK functions, imports, overlays found. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenledger/functions.csvhas as many rows as theExportPSPFunctionsCSV, and every import is listed with its library.Proof this works: God of War PSP (Ghidra + ghidra-allegrex exports to JSON), https://github.com/kotcrab/ghidra-allegrex, The 3rd Birthday Recomp (import list as the HLE checklist)
- Install Ghidra 12.1.4 and the
First light under the interpreter
You run the game before any code is recompiled. The interpreter runs it slowly but truly. Each run names the next missing system call. Each fix costs seconds, not hours.
- Run
<PREFIX>_NO_RENDER=1 <PREFIX>_NO_AUDIO=1 timeout 90 <Game>Native. Yourtools/boot_check.pydoes the same on Windows. - Add
<PREFIX>_LIST_STUBS=1to print every import nothing implements. - Read the last
[hle-stub]line before aRuntime stoppedmessage. That call is the next job. - Set
<PREFIX>_STRICT_HLE=1so the game stops at a missing call instead of going on with a fake answer. - Implement that one call through the profile's
register_extra_hlehook or an HLE extension. Run again. - A run with a window may not stop on a plain
timeout. Usetimeout -s KILL, and never leave the game running.
Prompt for ClaudeGOAL: Implement the system call `<LIBRARY>::<FUNCTION>` so the interpreter boot gets past it. READ FIRST: `CLAUDE.md`, the last boot log at `<LOG_PATH>`, `ledger/imports.md`, `PPSSPP` source for this call (read only, never copy). FENCE: Edit only the HLE files in `host/` that `register_extra_hle` reaches, or the HLE extension file I name. `portablekit/` is read-only. Do not stub other calls. CHECK: Run `python tools/boot_check.py --seconds 90`. Done means the log no longer stops at this call, and the earlier boot milestones in `PROGRESS.md` still print. BUDGET: Stop after 3 failed tries or 45 minutes. IF BLOCKED: Stop. Do not return a fake success code to move on. Tell me what the game expects and what you could not confirm. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the log lines before and after. 3) Files changed. 4) The next call the game stops on. 5) New parking-lot items.
Done whenpython tools/boot_check.py --seconds 90runs past the call, and the log names the next stop or shows the title screen.Proof this works: https://github.com/TeamGDB/PortableKit/blob/main/docs/BRINGING_UP_A_GAME.md, Tag Force Recomp (every missing call fails loudly), Ape Escape Mind Over Monkey (bind a call only when its contract is known)
- Run
Recompile and boot with no interpreter
Now you turn all the code into C++ and build it. The build is long, so keep jobs low. Then you prove the boot uses only recompiled code.
- Run
psp_recomp <EBOOT.ELF> --auto generated. It takes a few minutes. - Count the
unsupported(...)sites in the output before you compile. Thousands in one category means a real recompiler gap. - Build with
cmake --build out -j2. Generated files are huge, so the build compiles only one per 4 GiB of memory. - Use
clang-clfor the generated code if you can. In one port, frames took 7 ms with it and 18 to 22 ms with MSVC. - Run with
PSPRECOMP_NO_INTERPRETER=1. The runtime stops at the first address with no recompiled code and names it. - With the interpreter on,
PSPRECOMP_INTERPRETER_VERBOSE=1lists every address it had to run. Recompile the code those belong to. - If the game has overlays, extract each one and recompile it into its own library with
portablekit/tools/add_overlay.py. Pick the right one at run time by a hash of its code.
Prompt for ClaudeGOAL: Generate and build the recompiled game, and boot it to <MILESTONE> with the interpreter off. READ FIRST: `CLAUDE.md`, `PROGRESS.md`, `portablekit/docs/BRINGING_UP_A_GAME.md` step 4. FENCE: Edit only `host/`, `config/` and build settings in `CMakeLists.txt`. Never edit files in `generated/`. If generated code is wrong, report it; the fix goes in the generator or the profile. CHECK: Run `python tools/boot_check.py --seconds 120 --no-interpreter`. It sets `PSPRECOMP_NO_INTERPRETER=1`. Done means PASS, the log shows <MILESTONE>, and no `Runtime stopped` line names a missing address. BUDGET: Use `-j2` at most. Stop after 2 full builds that fail the same way. IF BLOCKED: Stop. Do not turn the interpreter back on to pass. List the first missing address and what code it belongs to. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the unsupported-site counts and the boot log tail. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenpython tools/boot_check.py --no-interpreterprints PASS at the milestone, and no missing address stops the run.Proof this works: Dissidia012-PC (no interpreter fallbacks proved this way; VERBOSE listed a missed disc PRX), Portable Ops Native (stage sweep with the interpreter off), Vice City Stories Recomp (clang-cl about 2.5x faster frames than MSVC), Yakumo (355 overlays, each its own library)
- Run
Grind: one gap at a time
Each task is one crash, one missing call or one drawing bug. Claude finds the cause with traces first.
PPSSPPis your reference for how the real system acts.- Turn on one trace at a time, like
<PREFIX>_TRACE_GE_LIST,<PREFIX>_TRACE_IOor<PREFIX>_TRACE_SYNC. - Compare with
PPSSPPat the same load base. Use its debugger to watch memory writes. - Write each fix with its cause and the trace that proved it in
PROGRESS.md. - Record dead ends too, so no session tries them again.
- Keep a list of bugs as GitHub issues or a ledger table. Hand out one per worker.
Prompt for ClaudeGOAL: Fix <BUG> (seen at <WHERE>) with a proven cause. READ FIRST: `CLAUDE.md`, `PROGRESS.md` dead ends, the log at `<LOG_PATH>`, the capture at `<CAPTURE_PATH>`. FENCE: Edit only `host/` and `config/`. `generated/` and `portablekit/` are read-only. No game-specific hacks that skip the bug. CHECK: Run `python tools/boot_check.py --replay <REPLAY_FILE>`. Done means PASS, the bug is gone in the capture at frame <N>, and all older replays still pass. BUDGET: Find the cause before any fix. Stop after 2 fixes that do not work, or 90 minutes. IF BLOCKED: Stop. Tell me the evidence you have, your best theory and what trace would prove it. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) The cause, with the trace lines that prove it. 3) Files changed. 4) Replay results. 5) New parking-lot items.
Done whenThe replay passes, the capture shows the fix, and every older replay still passes.Proof this works: Yakumo (AGENTS.md: trace the hardware, measure before changing), The 3rd Birthday Recomp (PPSSPP as oracle, dated fix log), Tag Force Recomp (TF_HOOK_TRACE found a wrong address in minutes)
- Turn on one trace at a time, like
Harden: replays, frames and packaging
You lock in old fixes with tests that run without you. Then you add settings and package a release that holds no game code. The player builds the game from their own disc.
- Record input sessions and make headless runs repeat exactly. Pin the clock and the gamepad.
- Keep a slow software renderer as the reference. Compare the GPU output against it frame by frame.
- Write a script that visits every level or stage and reports crashes and missing calls.
- Run tests that need no game data in CI.
- Package only the runtime and launcher. The launcher builds the game on the player's PC.
- State in the release notes what you tested and what you did not.
Prompt for ClaudeGOAL: Add `tools/regress.py`, a regression set a fresh checkout can run: replays at fixed frames, a stage sweep and a `--no-interpreter` switch. READ FIRST: `CLAUDE.md`, `PROGRESS.md`, `tools/boot_check.py`. FENCE: Edit only `tools/` and `tests/`. Do not change game behaviour to make a test pass. Do not commit replays that hold game data. CHECK: On a clean clone, run `python tools/regress.py`. Done means it prints PASS for every replay and every stage, then a summary line with the counts. BUDGET: Stop after 90 minutes or 3 failed designs. IF BLOCKED: Stop. Tell me which run is not repeatable and what changes between runs. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the summary line. 3) Files changed. 4) What the set does not cover. 5) New parking-lot items.
Done whenpython tools/regress.pyprints PASS for all replays and stages on a clean clone.Proof this works: God of War PSP (34/34 identical frames, WAV hash, level tour), Renegade Squadron PC (GPU compared to the software renderer), LCS Recomp (stress test with numeric pass and fail), Sims 2 PSP Recomp (900-frame startup check, per-release status log)
Path B: Full decomp for porting
You split each module with splat, find the original compiler by test, and match functions one by one. A match means the old compiler turns your C into the exact same bytes. The tools run in WSL. No PSP game is fully done yet, so this path is still being worked out.
Method: matching decompilation
Pick this after Path A works, or when you want to change the game deeply. Expect many months. If you only want to play, stay on Path A.
Scope and find the compiler
You check what decomp work exists for your game. Then you find which compiler and flags built it. You test candidates on a few small functions and count exact matches.
- Search GitHub and decomp.dev for your game and its engine. Check
sotn-decomp,mhp2g-decompandHST-Decompfor setups you can copy. - Pick three to six small functions from the smallest module.
- Compile each with every candidate:
mwccpspbuilds,pspsnc,psp-gcc1.3.1 and 1.7.1, at common flags. - Count exact matches for each compiler and flag set.
- Write the winner and its flags into
SCOPE.md.
Prompt for ClaudeGOAL: Find the compiler and flags that built <GAME>, by experiment. READ FIRST: `SCOPE.md`, the six target functions in `asm/<MODULE>/`, `notes/compilers.md`. FENCE: Edit only `notes/compilers.md` and files under `try/compiler-test/`. Everything else is read-only. CHECK: For each compiler and flag set, run `<MATCH_TOOL> try/compiler-test/<FUNC>.c`. Done means `notes/compilers.md` has a table of exact matches per compiler and flag set, with the command used. BUDGET: Stop after testing every candidate once, or 90 minutes. IF BLOCKED: Stop. Do not download compilers from unknown sites. Tell me which candidate you could not run. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) The match table. 3) Files changed. 4) Your pick and why. 5) New parking-lot items.
Done whenOne compiler and flag set matches every test function exactly, and the table is innotes/compilers.md.Proof this works: Dissidia012-PC (SNC matched 5 of 6 at -O2, 6 of 6 with -g), https://github.com/angelof-exe/ygo-tf-5-decomp (mwccpsp_3.0.1_219, flags -O4,s; builds 180 to 219 all match its simple functions), https://github.com/decompme/compilers (PSP compiler kits)
- Search GitHub and decomp.dev for your game and its engine. Check
Set up the matching build in WSL
You set up WSL with the splitter, the disassembler, an Allegrex assembler, the diff tool and the old compiler. The build must check the hash of every module. One command builds and checks all.
- In WSL (Ubuntu 24.04), run
sudo apt-get install binutils-mipsel-linux-gnu ninja-build python3-venv libc6-i386. Then make a venv withpython3 -m venv .venv. libc6-i386is needed because the Sonypsp-gcckits are 32-bit Linux programs.- Install the Python tools with
.venv/bin/python3 -m pip install -U splat64[mips] spimdisasm ninja_syntax. - Stock
binutilsmay not know Allegrex. Getallegrex-as.tar.gzfrom thecc1-psx-26release ofsotn-decomp, check its SHA-256, and unpack it. - Download
wibo-i686(1.2.0) andobjdiff-cli-linux-x86_64from their release pages. Runchmod +xon both. - Download your kit, like
mwccpsp_3.0.1_219.tar.gz, from thecompilersrelease ofdecompme/compilers. Unpack it inbin/on the Linux file system, outside Git. - Pin the kit's SHA-256 in a file, like
mhp2g-decompdoes withbin/mwccpsp_219.tar.gz.sha256. - Add
mwccgapas a submodule if you use CodeWarrior. It lets C files hold not-yet-matched functions as assembly. Point its--as-pathat the Allegrex assembler. - Write
configure.pythat writes abuild.ninja. The last build step runssha1sum -con every module.
Prompt for ClaudeGOAL: Make `ninja` build the module <MODULE> from its assembly and check its SHA-1. READ FIRST: `SCOPE.md`, `notes/compilers.md`, `configure.py`, the setup of `tclamb/mhp2g-decomp` as a model. FENCE: Edit only `configure.py`, `config/`, `tools/` and `requirements.txt`. Never edit the checksum files in `config/*.sha1`. Never commit compilers or game files. CHECK: In WSL, run `python3 configure.py && ninja`. Done means it exits 0 and the last line shows the module's `sha1sum -c` OK. BUDGET: Stop after 3 failed tries with the same error, or 60 minutes. IF BLOCKED: Stop. Do not change a checksum to pass. Tell me the error and what you need. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the `ninja` output tail. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenninjaexits 0 andsha1sum -creports OK for the module built from assembly.Proof this works: https://github.com/tclamb/mhp2g-decomp (configure.py, mwccgap, wibo, sha1sum, patched Allegrex assembler), Dissidia012-PC tools/setup_wsl.sh (binutils-mipsel-linux-gnu plus allegrex-as from sotn-decomp), Dissidia012-PC (SNC through wibo in WSL Ubuntu 24.04), https://github.com/decompals/wibo
- In WSL (Ubuntu 24.04), run
Split each module
splatcuts a module into code, data and a linker script. Start with the smallest module. Overlays and extra.prxfiles are separate modules.- Write a
splatconfig per module inconfig/<module>.yaml. - Run
python3 -m splat split config/<module>.yaml. - Fix segment edges until the module rebuilds from assembly with the right hash.
- If the splat linker script pads segments, write your own linker script.
- Keep
symbol_addrs.txtas the one place for names.
Prompt for ClaudeGOAL: Split <MODULE> with splat so it rebuilds byte for byte from assembly. READ FIRST: `config/<MODULE>.yaml`, `notes/compilers.md`, the splat wiki page on segments. FENCE: Edit only `config/<MODULE>.yaml`, `config/<MODULE>.symbol_addrs.txt` and the module linker script. Never edit files in `asm/` by hand; they are generated. CHECK: In WSL, run `python3 -m splat split config/<MODULE>.yaml && ninja`. Done means `sha1sum -c` prints OK for <MODULE>. BUDGET: Stop after 5 split attempts with no progress, or 60 minutes. IF BLOCKED: Stop. Tell me which segment edge is wrong and the bytes around it. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the `sha1sum` line. 3) Files changed. 4) Segments still unsure. 5) New parking-lot items.
Done whenThe module rebuilt from split assembly passessha1sum -c.Proof this works: Dissidia012-PC (splat linker script replaced by a hand-written one), https://github.com/ethteck/splat, https://github.com/angelof-exe/ygo-tf-5-decomp (section-accurate splat config)
- Write a
Map functions and mark library code
You build the function ledger. You mark SDK and middleware code so no one matches it by hand. You find repeated functions, because one match can solve many.
- Export the function list with sizes from Ghidra or the splat output.
- Mark Sony SDK, C library and middleware functions in the ledger.
- Find functions with the same bytes. A match for one is a match for all copies.
- Sort the rest by size. Small leaf functions go first.
- Set up
objdiffwith anobjdiff.jsonso it can report progress.
Prompt for ClaudeGOAL: Build `ledger/functions.csv` for <MODULE> with kind, size, duplicate group and status. READ FIRST: `config/<MODULE>.symbol_addrs.txt`, the Ghidra export at `<EXPORT_PATH>`, `ledger/README.md`. FENCE: Edit only `ledger/`. Everything else is read-only. CHECK: Run `python3 tools/ledger_check.py`. Done means it prints OK: every function in the module is in the ledger once, and each has a kind and a status. BUDGET: Stop after 60 minutes. IF BLOCKED: Stop. Do not guess library names. Mark unsure rows as unknown and tell me how many. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Counts by kind and the number of duplicate groups. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whentools/ledger_check.pyprints OK and every function has a kind and a status.Proof this works: https://github.com/Jstar269/HST-Decomp (SDK code kept out; duplicates reused by a tool), Tag Force Recomp (pick functions by session coverage)
Match the first function
You match one small function end to end. This proves the compiler, flags and build. Then the whole module must still pass its hash.
- Pick a small leaf function from the smallest module.
- Get a draft from
m2con its assembly. - Edit the C until
objdiffshows 100% for that function. - Replace its
INCLUDE_ASMline with the C. - Run the full build. The module hash must still match.
Prompt for ClaudeGOAL: Make `<FUNCTION>` in `src/<MODULE>/<FILE>.c` match exactly. READ FIRST: `asm/<MODULE>/<FUNCTION>.s`, `notes/compilers.md`, `notes/compiler-quirks.md`. FENCE: Edit only `src/<MODULE>/<FILE>.c` and headers in `include/` that this function needs. No inline asm, no `.word`, no `.incbin`, no `#pragma` tricks. CHECK: In WSL, run `ninja`. Done means objdiff shows 100% for `<FUNCTION>` and `sha1sum -c` prints OK for the whole module. BUDGET: Stop after 10 attempts with no gain. Save each attempt as a new file in `try/<FUNCTION>/`. IF BLOCKED: Stop. Report the best score, the remaining differing instructions and your theory. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the objdiff score and the sha1sum line. 3) Files changed. 4) Compiler lessons learned.
Done whenobjdiffshows 100% for the function and the full module passessha1sum -c.Proof this works: Dissidia012-PC (started on the 24 KB extra overlay), https://github.com/angelof-exe/ygo-tf-5-decomp (smallest module first, 15 of 16 matched), https://github.com/matt-kempster/m2c
Bulk grind with many workers
Now you match many functions in parallel. A script picks the next units, not the model. Duplicates and tool output go first, then small functions, then bigger ones.
- Let tools handle repeated code and plain translations first. They cost no tokens.
- Give each worker its own git worktree and its own slice of the ledger.
- One function per session. Clear the chat between functions.
- Workers save near misses in
wip/with a note. Only exact matches go insrc/. - Merge one branch at a time. Run the full build after each merge.
Prompt for ClaudeGOAL: Match the functions in batch <BATCH_ID> from `ledger/batches/<BATCH_ID>.txt`, one at a time. READ FIRST: `CLAUDE.md`, `notes/compiler-quirks.md`, the batch file. Nothing else unless a function needs it. FENCE: Work only in worktree `<WORKTREE_PATH>`. Edit only the `src/` files of functions in this batch and `wip/`. Never edit `asm/`, `config/*.sha1`, `tools/` or the ledger. CHECK: After each function, run `ninja`. A function is done only when objdiff shows 100% and `sha1sum -c` prints OK. BUDGET: At most 5 serious attempts per function. Then save the best try in `wip/` with a note and move on. IF BLOCKED: Stop the batch. Tell me what broke the build and the last good commit. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) A table: function, result, attempts. 3) Files changed. 4) Functions left. 5) New parking-lot items.
Done whenEvery function in the batch is either matched with a passing build or saved inwip/with a note.Proof this works: https://github.com/Jstar269/HST-Decomp (tools first, agents on the rest, 41% of code in about four weeks), https://blog.chrislewis.au/the-unexpected-effectiveness-of-one-shot-decompilation-with-claude/ (Snowboard Kids 2: one function per headless run)
Work the hard tail
Some functions resist the bulk workers. They need a stronger job type and a shared file of compiler lessons. Some may never match without a trick, and that is allowed to stay open.
- Send units that failed five bulk tries to the hard queue.
- Keep
notes/compiler-quirks.mdshort and general. No notes about single functions. - Check VFPU code. Allow inline VFPU asm only where the original used it, and mark it.
- Try the other compiler kits only for functions the main one cannot reproduce.
- Leave a function non-matching rather than accept a fake match.
Prompt for ClaudeGOAL: Match `<FUNCTION>`, which failed 5 bulk attempts. READ FIRST: `wip/<FUNCTION>.c` and its note, `asm/<MODULE>/<FUNCTION>.s`, `notes/compiler-quirks.md`. FENCE: Edit only `src/<MODULE>/<FILE>.c`, `wip/<FUNCTION>.c` and `notes/compiler-quirks.md` (general lessons only). No asm that emits non-VFPU instructions, no `.word`, no data in `.text`. CHECK: Run `ninja`. Done means 100% in objdiff and `sha1sum -c` OK. BUDGET: Stop after 15 attempts with no gain. Save each try in `try/<FUNCTION>/`. IF BLOCKED: Stop. Name the exact differing instructions and a theory class, not a vague guess. Say if it may need a different compiler build. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Best score and the diff summary. 3) Files changed. 4) The lesson for `compiler-quirks.md`, if general.
Done whenThe function matches with a passing build, or it is left inwip/with the exact remaining differences named.Proof this works: https://github.com/Jstar269/HST-Decomp (VFPU inline asm rule, secondary compiler only for leftovers), Dissidia012-PC (-g changes SNC scheduling; twelve functions differ without it)
Harden: gates, review and progress
You add checks that catch fake matches. A fresh agent re-checks claimed work. CI rebuilds everything from scratch on a machine Claude cannot touch.
- Write a gate script that rejects
.word,.incbin, non-VFPU asm and data forced into code. - Block edits to
config/*.sha1andtools/with a Claude Code hook. - Run a fresh verify session on every merged batch.
- Have CI run
configure.pyandninjafrom a clean clone. - Publish an
objdiffprogress report on each merge.
Prompt for ClaudeGOAL: Verify the matches claimed in branch <BRANCH> and hunt for cheating. READ FIRST: `CLAUDE.md`, the diff of <BRANCH> against main, `tools/gate.py`. FENCE: Read only. Do not fix anything. Write findings only in `notes/verify-<BRANCH>.md`. CHECK: On a clean clone, run `python3 configure.py && ninja && python3 tools/gate.py`. Done means you report each claimed function as REAL or FAKE with proof. BUDGET: Stop after 60 minutes. IF BLOCKED: Stop. Tell me what you could not check and why. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the build and gate output. 3) A table: function, REAL or FAKE, reason. 4) Any edits outside the fence in the diff. 5) Any changed checksum or tool file.
Done whenA clean clone builds,sha1sum -cpasses, the gate passes, and the verify note lists no fake matches.Proof this works: https://github.com/Jstar269/HST-Decomp (hstgate.py rejects fake matches), https://github.com/cdlewis/snowboardkids2-decomp/tree/main/.claude/hooks (hooks block checksum and asm edits)
- Write a gate script that rejects
Port: swap recompiled code for your C
No PSP game has a finished decomp port yet. The realistic route is a hybrid. Your matched C replaces recompiled functions inside the Path A runtime. When every function is C, you drop the generated code.
- Hook each recompiled function so your C can run in its place.
- Add a
--verify-overridesswitch totools/regress.py. It runs the original and your C from the same state, like Tag Force'sTF_DECOMP_VERIFY. - Run the old and new versions from the same state and compare results.
- Grow the C part one module at a time, driven by your replays.
- Move system calls behind one interface so the runtime can change.
- Fix 64-bit pointer and byte-order issues before a new target.
- Build for the new system and run the same replays.
Prompt for ClaudeGOAL: Replace the recompiled `<FUNCTION>` with the decomp C in the Path A runtime. READ FIRST: `src/<MODULE>/<FILE>.c`, the hook table in `host/`, `PROGRESS.md`. FENCE: Edit only the override file in `host/overrides/` and the hook table. Never edit `generated/`. Do not change the matched source. CHECK: Run `python tools/regress.py --verify-overrides`. Done means the original and the override give the same results from the same state, and all replays pass. BUDGET: Stop after 3 failed tries. IF BLOCKED: Stop. Tell me which value differs, where, and your theory. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the compare and replay output. 3) Files changed. 4) What is left. 5) New parking-lot items.
Done whenThe override gives the same results as the original from the same state, and all replays pass.Proof this works: Dissidia012-PC (matched C used as native overrides), Tag Force Recomp (TF_DECOMP_VERIFY runs both from the same state), https://github.com/nicolalol3/mhfu-decomp (non-matching C injected into the real program)
Tools you need
| Tool | What it does | How to get it | How we know |
|---|---|---|---|
| PortableKit Required both | A PSP recompiler and full runtime. Its team (TeamGDB) took it out of Yakumo. It has an interpreter, a Vulkan renderer, audio, saves and an installer. Path A Path B | git clone --recursive https://github.com/TeamGDB/PortableKit.git, then cmake -S . -B out -G Ninja -DCMAKE_BUILD_TYPE=Release and cmake --build out -j2 (on Windows, in a Visual Studio developer prompt) | README, BRINGING_UP_A_GAME.md, BUILDING.md and PROFILE_GUIDE.md read 2026-11-13. Extracted from Yakumo; used by: Dissidia012-PC, Portable Ops Native (a fork). CI tests the framework on Windows, but its README says only Yakumo has run a game there. |
| PSPRecomp Helpful both | The other PSP recomp framework. It gives psp_analyze, psp_recomp and a runtime. You add a game profile. It has no interpreter and no decryption.Path A | git clone https://github.com/jessicanataliagta/PSPRecomp.git, then cmake -S . -B out/framework -DPSPRECOMP_PROFILE="" and cmake --build out/framework --config Release | README and docs/PROFILE_GUIDE.md read 2026-11-13; Yakumo, Ape Escape and Sims 2 also build it on Linux; used by: LCS Recomp, Vice City Stories Recomp, Renegade Squadron PC, Ape Escape, Sims 2 PSP, MHForever |
| PPSSPP Required Windows | The main PSP emulator. You use it as the reference for how the real system acts, and to save function names as a .sym file.Path A Path B | Download PPSSPPSetup.exe or ppsspp_win.zip (version 1.20.4) from https://www.ppsspp.org/download/ | download page read 2026-11-13; used by: The 3rd Birthday (oracle), God of War PSP, Dissidia012-PC |
| pspdecrypt Required both | Decrypts a PSP program file, like EBOOT.BIN, into an ELF or PRX you can read.Path A Path B | Download pspdecrypt-1.0-windows.zip or pspdecrypt-1.0-linux.zip from the releases page | README and release 1.0 assets read 2026-11-13; used by: mhp2g-decomp, LCS Recomp; Dissidia012-PC used the hrydgard fork |
| Ghidra Required both | A free tool that shows a program's functions and turns machine code into rough C. You use it to map the game. Path A Path B | Install JDK 21 64-bit, then unzip ghidra_12.1.4_PUBLIC_20260921.zip from the Ghidra_12.1.4_build release. Use 12.1.4, not 12.2, because GhidraMCP needs it. | README at tag Ghidra_12.1.4_build (JDK 21) and release list read 2026-11-13; latest is 12.2 (JDK 25); GhidraMCP README asks for 12.1.4; used by: God of War PSP and Dissidia012-PC (12.1.3), Tag Force Recomp |
| ghidra-allegrex Required both | A Ghidra add-on for the PSP's CPU. It reads PSP relocations, VFPU code and PPSSPP symbol files.Path A Path B | Download ghidra_12.1.4_PUBLIC_20261025_ghidra-allegrex.zip from release v21.4, then File -> Install Extensions in Ghidra. For Ghidra 12.2, use v21.6 instead. | README and releases v21.4 and v21.6 read 2026-11-13; used by: God of War PSP, Dissidia012-PC (v21.4) |
| Visual Studio 2022, CMake and Ninja Required Windows | The C++ compiler and build tools for Path A on Windows. clang-cl from Visual Studio or LLVM builds the generated code faster.Path A | Install Visual Studio 2022 with the C++ workload; install CMake 3.20 or newer and Ninja. Run Ninja builds from a Visual Studio developer prompt. | PortableKit and PSPRecomp READMEs read 2026-11-13; used by: Vice City Stories Recomp, LCS Recomp, Renegade Squadron PC |
| Vulkan SDK Required both | Headers, the shader compiler and validation layers for the Vulkan renderer. The validation layer finds draw-order bugs. Path A | Download the Windows installer from https://vulkan.lunarg.com/ | PortableKit README read 2026-11-13: a port needs a Vulkan loader, headers and glslangValidator; used by: Vice City Stories Recomp (glslc), The 3rd Birthday (sync validation), Sims 2 PSP (CI validation) |
| splat Required WSL/Linux | Splits a PSP module into assembly, data and a linker script. It supports PSP binaries. Path B | python3 -m pip install -U splat64[mips] | README and Quickstart wiki read 2026-11-13; used by: Dissidia012-PC (0.50.0), mhp2g-decomp, sotn-decomp |
| spimdisasm Required WSL/Linux | A MIPS disassembler that makes assembly which builds back exactly. It knows the PSP's Allegrex instructions. Path B | python3 -m pip install -U spimdisasm | README read 2026-11-13; used by: Dissidia012-PC (1.42.4), mhp2g-decomp |
| m2c Helpful both | Turns MIPS assembly into a first C draft. You then edit the draft until it matches. Path B | python3 -m pip install "m2c @ git+https://github.com/matt-kempster/m2c.git" | README read 2026-11-13; used by: sotn-decomp, ygo-tf-5-decomp |
| objdiff Required both | Compares your compiled function with the original, byte by byte. The CLI writes progress reports. Path B | Download objdiff-windows-x86_64.exe (GUI) and objdiff-cli-linux-x86_64 (for WSL) from the v3.8.3 release | README and v3.8.3 release assets read 2026-11-13 (lists MIPS PSP); used by: mhp2g-decomp (v3.6.1 pinned in configure.py) |
| wibo Required WSL/Linux | Runs small Windows command-line programs on Linux. PSP decomps use it to run the old Windows compilers in WSL. Path B | Download wibo-i686 from the releases page (1.2.0) and make it executable with chmod +x | README and release 1.2.0 read 2026-11-13; used by: Dissidia012-PC (SNC), mhp2g-decomp, HST-Decomp |
| PSP compiler kits (decomp.me) Required WSL/Linux | The list of PSP compilers the decomp community uses: mwccpsp builds 121 to 219, psp-gcc 1.3.1 and 1.7.1, and pspsnc 1.2.7503.0.Path B | In WSL: wget https://github.com/decompme/compilers/releases/download/compilers/<KIT>.tar.gz, then tar xzf it into bin/<KIT> on the Linux file system, outside Git | repo tree and the PSP Dockerfiles read 2026-11-13: each kit downloads <KIT>.tar.gz from the compilers release; HST-Decomp says to install compilers from these kits |
| mwccgap Helpful WSL/Linux | Lets a C file hold unmatched functions as assembly when you use the CodeWarrior compiler. It swaps the assembly in after compiling. Path B | git submodule add https://github.com/mkst/mwccgap.git tools/mwccgap | README read 2026-11-13 (it gives no install command; mhp2g-decomp adds it as a submodule at tools/mwccgap); used by: mhp2g-decomp, sotn-decomp |
| Allegrex assembler (allegrex-as) Required WSL/Linux | A GNU assembler build that knows the PSP's Allegrex and VFPU instructions. PSP matching builds use it in place of the stock MIPS assembler. Path B | In WSL: download allegrex-as.tar.gz from the cc1-psx-26 release of Xeeynamo/sotn-decomp, check its SHA-256, and unpack it | sotn-decomp Makefile and Dissidia012-PC tools/setup_wsl.sh read 2026-11-13; used by: sotn-decomp, Dissidia012-PC; mhp2g-decomp builds a patched pspas instead |
| WSL with Ubuntu 24.04 Required Windows | Linux inside Windows. Path B runs its build here, with ninja, MIPS binutils, Python and the old compilers.Path B | wsl --install -d Ubuntu-24.04, then in WSL: sudo apt-get install binutils-mipsel-linux-gnu ninja-build python3-venv libc6-i386 | Dissidia012-PC card (WSL Ubuntu 24.04, binutils-mipsel-linux-gnu); sotn-decomp tools/requirements-debian.txt (ninja-build, python3-venv); HST-Decomp docs/GUIDE.md (libc6-i386) read 2026-11-13 |
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.
matching-decomp (decomp-skills)
A one-function-at-a-time method with a small tool, dk.py, for MIPS splat projects. PSP is on its list. It commits matches and undoes misses, so save your work first.
npx skills add ketbome/decomp-skills --skill matching-decomp -a claude-code
decompile-to-matching-c-cpp
Rules for byte-matching C and C++ that ban fake matches. It fits Path B, where much PSP code is C++.
npx skills add xsyetopz/skills --skill decompile-to-matching-c-cpp -a claude-code
debug-game-in-emulator
Makes every PPSSPP run the same: a throwaway data folder, a log and a time limit. Claude must name the failing layer before any change.
npx skills add xsyetopz/skills --skill debug-game-in-emulator -a claude-code
dl-binary-recompilation-engineer
A design guide for a recompiler and runtime. Use it if your game needs changes inside PortableKit or PSPRecomp. It suggests running npx rea-agents setup; decide that yourself.
npx skills add alexishida/dalhe-cli --skill dl-binary-recompilation-engineer -a claude-code
ghidra-headless
Runs Ghidra with no window and writes functions and code to files. Set GHIDRA_HOME yourself on Windows. Install ghidra-allegrex first.
npx skills add trailofbits/skills-curated --skill ghidra-headless -a claude-code
orchestrator
Runs a Path B push with many workers, each in its own worktree and slice. Every merge must pass the byte check.
npx skills add lemiur/game-decompilation-skill-for-claude --skill orchestrator -a claude-code
verification-before-completion
Claude may not say DONE without fresh proof from the check. That fits both the boot check and the hash check.
npx skills add obra/superpowers --skill verification-before-completion -a claude-code
handoff
Writes a short note so a fresh session can carry on. Tell it to save inside the project, not the temp folder.
npx skills add mattpocock/skills --skill handoff -a claude-code
GhidraMCP
Lets Claude list functions, read decompiled code and rename things in Ghidra. It needs Ghidra 12.1.4, so use the 12.1.4 build of ghidra-allegrex too. MHForever planned a Ghidra plus MCP setup.
In Ghidra 12.1.4, add the release 2.0 zip with File -> Install Extensions and enable GhidraMCPPlugin in 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/
psp-boot-check
Every Path A task ends with the same bounded run. The skill makes Claude run it the same way each time and read the right log lines.
A project skill in `.claude/skills/psp-boot-check/SKILL.md`. It runs `python tools/boot_check.py` with a time limit, the interpreter on or off, and a replay file. It reads the log and reports the first `[hle-stub]` line, the stop reason and interpreted addresses. It never leaves the game running.
psp-match-one
Path B workers need one fixed loop with a hard stop. This keeps every worker on the same compiler, flags and verdict.
A project skill in `.claude/skills/psp-match-one/SKILL.md`. It builds one function with the chosen `mwccpsp` or `pspsnc` kit through `wibo`, prints the `objdiff` score, runs `ninja` and `sha1sum -c`, and saves each try in `try/<function>/`. It lists the banned constructs and stops after five tries.
Claude setup for this system
On Path A, one task is one missing system call, one crash or one drawing bug. Each ends with the bounded boot check or a replay. On Path B, one task is one function, checked by objdiff and the module hash. Keep the ledger as the list of units. Give each worker a slice, never the whole game.
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 | Survey the disc, pick PortableKit or PSPRecomp, find prior work and write SCOPE.md. For Path B, also run the compiler test. | 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 | Build the framework, write the profile constants, the boot check and the content guard. For Path B, set up WSL, splat, wibo and ninja. | Opus 5.5 effort medium | Sonnet 5.5 effort medium |
| Study the game file | Map the decrypted program in Ghidra with ghidra-allegrex. List imports by NID, find overlays and mark SDK code in the ledger. | Opus 5.5 effort high | Opus 5.5 effort mediumRaise to high for function edges and data layouts. A mistake there spreads. |
| Build the runtime | Write missing system calls, GE drawing features, audio and saves in the game profile. Use PPSSPP behaviour as the reference. | Opus 5.5 effort high | Opus 5.5 effort mediumRaise to high for timing and graphics bugs. |
| Find a bug | Find why a scene crashes or draws wrong. Use the _TRACE_ switches, PPSSPP memory watches and frame captures. No fix until the cause is proven. | 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. |
| Bulk units | Match small Path B functions, one per session, in parallel worktrees. On Path A, add simple calls that the import list already describes. | 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 that failed five bulk tries, VFPU-heavy code, and compiler quirks. On Path A, timing bugs and overlay switching. | 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. |
| Check the work | A fresh session rebuilds from a clean clone. It reruns the boot check with the interpreter off, or the hash check. It hunts for fake matches and faked calls. | 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, dead ends and the compiler-quirks file after each batch. | Haiku 5.5 effort medium | Haiku 5.5 effort medium |
How many sessions at once
Max 20x (now called Ultra)
Path A: run one lead session and two or three workers, each on one bug in its own worktree. Only one full build runs at a time, because generated files use gigabytes of memory. Path B: run four to six match workers in worktrees, plus one verify session.
Max 5x (now called Max)
Path A: one worker at a time, plus a short verify session at the end of each day. Path B: two match workers in worktrees. Send hard units to one session late in the week.
Lines for this project's CLAUDE.md
- Read `SCOPE.md` and `PROGRESS.md` at the start of every session. - Never edit files in `generated/`. If generated code is wrong, fix the generator or the profile, then regenerate. - Bound every game run with a time limit. Never leave the game running or drive it with an open-ended input loop. - Path A: build with `cmake --build out --target <TARGET> -j2`, never `ninja` directly. Never delete `.ninja_deps` or `.ninja_log`. - A boot is done only when `python tools/boot_check.py --no-interpreter` prints PASS. - Trace the hardware; do not recall it. Never write GE register numbers, PSP structs or NID meanings from memory. - A missing system call must stop the run with its name. Never return a fake success to move on. - No game data in Git: no ISO, EBOOT, PRX, decrypted files, generated code or captures. - `portablekit/` is read-only. Framework changes go in numbered patch files I approve. - Path B: only `ninja` with `sha1sum -c` OK counts as a match. Never edit `config/*.sha1`, `asm/` or `tools/`. - Path B: no inline asm except VFPU asm the original used, no `.word`, no `.incbin`, no data in `.text`. - Never paste game disassembly into decomp.me or other public sites. - In a worktree, use absolute paths and run builds only inside that worktree. - Write side issues in `notes/parking-lot.md`. Write each result and dead end in `PROGRESS.md`. - Do not copy code from `PPSSPP` into this repo. Read it as a reference only.
Keep the context small
- Give Claude an address and a log path, not pasted disassembly.
- Ask for one
_TRACE_switch at a time. Full traces of a hot module run for a long time and fill the context. - Never let Claude open files in
generated/. They are huge. Usedump_functionfor one function instead. - Clear the chat after each fixed bug or matched function.
- Use a subagent to read a long Ghidra export and return a short summary.
- Keep
CLAUDE.mdshort. Point tonotes/compiler-quirks.mdand the bring-up doc by topic.
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 on a new PSP game. It ends with a draft SCOPE.md and a clear yes, no or maybe.
GOAL: Decide if <GAME> (<DISC_ID>) can be recompiled for PC, and which framework to use. READ FIRST: `notes/disc-listing.txt`, the READMEs of `TeamGDB/PortableKit` and `jessicanataliagta/PSPRecomp`, the RecompLauncher PSP list. FENCE: Edit only `SCOPE.md` and `notes/survey.md`. Write no code. CHECK: `SCOPE.md` answers: is EBOOT.BIN encrypted, extra PRX modules, overlays, import count by library, VFPU use, prior work with URLs, framework pick with reasons, first milestone and its check. BUDGET: Stop after 45 minutes. IF BLOCKED: Stop. Say plainly what you cannot know without the disc or a test run. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Verdict: go, no-go or test first, with reasons. 3) Files changed. 4) Risks ranked. 5) New parking-lot items.
A good answer: A filled SCOPE.md, a one-line verdict, and risks ranked with evidence, like 300 overlays or 2,000 VFPU instructions.
Map the binary
After the executable is decrypted and pinned. Use it to build the function ledger and the import list.
GOAL: Build `ledger/functions.csv` and `ledger/imports.md` from the Ghidra export of <GAME>. READ FIRST: `SCOPE.md`, `<EXPORT_PATH>`, the `PPSSPP` `.sym` file at `<SYM_PATH>`. FENCE: Edit only `ledger/`. The Ghidra project is read-only. CHECK: Run `python tools/ledger_check.py`. Done means it prints OK and the function count equals the export's. BUDGET: Stop after 60 minutes. IF BLOCKED: Stop. Mark unsure rows as unknown. Do not invent names. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Counts: functions, SDK, middleware, imports, overlays. 3) Files changed. 4) What is left.
A good answer: A ledger whose counts match Ghidra, imports grouped by library, and overlay loaders named by address.
Unit loop: one missing system call (Path A)
Each time the boot stops at a missing call.
GOAL: Implement `<LIBRARY>::<FUNCTION>` so the boot passes it. READ FIRST: `CLAUDE.md`, the boot log `<LOG_PATH>`, `ledger/imports.md`. FENCE: Edit only the HLE files in `host/`. `portablekit/` and `generated/` are read-only. CHECK: Run `python tools/boot_check.py --seconds 90`. Done means the log passes this call and earlier milestones still print. BUDGET: Stop after 3 failed tries or 45 minutes. IF BLOCKED: Stop. Do not fake a return value. Tell me what the game expects. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Log lines before and after. 3) Files changed. 4) The next stop.
A good answer: DONE, the log lines showing the call passed, one small file changed, and the next missing call named.
Unit loop: match one function (Path B)
For each function in the bulk queue.
GOAL: Make `<FUNCTION>` match exactly with <COMPILER> <FLAGS>. READ FIRST: `asm/<MODULE>/<FUNCTION>.s`, `notes/compiler-quirks.md`. FENCE: Edit only `src/<MODULE>/<FILE>.c`. No inline asm except original VFPU asm, no `.word`, no `#pragma` tricks. CHECK: In WSL, run `ninja`. Done means objdiff 100% for `<FUNCTION>` and `sha1sum -c` OK. BUDGET: 5 serious attempts. Save each in `try/<FUNCTION>/`. IF BLOCKED: Stop. Save the best try in `wip/` with a note naming the differing instructions. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Score and sha1sum line. 3) Files changed. 4) Lesson, if general.
A good answer: DONE with 100% and an OK hash, or PARTIAL with the best try saved and the exact differences named.
Batch dispatch
In the lead session, to hand out the next units to workers.
GOAL: Pick the next <N> units from `ledger/functions.csv` (or `ledger/bugs.md`) and start one worker per unit. READ FIRST: `CLAUDE.md`, the ledger, `PROGRESS.md`. FENCE: Edit only the status column of the ledger and `ledger/batches/`. Each worker gets its own worktree at an absolute path. Do not do unit work yourself. CHECK: Each worker reports with the unit's check output. Done means every unit is marked matched, fixed, wip or blocked, with proof pasted. BUDGET: At most <N> workers at once. Stop the batch if two workers break the build. IF BLOCKED: Stop. Tell me which worker broke what and the last good commit. OTHER PROBLEMS: Collect them in `notes/parking-lot.md`. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Table: unit, worker, result, proof line. 3) Ledger rows changed. 4) Next batch suggestion.
A good answer: A table with one row per unit, each with a proof line, and ledger statuses updated to match.
Debug with evidence
When a scene crashes, hangs or draws wrong.
GOAL: Find the cause of <SYMPTOM> at <WHERE>. Do not fix it yet. READ FIRST: `PROGRESS.md` dead ends, the log `<LOG_PATH>`, the capture `<CAPTURE_PATH>`. FENCE: Read only, except new trace output under `out/traces/`. No code changes. CHECK: Done means you name the cause and show trace lines or a `PPSSPP` comparison that prove it. BUDGET: Stop after 60 minutes or 3 theories that fail. IF BLOCKED: Stop. List each theory, the test you ran and what it showed. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) The cause and its proof. 3) The fix you suggest and its risk. 4) Dead ends to record.
A good answer: One cause backed by trace lines or a memory diff, a suggested fix, and dead ends written down.
Verify and hunt for cheating
In a fresh session after each batch or before each release.
GOAL: Check that the work claimed in <BRANCH> is real. READ FIRST: `CLAUDE.md`, the diff of <BRANCH> against main. FENCE: Read only. Write only `notes/verify-<BRANCH>.md`. CHECK: On a clean clone, run the full check: Path A `python tools/regress.py --no-interpreter`; Path B `python3 configure.py && ninja && python3 tools/gate.py`. Done means each claim is marked REAL or FAKE with proof. BUDGET: Stop after 60 minutes. IF BLOCKED: Stop. Say what you could not check. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Check output. 3) Look for: edited hashes, edited tools, edits in `generated/`, fake system call returns, interpreter left on, asm in sources, disabled tests. 4) Verdict per claim.
A good answer: A list of every claim with REAL or FAKE, the check output pasted, and any edit outside the fence named.
Status report
At the end of a day or a batch.
GOAL: Report project status from the ledger and logs only. READ FIRST: `ledger/functions.csv`, `ledger/bugs.md`, `PROGRESS.md`, the last regression output. FENCE: Read only. Write only `notes/status-<DATE>.md`. CHECK: Every number in the report comes from a file or a command you ran. Name the source next to each number. BUDGET: 15 minutes. IF BLOCKED: Stop. Say which number you could not get. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Counts: matched, wip, open bugs, replays passing, stages reached. 3) Change since last report. 4) Top three blockers. No prose padding.
A good answer: A short list of numbers with sources, the change since last time, and three blockers.
Session handoff
Before you stop for the day or when a session gets long.
GOAL: Write what the next session needs into the ledger files. READ FIRST: `PROGRESS.md`, `git status`, `git log -5`. FENCE: Edit only `PROGRESS.md` and the ledger status columns. No code changes. CHECK: A new session can start from `PROGRESS.md` alone. It names the current unit, its state, the last check output, the next step and the dead ends. BUDGET: 10 minutes. IF BLOCKED: Stop. Say what state you could not confirm. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) The new `PROGRESS.md` section. 3) Uncommitted files and why.
A good answer: A dated PROGRESS.md section with the next step, the last proof and the dead ends, plus a list of uncommitted files.
Blocked or cannot deliver
When a task has gone around in circles or Claude says it is impossible.
GOAL: Give me a plain answer on <TASK>: can it be done, and how. READ FIRST: Your notes on this task and `PROGRESS.md` dead ends. FENCE: Read only. No more attempts. CHECK: Done means you state one of: can do with <PLAN>, cannot do because <PROOF>, or unknown until <TEST>. BUDGET: 10 minutes. IF BLOCKED: Say unknown and name the one test that would tell. REPORT: 1) DONE, PARTIAL or BLOCKED. 2) What cannot be done and why, with evidence. 3) Two or three options with cost in sessions. 4) Your pick.
A good answer: A short, honest verdict with evidence and priced options, not another attempt.
Scope change request
When Claude finds that the task needs edits outside the fence.
GOAL: Ask me before you leave the fence for <TASK>. READ FIRST: `SCOPE.md`, the task card you are on. FENCE: Make no edits outside the fence while you wait. CHECK: Done means I have your request with: the file or folder, the exact change, why the task needs it, and the risk. BUDGET: 5 minutes to write the request. IF BLOCKED: Park the task in `PROGRESS.md` and stop. OTHER PROBLEMS: Write them in `notes/parking-lot.md`. REPORT: 1) BLOCKED. 2) The request. 3) What you will do if I say no.
A good answer: A short request naming the file, the change and the risk, and a plan for a no.
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 generated C++ to fix a crash. | Never edit generated/. Fix the generator or the profile, then regenerate. Block the folder with a hook. |
| Claude returns a fake success from a missing system call so the game moves on. | A missing call stops the run with its name. Use strict HLE mode. A fake return is a failed task. |
| Claude writes GE register numbers, PSP structs or NID meanings from memory. | Trace the hardware; do not recall it. Every constant needs a trace line, a PPSSPP source line or a doc link. |
| Claude says the game runs, but the interpreter ran the missing parts. | A boot counts only when python tools/boot_check.py --no-interpreter prints PASS. Paste that output. |
| Claude starts a full rebuild or many compile jobs and the machine runs out of memory. | Build named targets with -j2. Full rebuilds and sweeps only for release candidates, when I ask. |
| Claude leaves the game running or drives it with an endless input loop. | Every run goes through tools/boot_check.py with a time limit. No open-ended loops. |
Claude forces a match with .word, non-VFPU asm or data placed in code. | The gate script refuses these. A clean non-match in wip/ beats a fake match. |
Claude copies code from PPSSPP into an MIT project, or pastes game code into decomp.me. | PPSSPP is a read-only reference. Never post game bytes or disassembly to public sites. |
Problems other projects hit
System calls silently did nothing because the recompiler found stubs by section name, and the game had its section names stripped.
Fix: Find import stubs from the import table, not section names. Run a bake-off on your own executable before picking a tool.
Seen in: The 3rd Birthday Recomp
The 16 KiB scratchpad memory at 0x00010000 was not mapped. Bone data stayed zero and the hero was invisible.
Fix: Map every PSP memory region, including the scratchpad. Add a test for it in the framework.
Seen in: The 3rd Birthday Recomp, Ape Escape Mind Over Monkey, The Sims 2 PSP Recomp
Most of the code lived in overlays loaded at run time, so a recompile of EBOOT.BIN alone missed it.
Fix: Survey overlays early. Recompile each one at its load address, and pick it by a hash of bytes the game never writes.
Seen in: MHForever, Yakumo, Dissidia012-PC, Portable Ops Native
Generated files are huge. Too many compile jobs ran out of memory, and the first build took an hour or more.
Fix: Use -j2 or one job per 4 GiB. Use ccache. Keep generated code out of link-time optimisation.
Seen in: Yakumo, Renegade Squadron PC, Vice City Stories Recomp, LCS Recomp
The game crashed at start on Linux because the recompiled code nests very deep.
Fix: Give the main thread a 64 MiB stack. On Linux run ulimit -s 65536 first.
Seen in: Yakumo, Ape Escape Mind Over Monkey
Some VFPU instructions were not handled, and Ghidra shows VFPU code poorly.
Fix: Count unsupported(...) sites before compiling. Translate instructions, not Ghidra's C. Test VFPU code against a reference.
Seen in: God of War PSP, Ape Escape Mind Over Monkey
Ghidra's C hid function arguments and return values, which led to crashes in hand-written code.
Fix: Read the registers set before each call and the load widths. Never trust Ghidra's C for call arguments.
Seen in: Tag Force Recomp
A paletted texture was rebuilt every frame. Memory grew past 10 GB or frame time jumped.
Fix: Apply the palette on the GPU in the pixel shader. Cache textures by content.
Seen in: Vice City Stories Recomp, Renegade Squadron PC
Addresses were built for one region, so other discs glitched in game.
Fix: Pin one disc version. Give each region its own hash, generated code and address table.
Seen in: LCS Recomp, Tag Force Recomp, The Sims 2 PSP Recomp
The SNC compiler made different code without -g, and the splat linker script padded segments.
Fix: Find flags by test, including debug flags. Write your own linker script when splat's pads.
Seen in: Dissidia012-PC
Antivirus blocked the compiler or the new game.dll while the launcher built the game.
Fix: Tell players to allow the build folder. Check that downloads are whole by hash.
Seen in: The 3rd Birthday Recomp, God of War PSP
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 | 3 to 10 weeks | 2 to 6 months | 6 to 18 months | high confidence |
| Path B: full decomp | 6 to 18 months | 1 to 3 years | 5 to 10 years | low confidence |
Read this first
These numbers assume one medium game and one person giving 10 to 15 hours a week. Path A is fairly sure: four dated AI projects on this system took weeks, not months. But none says how many hours it took, and some hid earlier private work. Path B is a guess. No PSP game is fully decompiled, and the last part of a decomp is always the slowest. The no-AI numbers come from other systems, because no PSP recomp predates agents.
What makes it faster or slower
- Whether
PortableKitorPSPRecompalready covers most system calls your game uses. - How much code sits in overlays or extra modules.
- How much VFPU code and how many rare GE features the game uses.
- Your PC: the first full build can take hours and needs a lot of memory.
- For Path B: which compiler, how many functions, and how much is C++.
The facts behind these numbers
| Project | What happened | Link |
|---|---|---|
| Dissidia012-PC | Decomp setup dated 2026-10-10. Recompiled build reached the title screen on 2026-10-18. First release 2026-10-24. One person, with a lot of AI help, on PortableKit. | source |
| The 3rd Birthday Recomp | Two-weekend bake-off, work log dated 2026-09-26, first release 2026-10-23. Four contributors. README says much of the code was written with Claude. | source |
| Portable Ops Native | First commit 2026-10-17. First prerelease 2026-11-08. One contributor, with an AGENTS.md and a commit naming a Claude session. | source |
| Renegade Squadron PC | First commit 2026-10-03. First release 2026-10-18. One person with Codex and Claude. | source |
| Ape Escape Mind Over Monkey | First commit 2026-08-12, the same day PSPRecomp was created, so its history may include the framework. First release 2026-10-15. Developer notes Claude and Codex. | source |
| HST-Decomp | Created 2026-10-15. On 2026-11-10: 41.4% of code bytes and 68.9% of 19,634 functions matched. One person, tools plus AI agents. | source |
| mhp2g-decomp | Created 2026-01-28. 3.55% decompiled on decomp.dev on 2026-11-13. One contributor, CodeWarrior build 219. | source |
| God of War PSP | Its own feasibility study on 2026-10-15 guessed 6 to 12 months to a full game. Version 0.1.0 came out 2026-10-17, after earlier private work. | source |
Projects reviewed (17)
We took the top-starred project for each of the top 12 PSP games on RecompLauncher. We added two more that used AI. The catalog has no working PSP decomp, so three Path B projects come from outside it.
What each project teaches
sotn-decomp
Castlevania: Symphony of the Night (Dracula X Chronicles, PSP)
Started: 2021-12. First release: none. Code: C.
AI: none stated
Lesson: The furthest PSP matching decomp, at about 83% for the PSP version. It had a head start from the same game's PS1 decomp.
Yakumo
Monster Hunter Portable 3rd
Started: 2026-09. First release: 2026-09. Code: C++.
AI: yes: ships AGENTS.md and CLAUDE.md for coding agents; how much code AI wrote is not stated Agent files: AGENTS.md, CLAUDE.md.
Lesson: Bound every run and trace the hardware instead of recalling it. Its AGENTS.md rules are a strong model for any PSP port.
LCS Recomp
Grand Theft Auto: Liberty City Stories
Started: 2026-09. First release: 2026-09. Code: C++.
AI: none stated
Lesson: A file-based control channel lets a script drive the game and check movement with numbers. That is a test an agent can run alone.
God of War PSP
God of War: Chains of Olympus; God of War: Ghost of Sparta
Started: 2026-10. First release: 2026-10. Code: C and Python.
AI: yes: AGENTS.md, CLAUDE.md and .claude/ are kept local and git-ignored
Lesson: Test each recompiled function against an independent CPU model on random inputs. Make headless runs repeat frame for frame.
Ace Combat X Recompilation
Ace Combat X: Skies of Deception
Started: 2026-08. First release: 2026-08. Code: C and Python.
AI: yes: NOTICE.md says the Vulkan backend was written with substantial help from Claude
Lesson: Split the pipeline into steps you can rerun and check alone. Add a golden boot trace test early.
Dissidia012-PC
Dissidia 012 Duodecim Final Fantasy
Started: 2026-10. First release: 2026-10. Code: C++, C and Python.
AI: yes: CONTRIBUTING.md says it is built with a lot of AI help
Lesson: Pair a recomp with a matching decomp. Recompile everything to play, and use matched C only where a feature needs it.
MHForever
Monster Hunter Freedom Unite
Started: 2026-10. First release: 2026-10. Code: C++.
AI: yes: README says developed with AI assistance; docs refer to a local CLAUDE.md
Lesson: Test the runtime on your own small homebrew programs first. Then CI can test it with no game data.
Vice City Stories Recomp
Grand Theft Auto: Vice City Stories
Started: 2026-10. First release: 2026-10. Code: C++.
AI: none stated
Lesson: Set the generator to stop on any missing function. Gaps then show up when you generate, not when you play.
mhp2g-decomp
Monster Hunter Portable 2nd G
Started: 2026-01. First release: none. Code: C++.
AI: none stated
Lesson: A clean model of a PSP matching build: hash-pinned tools, one ninja command, and sha1sum -c as the final step.
The 3rd Birthday Recomp
The 3rd Birthday
Started: 2026-06. First release: 2026-10. Code: C and Python.
AI: yes: README says much of the code was written with Claude
Lesson: Run a short bake-off of frameworks on your own executable with fixed checks. Only one of three worked here.
Street Fighter Alpha 3 MAX
Street Fighter Alpha 3 MAX
Started: unknown. First release: 2026-11. Code: unknown.
AI: yes: the catalog flags AI use for code; the repo could not be read
Lesson: The repo returned 404 a week after its last release. Do not build on a project you cannot read.
Portable Ops Native
Metal Gear Solid: Portable Ops
Started: 2026-10. First release: 2026-11. Code: C++.
AI: yes: AGENTS.md and a commit naming a Claude session Agent files: AGENTS.md.
Lesson: Boot every stage headless with the interpreter off. Anything that stops is missing code.
Renegade Squadron PC
Star Wars Battlefront: Renegade Squadron
Started: 2026-10. First release: 2026-10. Code: C++ and Python.
AI: yes: README credits Codex for the first recomp and Claude for speed and rendering work
Lesson: Write renderer tests that need no game files. Say next to each claim what was not proven.
Tag Force Recomp
Yu-Gi-Oh! GX Tag Force
Started: 2026-10. First release: 2026-10. Code: C++ and Python.
AI: yes: AGENTS.md and CLAUDE.md are listed as local-only in .gitignore
Lesson: Replace generated functions one by one with readable C++ and run both from the same state to compare. That turns a recomp into a decomp.
Ape Escape Mind Over Monkey
Saru Get You: Saru Saru Daisakusen
Started: 2026-08. First release: 2026-10. Code: C++.
AI: yes: developer note says Claude and Codex for coding
Lesson: Bind a system call only when its behaviour is known. Let every other call stop the run, so gaps are reported, not faked.
The Sims 2 PSP Recomp
The Sims 2
Started: 2026-11. First release: 2026-11. Code: C++.
AI: yes: developer note says AI helped with code, tests and docs
Lesson: Wrap the whole flow in one command that checks the disc, builds and runs a startup check. Log what each release did not test.
hst-decomp
Hot Shots Tennis: Get a Grip
Started: 2026-10. First release: none. Code: C and C++.
AI: yes: README says AI agents work on functions the tools cannot match Agent files: AGENTS.md.
Lesson: Tools first, agents on the rest, and one strict match checker as the only verdict. It reached 41% of code in about four weeks.
What we could not check
- How many hours a week any dated project spent. The time ranges assume 10 to 15.
- Earlier private history of Tag Force Recomp, God of War PSP, MHForever, Yakumo and Sims 2. Their first public commit may not be their start.
- Whether HST-Decomp's pace holds past 41%. No PSP game is fully decompiled.
- What Street Fighter Alpha 3 MAX was. Its repo returned 404.
- The current Vulkan SDK version. The LunarG page did not show it.
- PSP RAM and VRAM sizes. They were seen only in search snippets, so they are left out.
- Whether
PortableKitbuilds a full port on Windows for a new game. Its CI tests the framework on Windows; Yakumo runs on Windows. - Whether the
<PREFIX>_STRICT_HLEand<PREFIX>_LIST_STUBSswitches work the same inPSPRecomp. They come from thePortableKitdocs. - Stars for the three outside projects come from GitHub on 2026-11-13, not from the catalog.
- No command in this guide was run here. Each was checked against live docs or the review cards only.
- How to get SDL3 and FFmpeg for a
PortableKitport on Windows. Its README gives install steps for macOS only. - Whether a plain
timeoutworks in Git Bash on Windows. Lettools/boot_check.pyenforce the time limit itself. - Whether stock
binutils-mipsel-linux-gnuaccepts-march=allegrex. The reviewed decomps useallegrex-asor a patchedpspasinstead. - That
ghidra-allegrexandGhidraMCPwork together in one Ghidra 12.1.4 install. Both READMEs were read, but the pair was not run. PSPRECOMP_INTERPRETER_VERBOSEcomes from the Dissidia012-PC card only. The PortableKit docs do not list it.- A third PSP framework, Nakagawa Recomp by the HST-Decomp author, exists but was not reviewed for this guide.
Sources
- PortableKit README
- PortableKit: Bringing up a new game
- PortableKit: Building
- PortableKit: Writing a profile
- PortableKit Ghidra export script
- PSPRecomp profile guide
- PSPRecomp README
- AljandrOrtega PSP recompilation toolkit
- PPSSPP downloads
- PPSSPP docs: Allegrex overview
- PPSSPP docs: the GE
- PSP RE quick start guide
- ghidra-allegrex README
- ghidra-allegrex releases
- Ghidra 12.1.4 release
- GhidraMCP release 2.0
- Ghidra README
- pspdecrypt README
- splat README
- splat Quickstart
- spimdisasm README
- m2c README
- objdiff README
- wibo README
- mwccgap README
- decomp.me compiler kits
- decomp.me compilers release
- sotn-decomp Makefile (allegrex-as download)
- sotn-decomp release with allegrex-as
- Dissidia012-PC WSL setup script
- HST-Decomp project guide (setup in WSL)
- Install WSL (Microsoft Learn)
- Snowboard Kids 2 decomp: Claude Code hooks
- One-shot decompilation with Claude (Snowboard Kids 2)
- GhidraMCP README
- HST-Decomp README and AGENTS.md
- mhp2g-decomp configure.py
- mhp2g-decomp progress on decomp.dev
- sotn-decomp README
- sotn-decomp PSP progress on decomp.dev
- Tag Force 5 decomp README
- MHFU non-matching decomp README
- Yakumo AGENTS.md
- God of War PSP feasibility study
- Dissidia012-PC decomp getting started
- skills.sh: matching-decomp skill