diff --git a/docs/superpowers/specs/2026-07-07-ghidra-mcp-native-re-design.md b/docs/superpowers/specs/2026-07-07-ghidra-mcp-native-re-design.md
new file mode 100644
index 0000000..655493b
--- /dev/null
+++ b/docs/superpowers/specs/2026-07-07-ghidra-mcp-native-re-design.md
@@ -0,0 +1,146 @@
+# Ghidra + MCP native-RE workflow (proven on `u00428010`) — design
+
+**Date:** 2026-07-07
+**Status:** approved (brainstorming) → ready for implementation plan
+**Slice:** native-engine RE enablement; first target = SCJUMP's decision→scene resolver.
+
+---
+
+## 1. Problem & goal
+
+We keep hitting the same wall: logic compiled into `AGE.EXE` that scripts call as native ops —
+**decision→scene (`u00428010`), call-script dispatch, op 0x60 (the rand-like SCJUMP gate), the gfx
+command-buffer.** Frida (dynamic observation) has taken us far but stalls where the native logic is a
+complex state machine that must be *read*, not just watched. The blocker that previously ruled out
+static analysis (packed exe) is gone — we have the in-place-unpacked engine dumped
+(`build/engine-dump/`, module @0x400000, validated at the AGF landmark 0x474f1f).
+
+**Goal:** stand up a repeatable "Claude drives Ghidra over MCP" loop and **prove it end-to-end on one
+native function — `u00428010`, the SCJUMP decision→scene resolver** — to a concrete result: either
+recover the `0x62ccf → SCxxxx.BIN` mapping (finishing the SCJUMP slice), or establish precisely what
+makes it runtime-only. Success de-risks the whole approach and leaves a documented, reusable process
+for the other native walls.
+
+## 2. Non-goals (this slice)
+
+- **Not** reversing call-script dispatch, op 0x60, or the gfx command-buffer — those are follow-on
+ slices that reuse the proven loop. One target only.
+- **Not** building custom RE tooling — we use an off-the-shelf Ghidra MCP server; we don't write our
+ own bridge.
+- **No redistribution** of engine binaries — the dump/PE stay local, for analysis only.
+- Not committing to reimplementing `u00428010` in the VM this slice; the deliverable is the
+ *understanding* (the mapping/table or a clear runtime verdict). Reimplementation is a later step.
+
+## 3. Environment (confirmed 2026-07-07)
+
+- **Have:** Ghidra 12.1.2 installed; the game runs locally (JP locale); Frida 17.15.3;
+ `build/engine-dump/` (raw runtime dump: `manifest.json` + `range_.bin`, module base 0x400000).
+- **Need (this slice sets up):** the bethington/ghidra-mcp server (plugin + bridge) registered in
+ Claude Code; possibly pe-sieve.exe (only if raw-dump analysis is inadequate).
+- **Target facts:** consumers do `lookup-array(ptr, 0x5f0ed, 0x62ccf)` then `u00428010(ptr)`. Kelebek
+ names the op by its handler VA `0x428010` (may drift in our build → resolve via the dispatch table
+ `[esi+idx*120+0x53d88]` / proximity). The interpreter executes from the **module @0x400000**
+ (stable base) — not the per-run heap (an earlier worry, since corrected).
+
+## 4. The MCP server — bethington/ghidra-mcp
+
+Chosen over LaurieWired/GhidraMCP because it explicitly exposes the primitives this analysis needs:
+`decompile_function`, `get_xrefs_to`/`get_xrefs_from`, `get_function_by_address`, `read_memory`,
+`list_data_items`, `search_byte_patterns`, struct/enum tools. Actively maintained (v5.14.2, Jun 2026),
+stdio-MCP transport designed for Claude Code. Requires Ghidra 12.1.2 (matches ours); prereqs Java 21,
+Maven 3.9+, Python 3.10+. The 256-tool surface is a non-issue for Claude Code — tools are deferred/
+searchable, so only the handful used are loaded via ToolSearch.
+
+**Setup (user, one-time):** build + deploy the Ghidra extension (`python -m tools.setup ...`), start
+the HTTP-serving plugin inside Ghidra (127.0.0.1:8089), run the MCP bridge, and register the server in
+Claude Code's MCP config. A connectivity check (I call `list_functions` and get a non-empty result)
+gates progress to analysis.
+
+**Fallback:** if the bridge proves painful, I can still work from decompiler output the user pastes,
+or a Ghidra headless export — degraded (no automated xrefs) but not blocked.
+
+## 5. Analyzable image — raw-dump-first, pe-sieve as escalation
+
+For reading one function's logic, a perfect IAT is often unnecessary (unnamed API calls are fine when
+the function is a table lookup). So:
+
+1. **Stage A — try the existing raw dump** (`build/engine-dump/range_<0x400000>.bin`), imported into
+ Ghidra as a raw 32-bit x86 binary at base 0x400000, auto-analyzed. Zero new setup. If the decompiler
+ renders `u00428010`'s region legibly, prep is done.
+2. **Stage B — escalate to pe-sieve only if Stage A is inadequate:** with the game running,
+ `pe-sieve.exe /pid /imp 3` rebuilds the IAT into a clean PE (recorded in
+ `vm-mapping-plan.md` appendix; pe-sieve is a single portable exe, Bash-drivable while the user has
+ the game up). Validate the dump by confirming plaintext `SYS4422`/`.BIN`/`DATA1` strings appear.
+
+The escalation is triggered by observation (illegible/incomplete decompilation), not assumed up front.
+
+## 6. Ghidra load parameters
+
+32-bit x86 (`x86:LE:32:default`), image base `0x400000`. For the raw dump: import as "Raw Binary",
+set the language + base, run auto-analysis (decompiler, function ID, data references). For a pe-sieve
+PE: standard PE import. Confirm the AGF landmark (VA 0x474f1f contains the `BM`/0x4D42 check) reads as
+real code — the recorded dump-sanity anchor.
+
+## 7. Analysis plan for `u00428010`
+
+Driven by me over MCP:
+1. **Locate the real handler.** Try `get_function_by_address(0x428010)`; if it lands mid-function or on
+ non-handler code (Kelebek build drift), find it via the interpreter's op dispatch table
+ (`[esi+idx*120+0x53d88]`) or by xrefs from the operand-fetch path (`call 0x41b940`).
+2. **Decompile it** and read how it consumes its pointer argument (the `&0x5f0ed[decision]` reference)
+ — what fields it reads, what it returns, what it calls.
+3. **Chase the data.** Follow xrefs/reads to any static table in `.data`: does the decision index map,
+ directly or via `0x5f0ed`, to a scene id / filename / SYS4INI section? `list_data_items` +
+ `read_memory` on the referenced table; cross-check candidate scene ids against the real corpus
+ (SC#### filenames) and `build/asset-sections.json`.
+4. **Verdict.** Either (a) recover the `decision → scene` mapping (ideally a static table we can export
+ → a *static* win finishing SCJUMP), or (b) determine it's computed at runtime (e.g. from live state
+ the table doesn't encode) and document exactly what's needed to resolve it (a Frida hook point).
+
+**Success criterion:** a concrete, evidence-backed answer to "what scene does decision N load?", or a
+precise statement of why it can't be answered statically + the identified runtime hook.
+
+## 8. Findings capture
+
+- **New canonical doc `docs/engine-re.md`** — "native-engine reverse engineering": the home for
+ decompiled native-op findings. This slice writes the `u00428010` section (handler address, decompiled
+ behavior, the `0x5f0ed`/table structure, the decision→scene verdict). Future native walls (call-script,
+ op 0x60, gfx buffer) get sections here. Includes a short "how to run the Ghidra+MCP loop" runbook
+ (setup + connect) so it's repeatable.
+- **`vm-map/opcodes.toml`** — if `u00428010` (and any native op identified along the way) gets real
+ semantics, record them there (its existing home); rebuild via `opcodes_build.py --build`.
+- **`docs/scjump-progression.md`** — update the "native decision→scene boundary" section with the
+ result (mapping recovered, or the precise runtime dependency).
+- **CLAUDE.md canonical-documents map** — add a row: `Native-engine RE (decompiled AGE.EXE) →
+ docs/engine-re.md`.
+- If pe-sieve is used, note the dump-prep recipe in `docs/engine-re.md` (and reference the existing
+ `vm-mapping-plan.md` appendix rather than duplicating).
+
+## 9. Risks & fallbacks
+
+- **MCP setup friction / version mismatch** → fallback to pasted decompiler output or headless export
+ (degraded, not blocked). A connectivity gate (§4) catches this before analysis.
+- **Anti-debug / protector** → attach post-title (already works for our Frida dump); pe-sieve is a
+ read-only scan (low risk). Not expected to affect Ghidra static analysis of an already-captured image.
+- **VA drift (Kelebek build ≠ ours)** → resolve the handler via the dispatch table, not the raw VA.
+- **The answer is genuinely runtime** → that is still a *successful* outcome for this slice: it
+ validates the workflow and pinpoints the exact Frida hook, converting an open wall into a defined task.
+
+## 10. Definition of done
+
+1. bethington/ghidra-mcp connected in Claude Code; I can `list_functions` / `decompile_function` on the
+ loaded engine image.
+2. `u00428010` located and decompiled; its use of `0x5f0ed` and any static table understood.
+3. A verdict on decision→scene: recovered mapping (with evidence) **or** a precise runtime-hook
+ statement.
+4. `docs/engine-re.md` written (findings + repeatable runbook); `scjump-progression.md` and (if
+ applicable) `opcodes.toml` + CLAUDE.md updated; status memory updated.
+
+## 11. Implementation order (for the plan)
+
+1. Set up bethington/ghidra-mcp (user) + register in Claude Code; connectivity gate.
+2. Load the raw engine dump in Ghidra (32-bit, base 0x400000); confirm the AGF landmark; assess decomp
+ quality. Escalate to pe-sieve `/imp 3` only if inadequate.
+3. Locate + decompile `u00428010`; chase `0x5f0ed` + referenced tables; reach the decision→scene verdict.
+4. Write `docs/engine-re.md` (findings + runbook); update `scjump-progression.md`, `opcodes.toml` (if
+ applicable), CLAUDE.md map, status memory.