ilmenit/altirrasdl/altirra-bridge
Claude Code and agent skill by ilmenit/altirrasdl
- community
Checking that the SKILL.md file is still in the repository.
Use this skill when controlling the AltirraSDL Atari emulator programmatically — driving the simulator from a script, capturing screenshots from a running Atari, injecting joystick/keyboard input, frame-stepping for deterministic testing, reading or writing CPU/memory/chip state, setting breakpoints or watchpoints, profiling 6502 code, loading symbols, or building automated tests against an Atari binary. Triggers on phrases like "AltirraBridge", "AltirraSDL --bridge", "AltirraBridgeServer", "Altirra Python SDK", "headless Atari emulator", "screenshot the Atari", "automate AltirraSDL", "drive the emulator from Python", "Atari debugger over a socket", "altirra_bridge package", as well as on tasks involving the bridge protocol, the Python `altirra_bridge` package, or the C `altirra_bridge.h` SDK.
Install
npx vskill@latest install ilmenit/altirrasdl/altirra-bridgeSKILL.md
AltirraBridge
AltirraBridge is a JSON-over-socket scripting interface bolted onto the AltirraSDL Atari emulator. It exposes the simulator core (CPU/ANTIC/GTIA/POKEY/PIA), the debugger, the profiler, and the display pipeline to client scripts. Two SDKs ship in the box: Python (altirra_bridge package, pure stdlib) and C (altirra_bridge.h / .c, single-file, libc + Winsock only).
This skill teaches you how to drive the bridge. It does not teach 6502 reverse-engineering — that's a separate methodology question.
When to use this skill
- The user mentions AltirraBridge, AltirraSDL
--bridge,
AltirraBridgeServer, or the bridge protocol.
- The user wants to script an Atari emulator: capture screenshots,
inject input, save/load state, run tests against a .xex/.atr, set breakpoints, profile a routine.
- The user is writing automated tests, AI gameplay agents, or
reverse-engineering tooling against AltirraSDL.
- The user references the Python
altirra_bridgepackage or the
C altirra_bridge.h header.
If the task is "explain what an LDA #$00 does" or "decode this 6502 hex dump", that's general 6502 knowledge — this skill won't help.
Two server targets
- `AltirraSDL --bridge` — full GUI emulator with the bridge
exposed alongside it. Use when you want to watch the Atari while it's being scripted, or when the user is debugging the bridge itself.
- `AltirraBridgeServer` — headless lean-SDK build. No window,
no fonts and no input layer. ~30% smaller binary. Use when running automated tests, in CI, or as a backend service.
Both speak the same protocol and accept the same SDK clients. The user can switch between them transparently.
Both need to be invoked with --bridge (or --bridge=tcp:127.0.0.1:0) to enable the listening socket. On startup the server prints two lines to stderr:
The token file contains the bound address on line 1 and a 128-bit hex session token on line 2. Every client must read this file to connect.
If a script launches the server with stderr piped, it must keep reading that pipe for the whole session (e.g. a daemon thread), not only until the token line: the server keeps logging to stderr and blocks once the pipe buffer is full, which looks like a hang or a crash. See references/workflows.md, "Headless CI test".
Quick start — Python
from_token_file does connect + HELLO in one call. The context manager closes the socket cleanly even on exceptions.
Quick start — C
For VBXE graphics or blitter work, read the VBXE workflow. It covers local RAM access, structured state and FX 1.27 behavior.
Key concepts
- Frame gate.
frame(N)resumes the simulator, lets it run
exactly N frames, then re-pauses. This is how you get deterministic timing for automated tests. The next command after frame() blocks server-side until the gate releases.
- Pause preserves on reset.
cold_reset()andwarm_reset()
restore the simulator's pause state — a paused emulator stays paused after reset. This is a deliberate invariant; rely on it.
- Debug-safe reads.
peek()/memdump()read through the
debugger's side-effect-free path. Reading $D000-$D7FF does NOT trigger ANTIC/GTIA/POKEY register effects, the way a normal LDA would on real hardware.
- Inline binary payloads. Every command that returns binary data
(SCREENSHOT, RAWSCREEN, MEMDUMP) supports both inline base64 and a server-side path= mode. Inline works over adb forward on Android with no shared filesystem; path is faster on local UDS.
- Bridge owns input. The bridge has its own PIA input slot, so
injected joystick/keyboard state does not fight with real-gamepad input from the host. Disconnect cleanup automatically releases every key, direction, and console switch — a crashed script cannot leave the simulator with stuck input.
Command groups
| Group | Commands | |
|---|---|---|
| Lifecycle | HELLO PING PAUSE RESUME FRAME QUIT | |
| State read | REGS PEEK PEEK16 ANTIC GTIA POKEY PIA DLIST HWSTATE PALETTE | |
| State write/input | POKE POKE16 MEMDUMP MEMLOAD JOY KEY CONSOL BOOT MOUNT COLD_RESET WARM_RESET | |
| Save states | STATE_SAVE STATE_LOAD STATE_LIST STATE_DROP (path / slot / inline modes; bridge.checkpoint() is a context manager that auto-rewinds) | |
| Rendering | SCREENSHOT RAWSCREEN RENDER_FRAME | |
| Introspection | DISASM HISTORY EVAL CALLSTACK MEMMAP BANK_INFO CART_INFO PMG AUDIO_STATE | |
| Breakpoints | BP_SET BP_CLEAR BP_CLEAR_ALL BP_LIST WATCH_SET | |
| Symbols | SYM_LOAD SYM_RESOLVE SYM_LOOKUP MEMSEARCH | |
| Profiler | PROFILE_START PROFILE_STOP PROFILE_STATUS PROFILE_DUMP PROFILE_DUMP_TREE | |
| Verifier | VERIFIER_STATUS VERIFIER_SET |
Progressive-disclosure references
When the user's task warrants deeper detail, read from references/:
- `references/python-quickstart.md` — Python SDK recipe
collection. Read this when the user is writing Python against the bridge: AltirraBridge class, every method, common patterns (XEX boot, screenshot, input injection, breakpoint loop, profile session).
- `references/c-quickstart.md` — C SDK recipe collection.
Read this when the user is writing C against altirra_bridge.h: atb_* functions, struct layouts, parsing the JSON responses for commands without struct outputs.
- `references/workflows.md` — task-oriented playbooks. Read
this when the user describes a goal rather than a method: "screenshot every level", "find where the score is stored", "run the game until it crashes", "render a frame from a hand-built display list". Each playbook is a complete script the user can adapt.
For full wire-protocol details not covered here, ask the user for the bridge package documentation location before trying to inspect it.
Higher-level Python tools (reverse engineering)
The altirra_bridge package ships a complete RE toolkit that takes a raw .xex, drives a persistent project through the bridge, analyzes the program structure, and emits labelled, commented MADS source:
- `altirra_bridge.loader.load_xex(path)` →
XexImage—
XEX parser: segments, $FFFF marker positions, INITAD vectors, RUN address. Pure local file work; no bridge needed.
- `altirra_bridge.Project` — persistent project state on
disk. Carries labels, comments, regions, notes, plus two fields that describe self-relocating XEXes: copy_sources (via proj.mark_copy_source(…)) and reconstructed_excludes (via proj.exclude_from_reconstructed(…)). Round-trips to the bridge's symbol loader via proj.export_lab() + bridge.sym_load().
- `altirra_bridge.analyzer` — split into
analyzer.disasm
(recursive_descent), analyzer.procedures (build_procedures, call_graph_context, detect_subsystems, suggest_name_from_graph), analyzer.subroutines (analyze_subroutine), analyzer.variables, analyzer.patterns, analyzer.hw, analyzer.sampling (the only live-bridge-required submodule), and analyzer.adapter.BridgeEmu.
- `altirra_bridge.asm_writer.write_all(bridge, image, proj, out_dir, *, reconstructed=None, emit_procs=True)`
— MADS exporter. One call; writes main.asm, equates.asm, per-segment files. Runs the analyzer pass internally and wraps safe procedures in MADS .proc/.endp blocks. Two modes:
- Byte-exact (default) — each XEX segment emitted at
its load address. verify(proj, out_dir) then reassembles with MADS and checks byte-exact equality with the original XEX.
- Reconstructed (
reconstructed=True, or auto-enabled
when proj.copy_sources is non-empty) — copy-source byte ranges are re-emitted at their runtime addresses so project labels and comments (which are typically keyed to runtime, not XEX-file, addresses) finally line up with the generated asm. Use this whenever the game relocates itself at boot. The output XEX boots but isn't byte-identical to the original; call exclude_from_reconstructed() to drop stale bootstrap code (relocator body, init segment, INITAD vector) so the reconstructed XEX loads cleanly.
Any other "should I write a Python helper?" decision should default to no — most things you'd want a helper for are already a single bridge command call away.
For a concrete end-to-end RE workflow (boot → analyze → label → export labelled asm), see references/workflows.md playbook 11.
Things to avoid
- Don't reimplement Altirra functionality client-side. If you
find yourself writing a 6502 disassembler in Python, stop — the bridge's DISASM command wraps Altirra's own ATDisassembleInsn, including symbol resolution and 65C816 mode switching.
- Don't poll PROFILE_STATUS in a tight loop. The profiler is
driven by the simulator scheduler; commands are dispatched between frames. Use profile_start() → frame(N) → profile_stop() → profile_dump() instead.
- Don't call `PROFILE_DUMP*` while the profiler is running.
The underlying GetSession is destructive (it std::moves the session out of the builder). The bridge will reject a running-state dump with a clear error, but the right pattern is STOP first, DUMP second.
- `PROFILE_DUMP*` is one-shot per session. Calling it twice
returns empty data. Restart the profiler to collect new data.
- Don't try to set range watches. Altirra's access-breakpoint
API is per-byte. WATCH_SET ... len=N is rejected; set one watch per address instead.
- Don't assume `WATCH_SET mode=rw` returns one id. It creates
two breakpoints (one read, one write) and returns both ids in a list. The Python SDK reflects this in its return type.
- **Don't expect SIO trace, verifier violation logs, or
tracepoint format strings yet.** These are roadmap items awaiting public Altirra core APIs; they appear in the bridge's "deferred" list and are not in the v1 protocol.
Security
- Security scanPassed, 46 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingsrc/AltirraSDL/AltirraBridge/skills/altirra-bridge/SKILL.md
Popularity
- Repository stars
- 51
- Repository forks
- 14
- 7-day trend score
- 20
Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 20 Jul 2026, 3 months ago.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/ilmenit/altirrasdl/altirra-bridge)