find-a-value
Skill0 starsChanged 48 days agoMITView on GitHub
Find where a program keeps a value in memory (health, ammo, gold, a score, a timer) with Pointer Lab's scanner over MCP. Covers a known number, an unknown value you can only watch go up or down, and float and double values. Use when the user wants to find, locate or scan for a value in a running game or program, or is on Pointer Lab tutorial steps 2, 3 or 4.
In this repository7 other files it gives its agents.
- find-what-writesSkill
- make-a-signatureSkill
- netcode-first-lookSkill
- safetySkill
- static-reconSkill
- walk-a-pointer-chainSkill
- write-a-trainerSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 13
Check the target against the safety skill first.
- Very specific: line 40
Use the pid from processes.
- Distinctive: line 65
Wait for it. Scans run in the background.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Find a value
Memory scanning: keep only the addresses that held the old value and now hold the new one, until one is left. Handbook: Ch. 7 Your First Hack, Ch. 10 Data Types, Ch. 12 Finding Game Data. Tutorial: step 2 (exact value), step 3 (unknown initial value), step 4 (float and double).
Check the target against the safety skill first.
Setup
This needs Pointer Lab's MCP tools (mcp__pointerlab__*). If they are not
available, the user registers them once per Pointer Lab start: Tools > MCP
Server, Start server, Copy claude mcp add command, then paste that
command into a terminal and restart Claude Code. The token in it changes every
time the server starts, so never write one down or reuse an old command. Keep
the server name pointerlab from the copied command; the write guard matches
on it.
Calls below are written tool {arguments}, the way Pointer Lab's own docs
write them. Integer arguments (pid, id, offset, limit) are JSON
numbers. Addresses can be a number or a string expression such as
"PointerLabTutorial.exe+0x2DBC8"; offsets inside an expression are hex. The pids, addresses and ids in the
examples are made up; use the ones your calls return.
Procedure
Attach.
processes {} attach {"pid": 5120}Use the pid from
processes. Check the reply:read_only: truemeans every later write will fail; the user needs to run Pointer Lab as the same user as the target, or elevated if the target is elevated.Limit the scan to writable memory. Game state is never in read-only pages, and this cuts the first scan by a large factor.
scan_set_optionsresets every option it is not given, so pass all of them each time.scan_set_options {"writable_only": true, "max_results": 1000000, "float_epsilon": 0.0001}First scan. Pick the row that matches what the user can see.
What the user sees First scan A whole number, e.g. Health: 100scan_first {"mode": "Exact value", "type": "i32", "value": "100"}A bar, no number scan_first {"mode": "Unknown initial value", "type": "i32"}A number with decimals, e.g. 96.700scan_first {"mode": "Exact value", "type": "f32", "value": "96.7"}A float that an f32 scan misses the same with "type": "f64"valueis always a string. An unknown-initial scan repliesbaseline_only: true: it recorded every value and filtered nothing, which is expected.Wait for it. Scans run in the background.
scan_status {}Poll until
runningis false. Readresults. Iftruncatedis true the result cap stopped the sweep early; raisemax_resultsand scan again.Change the value in the target, then narrow. You cannot press the game's buttons, so ask the user to do it (in the tutorial, Hit me) and to tell you the new number if one is shown.
What changed Next scan New number shown scan_next {"mode": "Exact value", "value": "93"}It went down scan_next {"mode": "Decreased value"}It went up scan_next {"mode": "Increased value"}Nothing happened since the last scan scan_next {"mode": "Unchanged value"}It went down by a known amount scan_next {"mode": "Decreased by", "value": "7"}scan_nextkeeps the first scan's type; you cannot switch from i32 to f32 partway. Pollscan_statusafter each one. AnUnchanged valuescan between two presses is cheap and removes most of memory.Repeat step 5 until
resultsis 1 to 3, then read them.scan_results {"limit": 20}Each row has
address(a number: use this one),value,previous, andstatic. In a scan rowhexis the value's bytes, not the address.static: truemeans the address is inside a module's image, which survives a restart; heap values showfalseand need a pointer chain.Prove it. Ask the user to change the value once more, then read the candidate and compare with what they see.
read {"address": 2381400145672, "type": "i32"}Track it, and show the user.
add_address {"address": 2381400145672, "type": "i32", "description": "health"} select_panel {"name": "Address List"}
Success, and dead ends
Success is one address whose read matches the value on screen after two
more changes you did not scan for.
| What happened | What it means | Next step |
| 0 results after the first exact scan | Wrong type. A float holding 100.0 is 00 00 C8 42, not 64 00 00 00 | Rescan with f32, then f64. Or start over with Unknown initial value |
| 0 results after an exact float scan | The display rounds, and bytes do not compare equal | Set float_epsilon to half the last shown digit (0.05 for one decimal) or use Unknown initial value |
| Results stop shrinking at 5 to 20 | Copies: a display copy, an undo buffer, the value in a struct and in a message | Alternate Unchanged value with a real change. Then read each; the one the game uses changes the game when edited |
| 0 results after a narrowing scan | The value changed twice between scans, or a scan used the wrong direction | Start over. Keep one change per scan |
| Value never matches the number shown | The display is scaled (x10, a percentage) or the value is encoded | Use Unknown initial value with Increased value and Decreased value only |
read_only: true on attach | The handle cannot write | Reads and scans still work. For writes, run Pointer Lab as the target's user |
Finishing a tutorial step
Steps 2 to 4 pass when the found value is set (1000 in step 2, 5000 in steps 3
and 4). Setting it is a write, which the safety hook blocks unless the user
opted in. Tell the user to double-click the value in the Address List and type
it, or, if they have opted in:
update_value {"id": 1, "value": "1000"}Next: find-what-writes to find the code that changes this value, or
walk-a-pointer-chain when the address moves between runs.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

