Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Notes for agents

- This repository runs Nintendo Switch games natively on Apple platforms: the game's own code runs, rewritten only where Apple's kernel requires it (`dm/tools/patch_nso.py`), on a host that answers Horizon's SVCs and the SDK's services (`dm/host`) and implements NVN, Vulkan and NVIDIA's desktop OpenGL on Metal (`dm/gfx/nvn`, `dm/gfx/vk`, `dm/gfx/gl`). Every game in the [games table](dm/games/README.md#games) is playable, tested on the Mac or the iPhone (a Mac gameplay test is enough to count); the table lists each with its build, SDK, engine and graphics API, and links its note, `dm/games/<id>/README.md`: what its profile needs and why, what was found on it, how to drive it on the Mac, what is open. [README.md](README.md) is the player-facing page (games, packing, playing); [docs/development.md](docs/development.md) has the internals, the script's options, building by hand, prewarm lists and power.
- Nintendo Switch games run natively on Apple platforms: game code is rewritten only where Apple's kernel requires it (`dm/tools/patch_nso.py`). The host (`dm/host`) answers Horizon's SVCs and SDK services; NVN, Vulkan and NVIDIA's desktop OpenGL run on Metal (`dm/gfx/nvn`, `dm/gfx/vk`, `dm/gfx/gl`). Every game in the [games table](dm/games/README.md#games) is playable, tested on Mac or iPhone (Mac gameplay testing suffices). The table lists builds, SDKs, engines and graphics APIs, linking each `dm/games/<id>/README.md`: profile requirements and reasons, findings, Mac controls and open work. [README.md](README.md) covers games, packing and playing for players; [docs/development.md](docs/development.md) covers internals, script options, manual builds, prewarm lists and power.
- Before any investigation or implementation, search this repository's issues and PRs (open, closed and merged) for reports, existing implementations and related work. Report matches, avoid duplicate work and link the resulting PR to relevant issues. Follow [Before starting work](docs/agents/06-dev-loop.md#before-starting-work).
- Where to start:

| Task | Read first |
Expand All @@ -14,7 +15,7 @@
| Checking a change before a pull request | [06-dev-loop.md](docs/agents/06-dev-loop.md) |
- Where a new finding goes, once: a fact about one game (its passes, shader keys, measurements, why its profile needs a key or a cut, its status) in that game's note, in the section it belongs to and marked current or resolved; a general mechanism (a host or tool change that holds for other games) as an entry in its `docs/reference/<subsystem>.md` section (Symptom, Cause, Fix, Found on with the game's note linked), then `python3 dm/tools/docs_symptoms.py` to update the symptom index, and a line under the game note's "Found on this game". Link to a finding instead of repeating it. Adding a game takes its note and its row in the games table. README keeps a text-only Switch 2 list, linked to the game notes; add a Switch 2 title after Mac gameplay testing passes. The games table holds every supported title, including original Switch games. Keep testing milestones, platform and remaining validation in the game note. This file changes only when a rule does; it states no game count (the games table is the count). `dm/tools/tests/test_docs.py` checks the links and anchors, the notes and their table rows, the symptom index, and the length of this file (1,500 words) and of each guide in `docs/agents` (6,000).
- Each game's constants and shader tables form a game profile in `dm/games/<id>/`, where `<id>` is the base game's title ID: `game.tsv` plus the tables (and `patches.py` when the rewriter has patches for its builds). Mario's profile is `010015100B514000`. Tools pick the profile with `DM_GAME`; `make -C dm/host` and `build_ipa.sh` pick it with `GAME`. There is no default game: set it every time (the tools stop and list the profiles otherwise). Put per-game values in the profile, not in code ([dm/games/README.md](dm/games/README.md)).
- Prefer general optimizations and fixes to game-specific rules. Performance work (frame pacing, power, caches, load times) counts here as much as correctness. First look for a change that holds for every game: Horizon / NVN / Vulkan semantics, or what the binary, its SDK version, its imports or its files show. Use a game-specific rule (a profile key, a rewriter cut, a build-ID gate, a per-game branch in the host) only when it is absolutely necessary, that is, when no general rule can do it.
- Prefer general optimizations and fixes to game-specific rules. Performance work (frame pacing, power, caches, load times) counts here as much as correctness. First look for a change that holds for every game: Horizon / NVN / Vulkan semantics, or what the binary, its SDK version, its imports or its files show. Use a game-specific rule (a profile key, a rewriter cut, a build-ID gate, a per-game branch in the host) only when no general rule can do it.
- Find a bug's root cause and fix it there; do not just work around it. Before changing code, find why it happens: the faulting instruction and its decompilation, the value that went wrong and who wrote it, the Horizon / NVN / Vulkan / Metal semantics the host or the translator gets wrong. Then fix that place. A change that only hides the symptom (a stub, a skipped call, a clamp, a retry, a sleep or a longer timeout, a cache flush, a profile key that turns a feature off) is a workaround: use one only when the cause is known and lies where it cannot be fixed (the game's own code, which a rewriter cut changes deliberately, or a platform limit), or when the user asks for a stopgap. Then say so in the code comment and in the game note or reference entry: the cause, or what is still unknown, marked open.
- Per-build knowledge is keyed by the NSO build ID: rewriter cuts, observation gates and frame-step stubs in the profile's `patches.py` (a game's own modules) or `dm/tools/sdk_patches.py` (Nintendo's `sdk` modules, which several games ship), which `dm/tools/patch_nso.py` (the general rewriter) loads, the profile's `build` rows (the builds the game was brought up on, and their display versions; the NSP script packs any other version from a derived profile, without those builds' fixes), and host behaviour that uses fixed module addresses checks `module_t.build_id` (from `fixups.tsv`; `dm_main_build()`). When a new game build appears, carry addresses over with `dm/tools/nso_fnmap.py` and check them by disassembly; never let fixed addresses run on a build they were not found in. For automatic cuts across updates, opt individual patches into `MATCH_CUTS` only after verifying their function fingerprints and assumptions; follow [Function-matched cuts](docs/reference/rewriter.md#function-matched-cuts-for-unregistered-builds). The shared matcher derives addresses from code; fixed addresses remain build-gated.
- To analyse or port **another** Switch title, first run `scripts/build_ipa_from_nsp.py` on its NSP folder. With no matching profile, it writes a survey to `<NSP folder>/<title ID>_survey/survey.md`, then a provisional profile guessed from the game files (`dm/games/profile_guess.py`; `<build folder>/profile/<title ID>/`; found by the tools through `DM_GAMES_DIR`), with a short heap check on the Mac when the game has virtual address memory, and a best-effort IPA that may not boot. Then follow [docs/agents](docs/agents/README.md) (extraction, binary survey, host bring-up, graphics specifics, debugging recipes; the [symptom index](docs/agents/symptoms.md) for each failure) and add a profile with its note.
Expand Down
17 changes: 17 additions & 0 deletions docs/agents/06-dev-loop.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@

One page for people and agents: the tools this repository has for building, running, debugging, measuring and checking a change, when to use which, and what a pull request needs. It links to where each tool is described instead of repeating it. Game files, keys, builds and runs stay outside the repository ([AGENTS.md](../../AGENTS.md)).

## Before starting work

Before task-specific investigation or implementation, check for existing reports, completed work and related changes. Read the repository instructions and identify the task first, then:

1. **Search the target repository's issues and PRs.** Use the upstream repository the PR will target, not only a personal fork. Include open and closed issues and open, merged and closed PRs. Search by symptoms and exact error text, game name or title ID, subsystem, affected files and symbols; use several focused queries rather than one long query. Search titles, bodies and comments. For example:

```sh
gh search issues --repo seedds/nxnative --include-prs --match title,body,comments --limit 100 '<terms>'
```

Leave out state filters to include all states. GitHub's web search is also suitable. If a result limit is reached, narrow the queries or retrieve more results before drawing a conclusion.
2. **Read relevant matches.** Read descriptions, discussion, linked issues and PRs, and the actual diffs. Check each PR's current status and whether its implementation is present in the target branch and this checkout. A closed PR may have been superseded or applied in another commit; its title or closed state alone does not prove the work is done.
3. **Report existing implementations before proceeding.** Put the issue and PR links, their status, what they cover and any remaining gap in the chat and any handoff to another agent. If a PR already implements the requested work, point to it and avoid reimplementing it. If it is open or absent from this checkout, explain that rather than treating its absence as new work. Continue only with an uncovered part of the task, making the overlap explicit.
4. **Use related work.** For a PR that overlaps without solving the same problem, consider its findings, approach, review feedback, tests and changed interfaces when choosing the new implementation. Account for dependencies and possible conflicts. Cite the related PR in the new PR's description and explain what was reused or how the changes fit together; do not assume an unmerged change is available on the target branch.
5. **Link reports to the resulting PR.** When an existing issue reports the problem, reference it in the PR description. Use `Fixes #<number>` only when the PR fully resolves that issue; use `Related to #<number>` for partial coverage or context. Identify remaining work explicitly, and preserve these links when updating the PR description. Follow [the PR template](../../.github/pull_request_template.md).
6. **Make the check's limits visible.** State what was searched and summarize the result, including when no relevant match was found. If GitHub access or search fails, say that the check is incomplete and why; use available local history and references, but do not claim there is no existing work. Repeat the search when the task's scope changes and before opening the PR, since another contributor may have worked on it in the meantime.

## 1. Build and run on the Mac

| Step | Tool | Details |
Expand Down
Loading