Skip to the page
It's Decomplicated
Nintendo, 2004

Nintendo DS decomp guide

Two ARM chips, shared code slots and new tools. Agent-helped teams matched whole DS games in months.

What this system is like

The DS has two ARM chips. The big one runs the game. The small one runs sound, touch and wireless. Most games load extra code into the same memory slots at different times. These swappable code blocks are called overlays. Overlays are the main trap on this system.

Tools for the DS got much better in 2024 with dsd. It reads a game file and lists every function, its size and its mode. That list is what both paths need. In 2026 many DS projects used Claude Code. Some shipped a playable PC build within weeks.

Path A turns the machine code into C with a recompiler. A recompiler is a tool that writes C that does the same thing as the machine code. You then write a runtime that stands in for the DS. Path B rebuilds the game as C that compiles back to the exact same bytes. Three DS games reached about 100% that way in 2026. At least two of them say agents helped.

The hard parts are plain. The original compiler, mwccarm, is not free to share, so you must supply it. Byte-exact C still needs real work before it runs on a 64-bit PC. Most steps run on Windows. A few test scripts need WSL, a Linux system inside Windows.

Two CPUs, one game

The ARM9 runs the game and the ARM7 runs sound, touch and wireless. They talk through a small message queue. Most projects recompile the ARM9 first. Some copy the ARM7 too, and some fake its jobs in the runtime.

Overlays share addresses

A game swaps code blocks in and out of the same memory slots. So one address can mean many functions. Every reviewed recomp and port had to handle this. Most compare the bytes in memory with each overlay before they run code there.

`dsd` maps the game for you

dsd init finds every function, its size and its ARM or Thumb mode. It also finds which overlay each call points to. That map feeds both a recompiler and a matching decomp.

The compiler is not free

DS games were built with Metrowerks mwccarm. Nobody may share it in a repo. You must supply your own copy for Path B. It runs on Windows as is, and on Linux through Wine or wibo.

SDK threads need special care

NitroSDK switches threads by saving and loading CPU state. Plain C cannot do that. Recomp projects swap those SDK calls for coroutines. A coroutine is a function that can pause and resume later.

Byte-exact C is not PC-ready C

Matched DS code assumes 4-byte pointers, signed char and ARM leftovers in registers. Ports built 32-bit first, then fixed pointers one by one. Expect that work after Path B.

Two paths

Path A

Get it running on PC

You map the game with dsd. A recompiler script turns each game function into one C function. You write a runtime in C that stands in for the DS: memory, timers, 2D, 3D, sound and input. Then you fix one crash or one wrong picture at a time. Six of the 13 reviewed projects took this road.

Go to the steps

Path B

Full decomp for porting

You split the game with dsd, then write C that mwccarm compiles back to the exact bytes. objdiff scores each function. dsd check modules checks the whole program. Three DS games reached about 100% this way in 2026, at least two with stated agent help. A port then compiles the same C for PC with a layer that stands in for the SDK.

Go to the steps

Path A: Get it running on PC

You map the game with dsd. A recompiler script turns each game function into one C function. You write a runtime in C that stands in for the DS: memory, timers, 2D, 3D, sound and input. Then you fix one crash or one wrong picture at a time. Six of the 13 reviewed projects took this road.

Method: static recompilation

Pick this when you want to play on PC soon and no matching decomp exists. If a finished decomp exists, port it instead, like KH Days Port and Eidos did.

  1. Scope the game and look for prior work

    You pick one game, one region and one exact file hash. Then you check what already exists. A decomp, a symbol list or a sister game can save months.

    • Hash your own dump in WSL: sha1sum game.nds.
    • Search for your game on decomp.wiki, pret.github.io and GitHub. Note any decomp, symbol file or recomp.
    • Check if another region is done. In DQIX Modern, the EU main code sits 0x10 bytes after the USA code. A small script converts the addresses.
    • Ask Claude for a draft SCOPE.md with the prompt below. Edit it yourself and approve it.
    Prompt for Claude
    GOAL: Write a draft `SCOPE.md` for a PC build of <GAME> (<REGION>, SHA-1 <HASH>) by static recompilation.
    READ FIRST: `notes/prior-work.md` (my search notes), https://decomp.wiki/platforms/nintendo-ds
    FENCE: Create only `SCOPE.md`. Do not install, download or build anything.
    CHECK: Run `grep "^## " SCOPE.md`. Done means it prints these 7 headings: Goal, Game and hash, Technique, Prior work, Milestone 1 and its check, Out of scope, Never edit.
    BUDGET: 30 minutes.
    IF BLOCKED: Stop. List what you could not find out and why.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) The headings you filled. 3) Each claim about prior work with its URL. 4) Open questions for me.
    Done whengrep -c "^## " SCOPE.md prints 7, grep -q <HASH> SCOPE.md succeeds, and you approved the file.

    Proof this works: Dragon Quest IX Modern, Egg of Time, https://decomp.wiki/platforms/nintendo-ds

  2. Set up the repo and extract the game

    You make the repo, keep the game file outside it, and extract the code. You also write one check command. It starts small and grows with the project.

    • Install WSL once. In PowerShell as administrator, run wsl --install, then restart.
    • Install Python 3 and Git for Windows. Git for Windows also gives you Git Bash.
    • Download dsd-windows-x86_64.exe (v0.12.1) from the ds-decomp releases and save it as tools/dsd.exe.
    • Install Python helpers: pip install capstone ndspy.
    • Install build tools: python -m pip install "cmake>=3.21,<4" ninja. Unzip llvm-mingw-20261104-ucrt-x86_64.zip and add its bin folder to PATH. Unzip SDL3-devel-3.4.18-mingw.zip for the window and sound library.
    • Extract: tools/dsd.exe rom extract --rom <ROM_DIR>/game.nds --output-path extract.
    • Add extract/, gen/, build/, *.nds, bios/ and saves to .gitignore.
    • Write tools/check.py. For now it rebuilds and prints OK. Write CLAUDE.md, PROGRESS.md and notes/parking-lot.md.
    Prompt for Claude
    GOAL: Lay out the repo and one check command for the <GAME> recomp.
    READ FIRST: `SCOPE.md`, `CLAUDE.md`
    FENCE: Edit only `tools/check.py`, `CMakeLists.txt`, `.gitignore`, `PROGRESS.md`. The ROM at <ROM_DIR> and `extract/` are read-only. Do not add features I did not ask for.
    CHECK: Run `python tools/check.py`. Done means it exits 0 and prints OK, and `git status --ignored` shows `extract/` as ignored.
    BUDGET: Stop after 3 failed tries on the same error.
    IF BLOCKED: Stop. Do not work around it. Tell me what blocked you, 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 check output. 3) Files changed. 4) What is left.
    Done whenpython tools/check.py exits 0 on a clean clone, and git status --porcelain --ignored lists extract/ only as ignored (!!).

    Proof this works: Egg of Time, https://github.com/AetiasHax/ds-decomp

  3. Map every function with dsd

    You let dsd find every function, its size, its mode and its overlay. You name the SDK code so nobody works on it by hand. The result is your function ledger.

    • Run tools/dsd.exe init --rom-config extract/config.yaml --output-path config --build-path build.
    • If it stops on a strange call, add --allow-unknown-function-calls. Egg of Time and khdays-decomp both needed it.
    • Name known SDK functions: tools/dsd.exe sig apply --config-path config/arm9/config.yaml --all.
    • Have Claude turn every symbols.txt into ledger/functions.csv with address, size, mode, module and a status column.
    • Optional: load the ROM in Ghidra 11.2.1 with dsd-ghidra and run SyncDsd.java to see names in Ghidra.
    Prompt for Claude
    GOAL: Build `ledger/functions.csv` from the dsd config, one row per function.
    READ FIRST: `config/arm9/config.yaml`, the `symbols.txt` and `relocs.txt` files under `config/`, `SCOPE.md`
    FENCE: Edit only `tools/make_ledger.py` and `ledger/`. Everything under `config/` and `extract/` is read-only.
    CHECK: Run `python tools/make_ledger.py --verify && python tools/check.py`. Done means both exit 0, the CSV row count equals the function count in the `symbols.txt` files, and each row has address, size, mode (ARM or Thumb), module and status.
    BUDGET: Stop after 3 failed tries or 45 minutes with no progress.
    IF BLOCKED: Stop. Show the rows or files that do not fit and why.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the counts per module. 3) How many functions are SDK. 4) Files changed.
    Done whenpython tools/make_ledger.py --verify exits 0. That means the CSV row count equals the function count in the symbols.txt files. Every row has size, mode, module, status and an SDK flag.

    Proof this works: Egg of Time, DQIX Enhanced, https://github.com/AetiasHax/dsd-ghidra

  4. Build and test the recompiler

    You write a script that turns each game function into one C function. You test it alone before you run the game. A bad translation here causes crashes that are very hard to trace later.

    • Use one C shape for every function, like void f_<module>_<addr>(CPU *cpu), plus an address table for calls through pointers. This is the Egg of Time design.
    • Branches inside a function become goto. Known bl and blx calls become direct C calls.
    • Keep special cases in small text files: hooks.txt, hle.txt, interpret.txt, patches.txt. DQIX Enhanced works this way.
    • Test the decoder against LLVM on every instruction, as DQIX did with 0 disagreements.
    • Test behavior: compile small C functions to ARM and Thumb, recompile them, and compare with the native build on random inputs.
    • Run both tests in WSL. They need a Linux clang with an ARM target: sudo apt install clang llvm lld. DQIX Modern could not run them on its Windows PC.
    • Or start from the ndsrecomp framework, which Metroid Prime Hunters used. It is pre-alpha and noncommercial. By default it wants your own DS BIOS and firmware dumps.
    Prompt for Claude
    GOAL: Make `tools/recomp.py` translate module <MODULE> and pass the decoder and behavior tests.
    READ FIRST: `CLAUDE.md`, `config/arm9/<MODULE>/symbols.txt`, `tests/README.md`
    FENCE: Edit only `tools/recomp.py`, `tools/recomp/` and `tests/`. Never edit files in `gen/`; they are output. Do not change the test inputs to make them pass.
    CHECK: In WSL, run `python3 tests/decoder_vs_llvm.py <MODULE> && python3 tests/semantics.py 2000`. Done means 0 disagreements and 0 failures.
    BUDGET: Stop after 5 failed tries on one instruction class.
    IF BLOCKED: Stop. Name the instruction, the expected result and the real result.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste both test summaries. 3) Files changed. 4) Instruction classes still untested.
    Done whenThe decoder test shows 0 disagreements and the behavior test shows 0 failures for every module you translate.

    Proof this works: DQIX Enhanced, Egg of Time, MetroidPrimeHuntersRecomp, https://github.com/RetroPortingToolKit/ndsrecomp

  5. Boot to the first frame

    You write the runtime and link it with the generated C. The goal is one picture on screen. Keep it small: memory, interrupts, timers, the file system and 2D first.

    • Run the recompiler over the ARM9 program and all overlays into gen/. Build with CMake and Ninja.
    • Replace the SDK thread switch (OS_SaveContext, OS_LoadContext) with coroutines, one per game thread. Find it by byte signature. Egg of Time uses minicoro for this.
    • Before any call into an overlay slot, compare the bytes in memory with each overlay's bytes. Run the one that matches.
    • Fake the ARM7's jobs at a high level at first. Egg of Time ships this way.
    • Add debug switches early: scripted keys, timed screenshots and a write watch on one address.
    • Set the right reset values. A wrong POWCNT1 value swapped the two screens in Metroid Prime Hunters.
    Prompt for Claude
    GOAL: Boot <GAME> to its first visible frame with no person at the keys.
    READ FIRST: `SCOPE.md`, `CLAUDE.md`, `docs/runtime-plan.md`, GBATEK sections DS Memory Maps and DS Video (https://problemkaputt.de/gbatek.htm)
    FENCE: Edit only `runtime/` and `CMakeLists.txt`. Never edit `gen/`. Fix bad generated code in `tools/recomp.py` and regenerate. No stub may return a fake value: unknown functions must abort and print their DS address.
    CHECK: Run `python tools/check.py --golden boot`. Done means the build passes, the game runs 600 frames with no crash, and `out/boot_0600.png` is not blank.
    BUDGET: Stop after 5 failed tries on one crash, or 60 minutes with no new frame reached.
    IF BLOCKED: Stop. Paste the last log lines, the address and what you think is missing.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the check output and the screenshot path. 3) Files changed. 4) Stubs that still abort.
    Done whenpython tools/check.py --golden boot runs 600 frames without a crash and saves a non-blank screenshot.

    Proof this works: Egg of Time, DQIX Enhanced, MetroidPrimeHuntersRecomp

  6. Grind: one crash or one missing function at a time

    You play forward and fix one problem per session. Each fix needs proof from a log, a trace or a side-by-side run. Missing functions go back into the recompiler's input, never into the C output.

    • Log every call that misses the address table. Add those addresses to an entry list like faltan.txt and regenerate. DS Kart and Metroid Prime Hunters both did this.
    • Build a lockstep mode. It runs an interpreter and your C side by side and stops at the first difference. SoulSilver Recomp checked 16,000 frames this way.
    • Or compare against melonDS at fixed frame counts, as ndsrecomp does with its ndsref oracle.
    • Record each fix and each dead end in PROGRESS.md and notes/dead-ends.md.
    Prompt for Claude
    GOAL: Fix crash <BUG_ID>: <ONE_LINE_SYMPTOM>.
    READ FIRST: `CLAUDE.md`, `PROGRESS.md`, `notes/dead-ends.md`, `logs/<BUG_ID>.log`, `inputs/<BUG_ID>.input`
    FENCE: Edit only `runtime/`, `tools/recomp.py` and its entry lists. Never edit `gen/`. Do not add per-scene hacks or fake events.
    CHECK: Run `python tools/check.py --golden <ROUTE>`. Done means the route passes its last checkpoint and every older golden run still passes.
    BUDGET: Stop after 3 fixes that did not work, or 60 minutes with no new evidence.
    IF BLOCKED: Stop. Do not work around it. Give the first point where the runs differ and your best theory.
    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 line or trace. 3) Paste the check output. 4) Files changed. 5) New dead ends.
    Done whenThe route's golden run reaches its last checkpoint and all older golden runs still pass.

    Proof this works: SoulSilver Recomp, DS Kart Recompiled, MetroidPrimeHuntersRecomp

  7. Make graphics and sound match the DS

    You build the 2D engines, the 3D engine and the sound mixer. Keep a slow software version as the reference. Check each fast path against it and against melonDS.

    • Write a software 2D and 3D renderer first. KH Days Port kept its software engines as the reference for the GPU path.
    • Save reference frames and your own frames at the same frame number. Compare them with a script, not by eye. Metroid Prime Hunters used ndsref at fixed frame counts. KH Days Port used DeSmuME save states.
    • Hash sound output sample by sample on a fixed input.
    • Test fades, menus and screen changes in motion. SoulSilver Recomp broke these many times.
    • Run lockstep with widescreen off. Widescreen changes the game's own math.
    Prompt for Claude
    GOAL: Make scene <SCENE> draw the same as the reference frame `refs/<SCENE>_<N>.png`.
    READ FIRST: `CLAUDE.md`, `docs/graphics.md`, `refs/<SCENE>_<N>.png`, GBATEK section DS 3D Video
    FENCE: Edit only `runtime/gpu2d/`, `runtime/gpu3d/` and `tests/render/`. Reference images are read-only. Do not lower the compare limit.
    CHECK: Run `python tests/render/compare.py <SCENE> <N>`. Done means 0 differing pixels against the reference, and the other render tests still pass.
    BUDGET: Stop after 4 failed tries or 60 minutes with no fewer wrong pixels.
    IF BLOCKED: Stop. Show the diff image path and the register state you suspect.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Pixel count before and after. 3) Files changed. 4) Scenes still wrong.
    Done whenThe render compare script reports 0 differing pixels for the scene, and older render tests still pass.

    Proof this works: KH Days Port, SoulSilver Recomp, MetroidPrimeHuntersRecomp

  8. Harden and package

    You build a set of replayed runs so old fixes stay fixed. Then you package the build so it ships no game code. The game is rebuilt on the player's PC from their own dump.

    • Record input files from a save. Replay them and compare key frames with references. DQIX Modern expects a 0.00 difference on every region before a merge.
    • Make the runtime fully repeatable: fixed clock, fixed random seed, recorded input.
    • Ship the runtime, the recompiler and a pinned compiler. Build the game on first start from the hashed ROM, like Egg of Time and DS Kart.
    • Check that no ROM, gen/ output, BIOS or save is in the release zip.
    Prompt for Claude
    GOAL: Add a smoke test that replays <N> recorded routes and compares key frames.
    READ FIRST: `CLAUDE.md`, `tests/smoke/README.md`, `PROGRESS.md`
    FENCE: Edit only `tests/smoke/` and `tools/check.py`. Reference frames and saves stay outside the repo at <REF_DIR> and are read-only.
    CHECK: Run `python tools/check.py --smoke` on a clean clone. Done means every route reports difference 0.00.
    BUDGET: Stop after 3 failed tries on one route.
    IF BLOCKED: Stop. Name the route, the frame and the difference.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the smoke output. 3) Files changed. 4) Routes not covered.
    Done whenpython tools/check.py --smoke passes on a clean clone, and the release zip holds no game data.

    Proof this works: Dragon Quest IX Modern, Egg of Time, DS Kart Recompiled

Path B: Full decomp for porting

You split the game with dsd, then write C that mwccarm compiles back to the exact bytes. objdiff scores each function. dsd check modules checks the whole program. Three DS games reached about 100% this way in 2026, at least two with stated agent help. A port then compiles the same C for PC with a layer that stands in for the SDK.

Method: matching decompilation

Pick this when you want source code you can port to other systems. It also gives a port that is not tied to the DS chips. It takes months, even with agents.

  1. Scope the decomp and find the compiler versions

    You confirm no decomp of your game exists, and you learn which compiler versions it needs. One game can use several mwccarm versions. Getting this wrong wastes weeks.

    • Search decomp.wiki, pret.github.io and GitHub for your game and its sister games.
    • Read the version list of a similar decomp. aletheia uses six mwccarm versions and lists one per function. khdays-decomp uses mwccarm 3.0 build 139 for almost everything.
    • Check the project rules of any decomp you build on. pret does not accept AI-written code.
    • Write SCOPE.md with the game hash, the region and the compiler versions you expect.
    Prompt for Claude
    GOAL: Write a draft `SCOPE.md` for a matching decomp of <GAME> (<REGION>, SHA-1 <HASH>).
    READ FIRST: `notes/prior-work.md`, https://decomp.wiki/platforms/nintendo-ds
    FENCE: Create only `SCOPE.md`. Do not download or install anything.
    CHECK: Run `grep "^## " SCOPE.md`. Done means it prints these 7 headings: Goal, Game and hash, Compiler versions and how we will confirm them, Prior work with URLs, Milestone 1 and its check, Out of scope, Never edit.
    BUDGET: 30 minutes.
    IF BLOCKED: Stop. List 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) Each prior-work claim with its URL. 3) Open questions for me.
    Done whengrep -c "^## " SCOPE.md prints 7, grep -q <HASH> SCOPE.md succeeds, and you approved the file.

    Proof this works: https://github.com/Project-Holon/aletheia, pokeheartgold Single Screen, https://decomp.wiki/platforms/nintendo-ds

  2. Set up dsd, the compiler and the gate

    You extract, split and relink the game so it rebuilds byte for byte before any C exists. That proves your pipeline. The one check is dsd check modules.

    • tools/dsd.exe rom extract --rom <ROM_DIR>/game.nds --output-path extract
    • tools/dsd.exe init --rom-config extract/config.yaml --output-path config --build-path build --allow-unknown-function-calls
    • tools/dsd.exe delink --config-path config/arm9/config.yaml and tools/dsd.exe lcf --config-path config/arm9/config.yaml --lcf-file build/linker.lcf --objects-file build/objects.txt
    • Put your own mwccarm.exe and mwldarm.exe under tools/mwccarm/<VERSION>/. On Windows they run as is. In WSL use Wine or wibo.
    • Unzip xpack-arm-none-eabi-gcc-15.2.1-1.1-win32-x64.zip into tools/gcc-arm/, as aletheia does. It gives arm-none-eabi-as for library assembly.
    • Run pip install capstone pyelftools ndspy, the list khdays-decomp gives.
    • Write tools/configure.py to make build.ninja, like khdays-decomp does. Write tools/gate.sh: run ninja, then tools/dsd.exe check modules --config-path config/arm9/config.yaml -f. Run it in Git Bash.
    Prompt for Claude
    GOAL: Make `tools/gate.sh` rebuild every module byte for byte from the delinked objects.
    READ FIRST: `SCOPE.md`, `CLAUDE.md`, https://github.com/AetiasHax/ds-decomp (README commands)
    FENCE: Edit only `tools/configure.py`, `tools/gate.sh` and `.gitignore`. `extract/`, `config/` and `tools/mwccarm/` are read-only. Do not edit checksums.
    CHECK: Run `bash tools/gate.sh`. Done means `dsd check modules` passes every module with exit code 0.
    BUDGET: Stop after 3 failed tries on one module.
    IF BLOCKED: Stop. Paste the failing module and the first wrong offset.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the gate output. 3) Files changed.
    Done whenbash tools/gate.sh exits 0 and dsd check modules reports every module as matching.

    Proof this works: https://github.com/Yokimitsuro/khdays-decomp, https://github.com/AetiasHax/ds-decomp

  3. Map the code and mark the SDK

    You build the ledger and set the SDK aside. SDK code is the same across many games. Name it by signature so nobody decompiles it by hand.

    • tools/dsd.exe sig apply --config-path config/arm9/config.yaml --all names known SDK functions.
    • Compare SDK code with the matched NitroSDK in pret's pokediamond. khdays-decomp did this.
    • Make ledger/functions.csv: address, size, mode, module, SDK yes or no, status, owner.
    • Load the ROM in Ghidra 11.2.1 with dsd-ghidra. Do not auto-analyze. Run SyncDsd.java.
    • Set up objdiff with tools/dsd.exe objdiff --config-path config/arm9/config.yaml. It writes objdiff.json.
    • Write the assembly files once with tools/dsd.exe dis --config-path config/arm9/config.yaml --asm-path asm/. Workers read these, not the ROM.
    Prompt for Claude
    GOAL: Fill `ledger/functions.csv` and mark every SDK and library function.
    READ FIRST: `config/` (read-only), `SCOPE.md`, `CLAUDE.md`
    FENCE: Edit only `tools/make_ledger.py`, `ledger/` and `config/*/symbols.txt` name fields that `dsd sig apply` changed. Do not rename by guess.
    CHECK: Run `python tools/make_ledger.py && bash tools/gate.sh`. Done means the gate still passes and every row has a status and an SDK flag.
    BUDGET: Stop after 45 minutes with no progress.
    IF BLOCKED: Stop. List the ranges you could not classify.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Counts: game, SDK, library, unknown. 3) Paste the gate output. 4) Files changed.
    Done whenEvery function has a row with status and SDK flag, and bash tools/gate.sh still passes.

    Proof this works: https://github.com/Yokimitsuro/khdays-decomp, Egg of Time, https://github.com/AetiasHax/dsd-ghidra

  4. Match one small function end to end

    You prove the whole loop on one tiny function. Write C, compile it with the right mwccarm, link it, and pass the gate. This also tests that your check can fail.

    • Pick a small leaf function, one that calls nothing.
    • Get a first draft from m2c or Ghidra, then fix it by hand or with Claude.
    • Check the score with objdiff-cli diff -u <UNIT> -o - <FUNC>. It prints JSON, and match_percent must be 100.
    • Always pass -o. Without it, objdiff-cli diff opens an interactive screen that Claude cannot use.
    • Add the file to the build and run bash tools/gate.sh.
    • Break the file on purpose and confirm the gate fails. Then undo it.
    Prompt for Claude
    GOAL: Match function <FUNC> at <ADDR> in C and link it into the build.
    READ FIRST: `CLAUDE.md`, the `asm/` file that holds <FUNC>, `ledger/functions.csv` row for <ADDR>
    FENCE: Edit only `src/<MODULE>/<FUNC>.c` and the build file list. `asm/`, `config/` and the gate are read-only. No inline assembly.
    CHECK: Run `objdiff-cli diff -u <UNIT> -o - <FUNC>` then `bash tools/gate.sh`. Done means `match_percent` is 100 in the JSON and the gate passes. Then break the file once and show the gate fails.
    BUDGET: Stop after 8 attempts with no better score.
    IF BLOCKED: Stop. Paste the best score and the differing lines.
    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 failed-on-purpose output. 3) Files changed.
    Done whenThe function scores 100% in objdiff, the gate passes with it linked, and a broken copy makes the gate fail.

    Proof this works: https://github.com/encounter/objdiff, https://github.com/matt-kempster/m2c

  5. Run the bulk matching loop

    Workers match functions in packets of neighbors from one module. Each worker has its own git worktree and build folder. After each batch the lead rebuilds the whole game and checks every module.

    • Cut the ledger into packets of next-door functions from one module, as aletheia does.
    • Give each worker one packet and one worktree: git worktree add ../wt-<id> -b match/<id>.
    • Workers run objdiff-cli diff -u <UNIT> -o - <FUNC> per function and park near misses in src/pending/ with notes.
    • The lead merges one packet at a time and runs bash tools/gate.sh after each merge.
    • Bigger packets pay off. Three workers on big batches did about 323 bytes a minute in pokeheartgold Single Screen.
    Prompt for Claude
    GOAL: Match the open functions in packet <PACKET_ID> (<MODULE> <START>-<END>).
    READ FIRST: `CLAUDE.md`, `docs/compiler-notes.md`, `ledger/functions.csv` rows for the packet
    FENCE: Work only in worktree <WORKTREE_PATH> with build folder `build-<PACKET_ID>`. Edit only `src/<MODULE>/` files for addresses in the packet. Never edit `asm/`, `config/`, headers others own, or the gate. No inline assembly or register pins.
    CHECK: For each function run `objdiff-cli diff -u <UNIT> -o - <FUNC>`. Then run `bash tools/gate.sh`. Done means each claimed function shows `match_percent` 100 and the gate passes in your worktree.
    BUDGET: At most 6 attempts per function. Stop the packet after 3 hours.
    IF BLOCKED: Park the best attempt in `src/pending/` with a note on the differing lines. Move to the next function.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Table: function, result, attempts. 3) Paste the gate output. 4) Files changed.
    Done whenEvery claimed function scores 100%, and bash tools/gate.sh passes on the merged main branch.

    Proof this works: https://github.com/Project-Holon/aletheia, pokeheartgold Single Screen, https://github.com/tangosdev/sm64ds-decomp

  6. Work the hard tail

    Some functions resist. You hand them to the hard job type with all past attempts. You also keep a shared file of compiler habits.

    • Collect each near miss with its best attempt and its diff.
    • Try changing the order of local variables. mwccarm often gives registers in that order.
    • Look for a small helper the compiler folded inline.
    • Write each new compiler habit in docs/compiler-notes.md, not in one function's notes.
    • A few functions need an instruction C cannot make, like clz. khdays-decomp has two such game functions. Mark those as allowed assembly and count them apart.
    Prompt for Claude
    GOAL: Match hard function <FUNC> at <ADDR>, or prove what blocks it.
    READ FIRST: `CLAUDE.md`, `docs/compiler-notes.md`, `src/pending/<FUNC>.c`, `docs/notes/<FUNC>.txt`
    FENCE: Edit only `src/<MODULE>/<FUNC>.c`, `src/pending/<FUNC>.c` and `docs/notes/<FUNC>.txt`. No inline assembly, no `asm("")` barriers, no forced registers.
    CHECK: Run `objdiff-cli diff -u <UNIT> -o - <FUNC>` then `bash tools/gate.sh`. Done means `match_percent` is 100 and the gate passes.
    BUDGET: Stop after 10 attempts with no better score.
    IF BLOCKED: Stop. Name the exact differing instructions and which cause you think it is.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Best score and attempt count. 3) Any new compiler habit for `docs/compiler-notes.md`.
    Done whenThe function matches and the gate passes, or the notes name the exact blocking instructions.

    Proof this works: pokeheartgold Single Screen, https://github.com/Yokimitsuro/khdays-decomp

  7. Make the C readable and portable

    Matched C is often full of address names and copied structs. You name things, share structs in headers, and fix pointer types. Every change must keep the bytes the same.

    • Move each shared struct into one header. Keep a change only if the file still compiles to the same bytes.
    • Rename func_0201xxxx names from evidence such as strings, callers or SDK names.
    • Turn integer stand-ins for pointers into real pointer types. aletheia did this for its port.
    • Count only real C as progress. Count assembly apart, like khdays-decomp does.
    Prompt for Claude
    GOAL: Move struct <STRUCT> into `include/<HEADER>.h` and use it in all its files.
    READ FIRST: `CLAUDE.md`, `docs/naming.md`, the file list from `grep -rl <STRUCT_HINT> src/`
    FENCE: Edit only those files and `include/<HEADER>.h`. Do not change behavior. Do not touch files outside the list.
    CHECK: Run `bash tools/gate.sh`. Done means every module still matches byte for byte.
    BUDGET: Stop after 3 failed tries on one file.
    IF BLOCKED: Stop. Name the file and the field that breaks the match.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the gate output. 3) Files changed. 4) Files skipped and why.
    Done whenThe struct lives in one header, all users include it, and the gate still passes.

    Proof this works: https://github.com/Project-Holon/aletheia, https://github.com/Yokimitsuro/khdays-decomp

  8. Port the decomp to PC

    You compile the matched C for PC with a layer that stands in for the DS SDK and hardware. The decomp stays read-only and pinned. Build 32-bit first, then fix pointers for 64-bit.

    • Add the decomp as a pinned, read-only submodule. Port changes go in your port layer or a build-time source rewrite.
    • Write shims for NitroSDK and NitroSystem, one file per module. Unknown functions abort and print their DS address.
    • Build 32-bit first so structs keep DS layout. DQIV and early KH Days Port did this.
    • Fix DS habits: signed char, divide by zero returns 0, calls that pass too few arguments.
    • Use a read-only Ghidra script to record register values at bad calls. KH Days Port fixed those calls from that list.
    • Replay scripted input and compare key frames with a reference before you trust a fix. KH Days Port used DeSmuME save states as its reference.
    Prompt for Claude
    GOAL: Make the PC build reach <MILESTONE> (for example, the title menu) with golden run <ROUTE>.
    READ FIRST: `CLAUDE.md`, `docs/port-plan.md`, `PROGRESS.md`, `external/<DECOMP>/` (read-only)
    FENCE: Edit only `port/`, `sdk_shims/`, `stubs/` and `CMakeLists.txt`. Never edit `external/<DECOMP>/`. A stub must abort and print its DS address.
    CHECK: Run `python tools/check.py --golden <ROUTE>`. Done means the route reaches <MILESTONE>, its key frames match the reference, and all unit tests pass.
    BUDGET: Stop after 3 failed fixes on one crash, or 60 minutes with no new evidence.
    IF BLOCKED: Stop. If a fix needs a decomp change, say which file and why. Do not make it.
    OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
    REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Paste the check output. 3) Files changed. 4) Stubs still aborting.
    Done whenpython tools/check.py --golden <ROUTE> passes, and git -C external/<DECOMP> status --porcelain prints nothing.

    Proof this works: KH Days Port, Eidos, Pokémon Platinum PC Port, DQIV Recompiled

Tools you need

ToolWhat it doesHow to get itHow we know
dsd (ds-decomp)
Required both
Extracts a DS game, finds every function, splits it into objects and rebuilds it. It also checks built modules against the original.
Path A Path B
Download `dsd-windows-x86_64.exe` (or `dsd-linux-x86_64`) v0.12.1 from https://github.com/AetiasHax/ds-decomp/releases and put it in `tools/`.tool README and release v0.12.1 assets (read 2026-11-13); --allow-unknown-function-calls is a hidden init flag in cli/src/cmd/init.rs at v0.12.1; used by: Egg of Time, khdays-decomp, DQIX Enhanced
objdiff
Required both
Compares your compiled object with the original, function by function, and gives a match score. It supports DS ARM code.
Path B
Download `objdiff-windows-x86_64.exe` and `objdiff-cli-windows-x86_64.exe` (v3.8.3) from https://github.com/encounter/objdiff/releases. Make its config with `dsd objdiff`.tool README and release v3.8.3 assets (read 2026-11-13); objdiff-cli/src/cmd/diff.rs at v3.8.3 shows -u, the symbol argument, and that only -o gives one-shot JSON with match_percent; dsd README objdiff command; named in Egg of Time NOTES.md
mwccarm and mwldarm (Metrowerks CodeWarrior for DS)
Required Windows
The original C compiler and linker DS games were built with. Path B needs the exact version your game used.
Path B
Not downloadable here and must not be committed. Supply your own copy under `tools/mwccarm/<VERSION>/`.aletheia README (six versions, not included, runs natively on Windows, Wine on Linux) and khdays-decomp README and CONTRIBUTING.md (3.0 build 139) read 2026-11-13; decomp.wiki names MWCC for DS; used by: pokeheartgold Single Screen, khdays-decomp, aletheia
Ghidra
Helpful both
A free tool that shows machine code as rough C. Use it to read functions and data. dsd-ghidra needs version 11.2.1.
Path A Path B
Install a JDK 21, then unzip `ghidra_11.2.1_PUBLIC_20241105.zip` from the `Ghidra_11.2.1_build` release at https://github.com/NationalSecurityAgency/ghidra/releases. 12.2 is the newest release, but `dsd-ghidra` needs 11.2.1.release assets via gh api (read 2026-11-13); used by: Egg of Time (11.2.1 with JDK 21), KH Days Port (read-only ABI script)
dsd-ghidra
Helpful both
A Ghidra add-on that loads a DS game and copies dsd function names into Ghidra.
Path A Path B
Download `ghidra_11.2.1_PUBLIC_20260814_dsd-ghidra.zip` (v0.7.0). In Ghidra: File, Install Extensions, plus icon, pick the zip, restart. Run `SyncDsd.java`.tool README and release v0.7.0 asset (read 2026-11-13); used by: Egg of Time, which notes v0.7.0 embeds dsd 0.12.0
melonDS
Required both
An accurate DS emulator. Use it to play the original and see what right looks like. Use direct boot, which needs no BIOS files.
Path A Path B
Download `melonDS-1.1-windows-x86_64.zip` from https://github.com/melonDS-emu/melonDS/releases and unzip it.README (firmware boot needs a BIOS dump, direct boot does not) and release 1.1 assets (read 2026-11-13); used by: SoulSilver Recomp (as hardware core), ndsrecomp (melonDS-based ndsref oracle), DQIX Enhanced (ported its research)
ndsrecomp
Helpful both
A ready DS static recompiler and runtime framework. Its README calls it very early pre-alpha, with no turnkey game build. Its own code is under a noncommercial license. By default it wants your own BIOS and firmware dumps.
Path A
`git clone https://github.com/RetroPortingToolKit/ndsrecomp`, then `cmake -G Ninja -B recompiler/build recompiler` and `cmake --build recompiler/build`. A Windows zip of v0.6.11 is on the releases page.tool README (status, build commands, PolyForm Noncommercial, BIOS and FreeBIOS paths) and release v0.6.11 asset (read 2026-11-13); used by: MetroidPrimeHuntersRecomp; the catalog entry for SkyRecompiled also says it is built on ndsrecomp
Capstone
Helpful both
A disassembler library for Python. Homemade recompilers use it to decode ARM and Thumb instructions.
Path A
`pip install capstone`repo and PyPI page answer (2026-11-13); pip install capstone is in the Egg of Time card and the khdays-decomp CONTRIBUTING.md; used by: Egg of Time, khdays-decomp, ctw-native
ndspy
Helpful both
A Python library for DS file formats: ROM, NitroFS, archives and compression.
Path A Path B
`pip install ndspy`tool README (read 2026-11-13); used by: MetroidPrimeHuntersRecomp, khdays-decomp
CMake and Ninja
Required both
CMake writes the build plan and Ninja runs it fast. Most reviewed DS builds use both.
Path A Path B
`python -m pip install "cmake>=3.21,<4" ninja`install line from pokemon-fulldex CI; used by: Egg of Time, SoulSilver Recomp, Eidos, MetroidPrimeHuntersRecomp, khdays-decomp
llvm-mingw (clang for Windows)
Required Windows
A clang compiler that makes Windows programs. It builds the huge generated C much faster than some other compilers.
Path A Path B
Download `llvm-mingw-20261104-ucrt-x86_64.zip` from https://github.com/mstorsjo/llvm-mingw/releases, unzip it and add `bin` to PATH.release 20261104 assets via gh api (read 2026-11-13); used by: Egg of Time and DS Kart Recompiled, which both pinned the older 20261020
SDL3
Required both
A library for the window, input, sound and timing of your PC build.
Path A Path B
Let CMake fetch it (`FetchContent`), or download `SDL3-devel-3.4.18-mingw.zip` (for clang) or `SDL3-devel-3.4.18-VC.zip` (for MSVC) from https://github.com/libsdl-org/SDL/releases.release-3.4.18 assets via gh api (read 2026-11-13; 3.4.20 is newest); version 3.4.18 pinned by Egg of Time and Eidos
m2c
Helpful both
Turns assembly into a first draft of C. Its ARM support is new, so treat output as a rough start.
Path B
Add the line `m2c @ git+https://github.com/matt-kempster/m2c.git` to `requirements.txt`, then run `pip install -r requirements.txt`. Or clone the repo and run `python m2c.py`.tool README lists the arm platform, the mwcc compiler and the requirements line (read 2026-11-13); decomp.wiki DS page says ARM support is recent; no reviewed DS project names it
wibo
Helpful WSL/Linux
Runs 32-bit Windows compilers like mwccarm on Linux, faster than Wine. You only need it in WSL.
Path B
In WSL, download `wibo-i686` (1.2.0) from https://github.com/decompals/wibo/releases and run `chmod +x wibo-i686`.tool README and release 1.2.0 (read 2026-11-13); m2c README names it as a Wine stand-in
arm-none-eabi binutils (xPack arm-none-eabi-gcc)
Required both
The GNU assembler for ARM, arm-none-eabi-as. Path B uses it to build library code that was assembly in the original.
Path B
Download `xpack-arm-none-eabi-gcc-15.2.1-1.1-win32-x64.zip` from https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases and unzip it into `tools/gcc-arm/`, as the aletheia README says.aletheia README (xPack into tools/gcc-arm/), khdays-decomp README and CONTRIBUTING.md (arm-none-eabi-as), xPack release v15.2.1-1.1 assets via gh api (all read 2026-11-13)
WSL (Ubuntu)
Required Windows
A Linux system inside Windows. You need it for wibo, Wine and the recompiler tests that use Linux clang.
Path A Path B
In PowerShell as administrator, run `wsl --install`, then restart.Microsoft WSL install page shows wsl --install (read 2026-11-13); pret pokeheartgold INSTALL.md uses wsl --install -d Ubuntu from an administrator PowerShell
Python 3
Required both
Runs pip, the ledger scripts and most homemade recompilers. ndspy needs Python 3.8 or newer.
Path A Path B
Download the Windows installer from https://www.python.org/downloads/windows/ and run it. In WSL: `sudo apt install python3`, as the DS Kart Recompiled Linux steps do.download page answers (read 2026-11-13); ndspy README says Python 3.8 or newer; used by: every reviewed recomp (recomp.py, build.py, prepare.py)
Git for Windows
Required Windows
Git keeps your history and makes one worktree per worker. It also gives you Git Bash, which runs the bash tools/gate.sh scripts on Windows.
Path A Path B
Download the installer from https://gitforwindows.org/ and run it.gitforwindows.org page names Git BASH (read 2026-11-13); worktrees used by: Dragon Quest IX Modern (git worktree add)
clang, LLVM and lld (in WSL)
Helpful WSL/Linux
A Linux C compiler with an ARM target and the LLVM disassembler. The recompiler tests compile small C functions to ARM and check your decoder against LLVM.
Path A
In WSL: `sudo apt install clang llvm lld`Ubuntu noble package pages for clang, llvm and lld answer (2026-11-13); DQIX Enhanced lists clang, lld and LLVM; DQIX Modern says these tests run only on Linux; DS Kart Recompiled uses sudo apt install python3 clang libsdl2-dev
minicoro
Helpful both
A one-file C library for coroutines. Recomp runtimes use it to replace the NitroSDK thread switch, one coroutine per game thread.
Path A
Copy `minicoro.h` from https://github.com/edubart/minicoro into `runtime/`. In exactly one C file, write `#define MINICORO_IMPL` before `#include "minicoro.h"`.tool README usage section (read 2026-11-13); used by: Egg of Time (one coroutine per game thread)

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 (xavirodriguez)

skills.sh

The only vetted matching skill with DS notes. Use it with care. It was built around one DS project and names other agent tools, not Claude Code. Its helper scripts sit outside the skill folder, so copy the whole repo.

npx skills add xavirodriguez/skills --skill matching-decomp -a claude-code

matcher

skills.sh

A careful method for one function. Claude gathers proof first, tests one idea at a time, and calls fake matches not done. Install the other lemiur skills with it.

npx skills add lemiur/game-decompilation-skill-for-claude --skill matcher -a claude-code

orchestrator

skills.sh

Runs many matching workers, each in its own worktree with its own slice. Every merge must pass the byte check. That fits the DS packet loop.

npx skills add lemiur/game-decompilation-skill-for-claude --skill orchestrator -a claude-code

static-recomp-scope-plan

skills.sh

Makes you write down what correct means before Path A starts: the exact game hash, the scenes to test and the numbers to hit.

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

native-platform-porting

skills.sh

Guides the PC port in the last Path B step. It warns Claude not to hide a small emulator inside the port.

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

verification-before-completion

plugin

Claude may not say done without fresh proof. DQIX Modern's CLAUDE.md requires this skill before any done report.

Comes with the superpowers plugin. Check `/skills` first. Or: npx skills add obra/superpowers --skill verification-before-completion -a claude-code

handoff

skills.sh

Writes a short note so a fresh session can carry on. Tell it to save inside your repo, not the temp folder. Metroid Prime Hunters used handoff notes between sessions.

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

GhidraMCP

MCP server

Lets Claude ask Ghidra for code and names. No reviewed DS project said it used an MCP server. It needs a newer Ghidra than dsd-ghidra, so keep two installs.

Install `uv`. Install the GhidraMCP 2.0 plugin zip in Ghidra 12.1.4 and enable it under File, Configure, Developer. Then: claude mcp add ghidra -- uvx --from git+https://github.com/LaurieWired/GhidraMCP ghidra-mcp --ghidra-server http://127.0.0.1:8080/

ds-build-check (subagent)

write-your-own

A narrow checker that cannot change code. DQIX Modern used this shape for its build check.

Create `.claude/agents/ds-build-check.md`. It checks the ROM path, runs `python tools/check.py` (or `bash tools/gate.sh`), reads the exit code and the last log, and reports in your fixed format. It edits no tracked file and never commits.

ds-overlay-dispatch

write-your-own

Overlay mix-ups caused crashes in Metroid Prime Hunters, Eidos and KH Days Port. One short skill keeps every session on the same rule.

Create `.claude/skills/ds-overlay-dispatch/SKILL.md`. It explains your overlay table, how the runtime compares live bytes before a call, where dispatch misses are logged, and how to add an entry and regenerate.

Claude setup for this system

Path A: one crash, one missing function, or one wrong scene is one unit. Each unit has a golden run that must pass. Recompiler changes are one unit at a time, because every change regenerates all of gen/. Path B: one packet of next-door functions from one module is one unit. Its check is 100% in objdiff, then dsd check modules on the merged branch.

Which model and effort for each job

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

JobWhat it means on this systemMax 20x (now called Ultra)Max 5x (now called Max)
Plan the projectFind prior work: a decomp, symbol files, a sister region or game. Pick the technique and write SCOPE.md with the hash and the first milestone.Fable 5.2
effort high
One session. This choice shapes months of work.
Opus 5.5
effort high
Use Fable 5.2 for this one session if you have weekly room.
Set up the projectInstall dsd, the compiler and CMake. Write tools/check.py or tools/gate.sh, the ignore rules and CLAUDE.md.Opus 5.5
effort medium
Sonnet 5.5
effort medium
Study the game fileRun dsd init, name SDK code with dsd sig apply, build the ledger, and map the overlay table and data layouts.Opus 5.5
effort high
Opus 5.5
effort medium
Raise to high for function edges and data layouts. A mistake there spreads.
Bulk unitsPath B: match the easy functions in a packet. Path A: add missed entry points from the dispatch-miss log.Sonnet 5.5
effort medium
Haiku 5.5 for the plainest units.
Sonnet 5.5
effort medium
Fewer workers at once. Haiku 5.5 for the plainest units.
Hard unitsFunctions that failed bulk tries, compiler-version puzzles, and odd ARM and Thumb tricks such as a Thumb bl used as a long jump.Fable 5.2
effort high
Go to xhigh only after a failed try at high.
Opus 5.5
effort high
Send only the last few that still fail to Fable 5.2.
Build the runtimeWrite the DS stand-in: memory map, interrupts, timers, IPC between the two CPUs, 2D and 3D engines, sound, saves and touch input.Opus 5.5
effort high
Opus 5.5
effort medium
Raise to high for timing and graphics bugs.
Find a bugFind the first point where your build and the reference differ, using lockstep, write watches or melonDS screenshots. Prove the cause before any fix.Opus 5.5
effort high
After two failed tries with full evidence, move to Fable 5.2.
Opus 5.5
effort high
One bug at a time.
Check the workA fresh session reruns the gate or golden runs and reads the diff. It hunts for cheats: edited references, silent stubs, inline assembly or edits in gen/.Opus 5.5
effort medium
Always a new session, never the one that did the work.
Sonnet 5.5
effort high
Always a new session, never the one that did the work.
Keep the recordsUpdate PROGRESS.md, the ledger counts, notes/dead-ends.md and docs/compiler-notes.md.Haiku 5.5
effort medium
Haiku 5.5
effort medium

How many sessions at once

Max 20x (now called Ultra)

Path B: one lead and three or four workers, each in its own worktree and build folder on its own packet. Merge one packet at a time and run the full gate after each. Path A: one runtime session, one debug session on a different crash, and one verify session. Run only one session that changes the recompiler.

Max 5x (now called Max)

Path B: one lead and one or two workers on big packets, so slow full rebuilds do not eat the gain. Path A: one working session at a time, plus a short verify session after each fix.

Lines for this project's CLAUDE.md

Add to CLAUDE.md
- At the start of every session, read `SCOPE.md`, `PROGRESS.md` and `notes/dead-ends.md`. Only the owner edits `SCOPE.md`.
- Never edit files in `gen/`. They are output. Fix `tools/recomp.py` or its entry lists and regenerate.
- The Path A check is `python tools/check.py`. A speed-up that changes lockstep or a golden run is a bug.
- The Path B verdict is `bash tools/gate.sh`, which ends with `dsd check modules -f`. An `objdiff` score is evidence, not proof.
- `external/`, `asm/`, `config/`, `extract/`, reference images and checksum files are read-only.
- Never pick overlay code by address alone. Every call into an overlay slot goes through the live-byte check.
- A stub must abort and print its DS address. Never return a made-up value to get past a screen.
- No inline assembly, `asm("")` barriers or forced registers in matched C. Allowed assembly exceptions are listed in `docs/asm-exceptions.md`.
- Never commit ROMs, `extract/`, `gen/`, BIOS, firmware, saves or compiler binaries. Run `git status` before every commit.
- Never say a test ran if it did not. Paste the exact command and its real output.
- Run at most one gameplay test per change unless I ask for more. Builds and file checks are always fine.
- In a worktree, use absolute paths and your own `build-<id>` folder.
- Write every failed idea with what you measured in `notes/dead-ends.md`.
- Do not send AI-written code to pret or any project whose rules forbid it.

Keep the context small

  • Give Claude one packet or one crash per session, with addresses and file paths. Do not paste whole assembly files.
  • Use a subagent to read big logs or traces and report the first difference only.
  • Keep CLAUDE.md short. Point to docs/compiler-notes.md and docs/runtime-plan.md by topic.
  • Generated C is hundreds of megabytes. Tell Claude to search gen/ with grep, never to open it whole.
  • Clear the chat between units. The ledger and PROGRESS.md carry the state.

More prompts for this system

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

Scope and feasibility

Before any work, to decide if your DS game is a good target and which path fits.

Prompt for Claude
GOAL: Tell me if <GAME> (<REGION>, SHA-1 <HASH>) can be done, by which path, and what exists already.
READ FIRST: https://decomp.wiki/platforms/nintendo-ds, https://pret.github.io/, `notes/prior-work.md`
FENCE: Read and search only. Create only `notes/feasibility.md`. Do not download game files or tools.
CHECK: Run `grep "^## " notes/feasibility.md` and `git status --porcelain`. Done means only that file is new, and it has one heading for each of: prior decomps, prior recomps, sister games, likely `mwccarm` versions, ARM7 needs, online or wireless parts, and a yes or no for Path A and Path B.
BUDGET: 45 minutes.
IF BLOCKED: Stop. Say which question has no answer and what would answer it.
OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Your advice in three lines. 3) Every claim with its URL. 4) Risks.

A good answer: A short file with links for every claim, a clear pick of path, and named risks such as encrypted overlays or missing compiler versions.

Map the binary

After setup, to turn the dsd config into a ledger with overlay notes.

Prompt for Claude
GOAL: Write `docs/overlays.md` and fill the module column of `ledger/functions.csv`.
READ FIRST: `config/arm9/config.yaml`, `config/arm9/overlays/` (read-only), `extract/arm9_overlays/`
FENCE: Edit only `docs/overlays.md`, `ledger/functions.csv` and `tools/make_ledger.py`. Do not rename symbols.
CHECK: Run `python tools/make_ledger.py --verify`. Done means every overlay is listed with its load address and size, and overlays that share an address are grouped.
BUDGET: Stop after 45 minutes with no progress.
IF BLOCKED: Stop. List overlays you could not place.
OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Number of overlays and shared-address groups. 3) Paste the verify output.

A good answer: A table of overlays by address, with groups that share a slot marked, and the verify script passing.

Path A unit loop: one dispatch miss

During Path A, when the miss log shows code that the recompiler did not cover.

Prompt for Claude
GOAL: Clear the dispatch misses listed in `logs/dispatch_misses.log` for route <ROUTE>.
READ FIRST: `CLAUDE.md`, `logs/dispatch_misses.log`, `docs/overlays.md`
FENCE: Edit only the entry lists (`faltan.txt`, `faltan7.txt` or `config/*.toml`). Never edit `gen/`. Do not add addresses you cannot tie to a real call.
CHECK: Regenerate, rebuild, and run `python tools/check.py --golden <ROUTE>`. Done means the miss log is empty for that route and older golden runs still pass.
BUDGET: Stop after 3 regenerate rounds with no fewer misses.
IF BLOCKED: Stop. List the addresses that keep missing and which overlay they belong to.
OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Misses before and after. 3) Paste the check output. 4) Files changed.

A good answer: The miss count drops to zero for the route, with each added address tied to its overlay and caller.

Path B unit loop: one function

For each function in a packet, when you run workers by hand.

Prompt for Claude
GOAL: Match <FUNC> at <ADDR> in <MODULE>.
READ FIRST: `CLAUDE.md`, `docs/compiler-notes.md`, the `asm/` file that holds <FUNC>, two matched functions that call it or that it calls
FENCE: Edit only `src/<MODULE>/<FUNC>.c`. Make each attempt a new file in `scratch/<FUNC>/`. No inline assembly, no forced registers.
CHECK: Run `objdiff-cli diff -u <UNIT> -o - <FUNC>`. Done means `match_percent` is 100 in the JSON. Then run `bash tools/gate.sh`, which must pass.
BUDGET: At most 6 attempts. Change one thing per attempt.
IF BLOCKED: Stop. Keep the best attempt in `src/pending/` and note the differing lines.
OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Best score and attempt count. 3) Paste both outputs. 4) Files changed.

A good answer: DONE with a 100% score and a passing gate, or PARTIAL with the best attempt parked and the exact differing lines.

Batch dispatch

In the lead session, to hand out the next set of packets to workers.

Prompt for Claude
GOAL: Start <N> workers on the next <N> open packets.
READ FIRST: `CLAUDE.md`, `ledger/functions.csv`, `ledger/claims.csv`
FENCE: Edit only `ledger/claims.csv`. Each worker gets its own worktree at <WT_ROOT>/<PACKET_ID> and its own `build-<PACKET_ID>` folder. Do not give two workers the same module.
CHECK: Run `python tools/claims.py check`. Done means no two claims overlap, and each worker got the Path B unit card with its packet filled in.
BUDGET: Stop after 20 minutes of setup.
IF BLOCKED: Stop. Say which packet or worktree failed.
OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) Table: worker, packet, worktree path. 3) Paste the claims check.

A good answer: A table of workers and packets with no overlap, and a passing claims check.

Debug with evidence

When your build and melonDS or the interpreter disagree, and you do not know why.

Prompt for Claude
GOAL: Find the cause of <SYMPTOM> on route <ROUTE>. Do not fix it yet.
READ FIRST: `CLAUDE.md`, `notes/dead-ends.md`, `logs/<ROUTE>.log`
FENCE: Read code and run tools only. You may add logging under `runtime/debug/`. Do not change behavior.
CHECK: Run your lockstep or frame compare for <ROUTE>, for example `python tools/check.py --lockstep <ROUTE>`. Done means you name the first frame and address where the runs differ, with the log lines that prove it.
BUDGET: 60 minutes or 3 theories, whichever comes first.
IF BLOCKED: Stop. List the theories you ruled out and how.
OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
REPORT: 1) DONE, PARTIAL or BLOCKED. 2) First difference with frame, CPU and address. 3) The proven cause or the best theory. 4) A fix plan for me to approve.

A good answer: One named first difference with pasted log lines, a cause backed by that evidence, and a fix plan, but no fix yet.

Verify and hunt for cheating

After any worker says DONE. Always run it in a fresh session.

Prompt for Claude
GOAL: Check that the work on branch <BRANCH> is real.
READ FIRST: `CLAUDE.md`, `git diff main...<BRANCH>`
FENCE: Read and run checks only. Do not edit files.
CHECK: Rerun `bash tools/gate.sh` (Path B) or `python tools/check.py` (Path A) yourself. Search the diff for: edits in `gen/`, `asm/`, `config/` or checksum files; inline assembly; stubs that return fixed values; disabled tests; files outside the fence.
BUDGET: 30 minutes.
IF BLOCKED: Stop. Say what you could not check.
OTHER PROBLEMS: Write them in `notes/parking-lot.md`. Do not fix them.
REPORT: 1) PASS or FAIL. 2) Paste your own check output. 3) Each problem with file and line.

A good answer: PASS or FAIL backed by a fresh check run, with any cheat shown by file and line.

Status report

At the end of a day or a week, to see real progress.

Prompt for Claude
GOAL: Give me a status report from the ledger, not from memory.
READ FIRST: `ledger/functions.csv`, `PROGRESS.md`, `notes/parking-lot.md`
FENCE: Read only. Do not edit files.
CHECK: Run `python tools/make_ledger.py --summary` and the gate or golden runs. Use only their numbers.
BUDGET: 15 minutes.
IF BLOCKED: Stop. Say which number you could not get.
REPORT: 1) Matched or fixed counts per module. 2) Gate or golden run result pasted. 3) Open blockers. 4) Top three next units.

A good answer: Numbers from the tools, a pasted check result and a short next list. No padding.

Session handoff

Before you stop for the day or the context runs low.

Prompt for Claude
GOAL: Write what the next session needs into the repo files.
READ FIRST: `PROGRESS.md`, `notes/dead-ends.md`, `git status`, `git log -5`
FENCE: Edit only `PROGRESS.md` and `notes/dead-ends.md`. Do not change code.
CHECK: Run `git status --porcelain`. Done means only `PROGRESS.md` and `notes/dead-ends.md` changed, and `PROGRESS.md` has: branch and commit, what was done, last check output, open unit, exact next command, and blockers.
BUDGET: 10 minutes.
IF BLOCKED: Stop. Say what you could not record.
REPORT: 1) DONE or PARTIAL. 2) Paste the new `PROGRESS.md` section.

A good answer: A short section a fresh session can act on with no chat history.

Blocked or cannot deliver

When a unit has failed more than its budget, or Claude keeps saying it is almost done.

Prompt for Claude
GOAL: Give me a plain answer on <UNIT>: can it be done now, yes or no?
READ FIRST: `PROGRESS.md`, `notes/dead-ends.md`, the last three reports for <UNIT>
FENCE: Read only. Do not try another fix.
CHECK: Run `git status --porcelain`. Done means it prints nothing, and each statement points to a log, a diff or a check output.
BUDGET: 15 minutes.
IF BLOCKED: Say so. That is a valid answer.
REPORT: 1) BLOCKED or NOT BLOCKED. 2) What exactly cannot be done and why. 3) Two or three options, each with its cost. 4) What you need from me.

A good answer: A one-word verdict, the reason with proof, and options such as parking the function or adding an allowed exception.

Scope change request

When Claude needs to touch something outside its fence, such as the decomp or a shared header.

Prompt for Claude
GOAL: Ask me before you leave the fence for <UNIT>.
READ FIRST: `SCOPE.md`, `CLAUDE.md`
FENCE: Do not make the change. Write the request only.
CHECK: Run `git status --porcelain`. Done means it prints nothing, and the request names the file, the exact change, why the fence blocks the work, and how we will check it.
BUDGET: 10 minutes.
IF BLOCKED: Stop and tell me.
REPORT: 1) The file and change. 2) Why it is needed, with proof. 3) The risk. 4) The check that will prove it safe.

A good answer: A short request you can answer yes or no, with a check named for after the change.

Keep Claude on task

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

The detourThe rule to give Claude
Claude edits the generated C in gen/ to fix a crash fast.Never edit gen/. Fix the recompiler or its entry lists and regenerate. Block gen/ with a hook that exits with code 2.
Claude runs code by address alone and calls the wrong overlay.Every call into an overlay slot must pass the live-byte check. A miss goes to the log, not to a guess.
Claude adds a stub or a fake event so a screen gets past a hang.A stub must abort and print its DS address. Fix the real cause or report BLOCKED.
Claude spends hours on speed tests and benchmark sweeps nobody asked for.No performance runs unless the task card asks. A speed-up that breaks lockstep is a bug.
Claude edits the matched decomp to make the PC port compile.The decomp is read-only. Port changes go in the port layer. A needed decomp change is a scope change request.
Claude forces a match with inline assembly or forced registers.No inline assembly, asm("") or register pins. Park the near miss in src/pending/ with notes.
Claude writes a pass file or says a test ran when it did not.No proof means not done. Paste the real command and output. Gate files written by hand count as cheating.

Problems other projects hit

Overlays share addresses. Code picked by address alone ran the wrong overlay and crashed.

Fix: Compare live bytes with each overlay's bytes before a call. Keep each overlay as its own bank or section.

Seen in: MetroidPrimeHuntersRecomp, Eidos, KH Days Port, Egg of Time, DQIX Enhanced

Function search missed code. Bridge functions reached only by pointer, or Thumb code mistaken for ARM, broke the build.

Fix: Keep a plain entry list fed back to the recompiler. Fix wrong modes in symbols.txt by hand and note it.

Seen in: DS Kart Recompiled, Egg of Time

The SDK thread switch saves and loads CPU state. Plain C calls cannot do that.

Fix: Find those SDK routines by byte signature and replace them with coroutines, one per game thread.

Seen in: Egg of Time, DQIX Enhanced, DS Kart Recompiled

Some code is encrypted in the ROM or leaks memory as anti-piracy. It hung or could not be recompiled.

Fix: Run encrypted functions in an interpreter. Patch the one bad call at recompile time without changing the ROM.

Seen in: DQIX Enhanced

Byte-matched C broke on PC: too few arguments, divide by zero, unsigned char, and a different order of side effects.

Fix: Build 32-bit first. Record register values with a read-only Ghidra script. Keep char signed and add a safe divide.

Seen in: KH Days Port, Eidos

Game data holds 32-bit pointers, so a 64-bit build crashed or read wrong fields.

Fix: Ship 32-bit first, or turn pointers into 4-byte DS addresses in a mapped window. Track the 64-bit work with a count.

Seen in: DQIV Recompiled, Eidos, KH Days Port

Generated code is huge. Builds took 20 to 30 minutes and about 1.5 GB of memory per job.

Fix: Build generated C at -O1. Use clang from llvm-mingw on Windows. Raise the stack size at link time if needed.

Seen in: SoulSilver Recomp, Egg of Time, DS Kart Recompiled

One function matched in objdiff, but the full link still failed or shifted data.

Fix: Run the whole-game gate after every batch, not just the per-function score.

Seen in: pokeheartgold Single Screen

Tool versions clashed. dsd-ghidra needs Ghidra 11.2.1, and Ghidra 11.2.1 could not load scripts built by Java 25.

Fix: Pin each tool version in SCOPE.md. Use JDK 21 for Ghidra 11.2.1, as Egg of Time did.

Seen in: Egg of Time

The pokeheartgold Single Screen install notes say mwldarm could not find its own program under WSL2. Upstream pret no longer warns about this.

Fix: Run the link on Windows, or use WSL1 or MSYS2 if WSL2 fails for you.

Seen in: pokeheartgold Single Screen

On Windows, mwccarm stopped with a license-file error.

Fix: Set the LM_LICENSE_FILE variable to license.dat, or run mwccarm.exe as Administrator.

Seen in: pokeheartgold Single Screen

How long it takes

Max 20x (now called Ultra)Max 5x (now called Max)One person, no AIHow sure
Path A: running on PC4 to 12 weeks10 to 30 weeks9 to 24 monthslow confidence
Path B: full decomp3 to 9 months7 months to 2 years5 to 10 yearslow confidence

Read this first

These numbers assume one medium-sized game and one person giving 10 to 15 hours a week. Confidence is low. The Max 20x ranges come from dated AI-assisted DS projects. Those teams had 1 to 25 people, were skilled, and often hid work done before their first public commit. No project reports hours worked. Your pace will likely be slower. No reviewed DS recomp is older than 2026, so the no-AI Path A range comes from PS1 and N64 projects. The no-AI Path B range comes from pret, which had many helpers and is still not done.

What makes it faster or slower

  • Whether a decomp or symbol list already exists. With one, Path A can start from known function edges.
  • How many overlays and functions the game has. Games in this guide range from about 9,000 functions (Chrono Trigger) to 35,197 (Pokemon Black).
  • How much the game uses 3D, wireless or the ARM7. Each adds runtime work.
  • How many mwccarm versions the game mixes, and whether you can get each one.
  • How strong your check is. Lockstep and frame compares save weeks of guessing.

The facts behind these numbers

ProjectWhat happenedLink
MetroidPrimeHuntersRecompFirst commit 2026-08-01, first release 2026-08-25, built on ndsrecomp (repo from 2026-07-15). 2 contributors. Agent handoff files in the repo.source
DQIX EnhancedFirst commit 2026-10-12, first release 2026-10-18. Later ran the whole game: 14,815 ARM9 and 962 ARM7 functions. Developer flagged AI use.source
EidosPort of the aletheia decomp. First commit 2026-09-16, first release 2026-10-23. 4 contributors. Parallel agent waves.source
KH Days PortFirst commit 2026-07-12, first release 2026-10-16. 5 contributors. Says AI tools helped.source
aletheia (Pokemon Black decomp)Repo created 2026-09-13. On 2026-11-13 its README says 100% matched, 35,197 functions, and that Claude Code assists development. 2 contributors.source
khdays-decompRepo created 2026-06-26. On 2026-11-13: 23,231 of about 23,233 functions complete (23,125 in real C) and 306 of 306 modules byte-identical. 3 contributors.source
sm64ds-decompRepo created 2026-06-14. On 2026-11-13: 11,389 of 11,389 functions matched. 25 contributors working with agent fleets.source
pret/pokediamondStarted 2020-04 with no agents. Still marked work in progress in 2026 with 37 contributors.source
pret/pokeheartgoldStarted 2021-06 with no agents. Still a work in progress in 2026 with 48 contributors.source

Projects reviewed (13)

The top-starred project for each of the top 12 DS games on RecompLauncher, plus one more project whose developer says AI was used. RecompLauncher lists 24 DS projects for 20 games.

What each project teaches

pokemon-fulldex

Pokémon DS games (catalog lists Pokemon FireRed)

Top rated on RecompLauncheremulator-basedin progress
melonDS core with JITSSR recomp.py (inherited)CMakeSDL2

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

AI: yes: README says built with AI help

Lesson: A recompiler is not always faster. This fork found melonDS's JIT ran its layouts about 1.7 times faster, so it ships the emulator core.

MetroidPrimeHuntersRecomp

Metroid Prime Hunters

Top rated on RecompLauncherstatic recompplayable
ndsrecompndspyCMakeNinjaMinGW GCCSDL3

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

AI: yes: AGENTS.md and agent handoff notes in the repo Agent files: AGENTS.md.

Lesson: Run scripted routes, record the code that fell back to the interpreter, and feed those addresses back in. Function count grew from 4,335 to 7,115 this way.

KH Days Port

Kingdom Hearts 358/2 Days

Top rated on RecompLauncherport of a decompplayable
khdays-decompprepare.pyMSVCCMakeNinjaSDL3

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

AI: yes: README says AI coding tools helped

Lesson: Keep the decomp read-only and change it only at build time with a script. A read-only Ghidra scan fixed calls that only worked by ARM luck.

Pokémon Platinum PC Port

Pokemon Platinum

Top rated on RecompLauncherport of a decompplayable
pret/pokeplatinumlibntrMesonNinjametroskrew

Started: 2022-11. First release: 2026-07. Code: C.

AI: none: README says no AI was used and AI pull requests are rejected Agent files: AGENTS.md.

Lesson: Replace the SDK, not the game code. One source tree builds both the original ROM and the PC game, and the ROM check stays in CI.

SoulSilver Recomp

Pokémon SoulSilver

Top rated on RecompLauncherstatic recompstalled
recomp.pymelonDS 1.1 coreCMakeNinjaSDL2

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

AI: yes: README says nearly all code was written by Claude through Claude Code Agent files: AGENTS.md, CLAUDE.md.

Lesson: Build a lockstep mode early. Run the interpreter and your C side by side and stop at the first difference.

Egg of Time

Chrono Trigger

Top rated on RecompLauncherstatic recompplayable
dsdrecomp.pyCapstonellvm-mingw clangCMakeSDL3

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

AI: yes: README says Claude through Claude Code did the analysis and wrote the recompiler and runtime

Lesson: Start from dsd. It gives every function's size, mode and overlay target, so you do not write function search yourself.

Eidos

Pokemon Black / Pokemon White

Top rated on RecompLauncherport of a decompplayable
aletheiaCMakeNinjaGCCClangMSVC

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

AI: not stated; repo shows parallel agent waves and path claims

Lesson: Give each parallel worker a path claim and its own build folder. End every wave with a measured row in a log.

pokeheartgold Single Screen

Pokémon HeartGold

Top rated on RecompLaunchermatching decompin progress
mwccarm 2.0Nitro SDK toolsGNU Makearm-none-eabi binutilsWine

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

AI: yes: README says nearly all changes were written by Claude through Claude Code

Lesson: Rebuild the whole ROM and compare its hash after every batch. Per-function checks missed link errors.

DQIX Enhanced

Dragon Quest IX

Top rated on RecompLauncherstatic recompplayable
recomp/build.pyrecomp/arm7.pyMSYS2 GCCGNU MakeSDL2OpenGL

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

AI: yes: developer flagged AI use for code in the catalog

Lesson: Test the recompiler alone first: decoder against LLVM, then small functions on random inputs. Then run the game.

ctw-native

Grand Theft Auto: Chinatown Wars

Top rated on RecompLauncherreimplementationin progress
CapstonepyelftoolsMinGW GCCCMakeSDL2

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

AI: yes: CONTRIBUTING.md allows AI help; AGENTS.md gives agent rules Agent files: AGENTS.md.

Lesson: If the game also came out on phones, the phone build may be easier to study. This project uses the Android build, not the DS ROM.

DQIV Recompiled

Dragon Quest IV: Chapters of the Chosen

Top rated on RecompLauncherport of a decompplayable
MSVCCMakeSDL3OpenGL

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

AI: none stated

Lesson: Despite its name it ports a decomp. It builds 32-bit on purpose, because the game data holds 32-bit pointers.

DS Kart Recompiled

Mario Kart DS

Top rated on RecompLauncherstatic recompplayable
recomp.pynds_rom.pyclangOpenGLDear ImGui

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

AI: yes: README says Claude co-wrote most of the code

Lesson: A DS recompiler can be one Python script. Both CPUs and every overlay are translated, and missed entries go in a plain text list.

Dragon Quest IX Modern

Dragon Quest IX: Sentinels of the Starry Skies

Added: developer used AIstatic recompin progress
recomp (from DQIX Enhanced)MSYS2 GCCGNU MakeSDL2OpenGL

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

AI: yes: developer says Claude helped write the recompiler, runtime and translations Agent files: CLAUDE.md, .claude/agents/dqix-build-check.md.

Lesson: Several Claude sessions can work at once if each has a role, a branch, a worktree and a list of files it owns.

What we could not check

  • The dates when sm64ds-decomp, khdays-decomp and aletheia reached 100% were not found. Only their state on 2026-11-13 was read.
  • Whether khdays-decomp used Claude. Only an indirect sign was seen: a .claude memory link in its CONTRIBUTING.md. The aletheia README does say Claude Code helps.
  • How much work DS Kart Recompiled, SoulSilver Recomp and Egg of Time did before their first public commit.
  • Whether m2c reads the assembly that dsd dis writes. The m2c README expects GNU as format, and the dsd README says dis targets no assembler. The -t arm-mwcc-c pairing was not tested.
  • The list of DS compilers on decomp.me. Its API did not answer a plain download.
  • Nothing in this guide was installed or run on this machine. Commands were checked against READMEs, release pages and source code only.
  • The objdiff-cli diff -u <UNIT> -o - <FUNC> form was read from the v3.8.3 source, not run.
  • Whether dsd, objdiff and the Windows compilers work the same inside WSL2 as on Windows.
  • Whether the WSL2 problem with mwldarm still happens. Only the pokeheartgold Single Screen INSTALL.md reports it. Upstream pret recommends WSL2.
  • How to save a melonDS frame at an exact frame number. No card shows it. The reviewed projects used ndsref, DeSmuME save states or their own interpreter.
  • Whether llvm-mingw clang on Windows can build the ARM test functions. DQIX Modern ran those tests only on Linux.
  • Whether dsd rom extract needs the ARM7 BIOS for some games. Its README lists --arm7-bios for decryption. Egg of Time extracted without it.
  • Where you can legally get mwccarm. This guide only says you must supply your own copy.
  • The tools/check.py, tools/gate.sh, tools/make_ledger.py and tools/claims.py scripts in the steps are ones you write. Their names follow the reviewed projects, but they are not ready-made tools.
  • The time ranges for one person at 10 to 15 hours a week are estimates. No reviewed project reports hours worked.

Sources