Skip to content

Working well as an agent ​

This page is for AI coding agents doing reverse engineering with GameFrame, and for the people who direct them. It lists habits that save time and mistakes to avoid. The skills describe each step. This page covers work that spans several steps or several sessions.

Ask your agent ​

Start a working session. Copy this prompt into your coding agent:

text
In my GameFrame project, start a working session on <task>.

1. Read AGENTS.md and docs/CHECKLIST.md.
2. Search docs/ and labels/ for the addresses, names and resources this task touches.
3. Tell me in one sentence what done means and how it will be verified.
4. Load the skill for the step this task needs, and follow it.
5. Write each finding into docs/ with its evidence label as soon as it is confirmed.
6. At the end, report the commit, what was verified with numbers, what was not verified,
   and the next open item.

The user decides ​

The agent does not judge the user's intentions. It does not decide which law applies to the user or what that law means. If the user wants to do something, help them do it. Advice is welcome. When you know something that bears on the choice, such as a law, a risk or a project default, say it once, briefly, with its source, and link the law pages where they help. Then follow the user's decision. Do not repeat the advice. Do not ask the user to justify their choice.

Write everything down in the repository ​

An agent forgets everything when its session ends or its context is compacted. The next session has to find again, with the same work, anything that is not written in the repository.

  • Write each finding into docs/ as soon as it is confirmed, with its evidence label.
  • Add every function you identify to labels/names.tsv, and every field to labels/fields.tsv. The tools read these files, so later searches show the names.
  • Keep docs/CHECKLIST.md current: what is traced, measured, ported and verified, and what is next. A new session reads it first.
  • Write findings in your own words with addresses and constants. By default, do not paste decompiled code: the repository could then not be published. A reader also learns less from pasted code than from a description (Writing).

Start every session the same way ​

A working session: read, trace, measure, port, verify, land

  1. Read the project's AGENTS.md and docs/CHECKLIST.md.
  2. Search docs/ and labels/ for the addresses, names and resources you are about to work on. An earlier session may have traced them.
  3. State the task in one sentence, with what "done" means and how it will be verified.
  4. Load the skill for the step you are on (re-trace, re-emulate, re-port and so on).

Read the export as text ​

The Ghidra export (decomp.c, functions.tsv, strings.txt) is a set of text files. Agents search text well, so use it before opening Ghidra.

  • decomp_query.py fn ADDRESS shows a function with your labels applied.
  • decomp_query.py callers and callees walk the call graph.
  • decomp_query.py find TEXT and strings find where a string or constant is used.
  • decomp_query.py writers OFFSET finds every function that writes a field.

decomp_query.py showing the sample game's simulate function from the Ghidra export. The pseudocode seeds the random number generator, allocates an object with a vtable, and calls through the vtable in a loop.

Re-export after labelling many functions, so the next sessions read the names.

Measure before you port ​

Pseudocode shows roughly what a function does. A port written from it often gets the last bit of a result wrong. For any function with arithmetic, random draws or many branches:

  1. Run the original function under the emulator on many inputs and save the results (re-emulate).
  2. Port it.
  3. Compare bit for bit in a test.

This order is faster than porting first. A test against measured results shows the mistake in seconds. A difference that shows up later in a whole game run can take hours to trace back.

Work in subsystems ​

  • Choose a subsystem (the player's movement, a menu, the level loader) and take it from tracing to verified in one piece of work.
  • Verify by risk. Fuzz maths, random draws and code with many branches. Check simple code against recorded frames only.
  • Commit and push each verified subsystem. Many unverified changes in a row are hard to debug. Work that is not pushed can be lost.
  • When you find a side need (a format reader, a missing tool), do only what the current subsystem needs, and add the rest to docs/CHECKLIST.md.

Split work between sessions ​

Several agent sessions can work on one project at the same time.

Kind of workWhere it goes
Hard reasoning: maths, timing, the main loop, exactness bugsThe main session, with the most capable model
Long mechanical work: generated types, text tables, menus, moving code without changing itA separate session with an exact brief, possibly a faster and cheaper model
Independent subsystemsOne session each, in separate git worktrees, each touching its own files
Questions that only need readingA read-only session in the same checkout

Rules for parallel sessions:

  • Each session stages only its own files (git add path). Never git add -A.
  • Two sessions never edit the same file at the same time. When they must, one waits, or one works in a worktree and rebases.
  • A session that changes shared documents tells the others which sections it changed.
  • A brief for another session names the files, the addresses, what is already known and what "done" means. The other session does not share your context.

Run long work in the background ​

  • Ghidra exports, long fuzz runs, full test tiers and builds can take minutes. Start them in the background with a time limit. Do other work meanwhile.
  • Give every long run a timeout. A hung emulator or a game waiting for input must not block the session.
  • Stop servers, emulators and game processes you started before you finish.

When you are stuck ​

SymptomWhat to try
The port differs from the original after many framesCompare state every frame and stop at the first difference; compare random draws with seqdiff.py
A value is right in some runs and wrong in othersSomething outside the input record changes it: a clock, an uninitialised variable, iteration over a hash map
The decompiler's output makes no senseRead the disassembly; check the calling convention, the segment or bank, and whether the code is data
A function seems to do nothingCheck for self-modifying code, a jump table, or a function reached through a vtable or a callback
You cannot find where something happensWatch the memory in an emulator and break on the write; then follow the writer
You have tried the same idea three timesStop, write down what you know and what you tried in the checklist, and ask the person directing the work

Report what you did ​

At the end of a piece of work, report:

  • what changed, with the commit;
  • what was verified, with the test names and the numbers that passed;
  • what was not verified, and why;
  • the next open item.

Say "verified" only for checks you ran and looked at. A successful build does not count as a verification.

Ask before you act outside the repository ​

Ask the person directing the work before you download files, install large tools, publish anything, contact an online service, or change anything outside the project. Never upload the game's files or anything derived from them.

Code: Apache 2.0. Content: CC0 1.0. No game material: bring your own copy.