Vault

emu-harness — drive emulators from Python (backends × machines)

One harness, two independent plug-in axes: backends (one emulator each: Mesen 2, BizHawk) and machines (one console each: NES). Lockstep inputs, frame advance, savestates, RAM reads and per-frame traces, for replay verification, search and testing. Game adapters live in each game’s repo. A peer of koei/ for the same reason: it spans consoles, so it is not filed under one.

Links: design + decisions → The AI Zelda speedrun harness · system → NES · series hub → Game Annotation · project SDK → projects/CLAUDE.md

Field Value
Logical name emu-harness (public) · github.com/chrisaacson69/emu-harness
Sibling path ../emu-harness (resolved via .claude/local-paths.md)
Entry point CLAUDE.md (layout, import rules, day-one rules)
Stack Python 3.14 + Lua inside each emulator
Depended on by game adapters in each game’s own repo (Zelda first, as the oracle: Zelda1-decompiler; mappy-decompiler, the first title through all nine phases)

Layout: emu_harness/backends/{mesen,bizhawk} · emu_harness/machines/nes · tools/ (replay, trace diff) · spike/<backend>/. Which backend runs which machine is configuration, not structure.

History: began 2026-10-01 as two repos stacked emulator-at-the-bottom, mesen-harness (core) → nes-harness (console). Merged 2026-10-02 when BizHawk became a second backend and turned emulator and machine into orthogonal axes (“Decision 2” on the design page). mesen-harness was renamed (GitHub redirects); nes-harness is archived with its history imported.

Status (2026-10-02): Mesen backend works headless (--testRunner, lockstep, savestates, per-frame RAM trace; Zelda Rev 1 smoke test deterministic). BizHawk has a .bk2 RAM-trace script only, the reference for cross-emulator drift; replay_log --offset -1 aligns against BizHawk movies (run 6). Known debt: machines/nes still subclasses the Mesen backend, to be split when BizHawk gets a Python client.

Status (2026-10-22): becoming the console-RE toolset. The NES/SNES decompiler tools (koei-nes, koei-snes, snes-decompiler, nes-render, per-title copies) fold in as plugins, REA-style. The repo’s MIGRATION.md holds the audit (339 files; jobs done up to 7 times) and the move order. Step 0 is done: an installable package (pip install -e, py -3.14) whose layer rules are import contracts run in pytest. nes-render, folded in as machines/nes/ppu (row O), was archived 2026-10-26. Rows A, A2, D, B and the generic half of E are done (2026-10-23): one .mlb exporter, one native-floor tool, and one shared 6502 recursive descent. A CPU-log benchmark measured every disassembler, and nes-disasm6 is now a plugin.

Next machines (planned 2026-10-27): 2600, Intellivision (first non-6502 CPU), Atari 800 → Taking emu-harness to the other three.

Tags

nes · python · tools · game-ai