Batocera roms
Agent skills that teach coding agents to operate a Batocera arcade cabinet: ops, ROMs, display, tuning, maintenance. Claude Code plugin.
npx -y skills add t3chnaztea/batocera-skills --skill batocera-romsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when working with ROMs and gamelists on a Batocera cabinet: figuring out which directory a system's ROMs go in, why a game does not appear in the menu, which file formats and extensions a system accepts, curating a large library by hiding rather than deleting, editing gamelist.xml safely, cleaning up multi-disc games, or verifying dumps against No-Intro/Redump DATs. Covers extensionless-ROM-in-zip failures, the 3DO/Opera no-m3u trap, cave3rd, and the es_systems_custom.cfg landmine. Not for shaders/bezels (batocera-display), or ROM directories renamed by a Batocera version upgrade (batocera-maintenance).
SKILL.md
6.6 KB, as published. Nobody here has run it
Batocera ROMs
Managing the game library: where ROMs live, why they do or don't show up, how to
curate a big collection without deleting anything, and how to verify dumps.
Assumes the connection pattern and safety doctrine from batocera-ops.
System directories
ROMs live in /userdata/roms/<system>/, one directory per system. The directory
name is Batocera's internal system name, which is not always the obvious
one. Don't guess — look it up on the box:
# Every system Batocera knows, with its dir name and display name:
SSHB "grep -E '<name>|<fullname>' /usr/share/emulationstation/es_systems.cfg"
# What you actually have ROMs for:
SSHB "ls /userdata/roms/"
Names that trip people up: Cave CV1000 arcade lives in cave3rd (not
cv1000); Odyssey 2 is odyssey2 (renamed from o2em); Half-Life is
halflife (renamed from xash3d_fwgs). Directory renames across versions are
common — the batocera-maintenance migration reference lists the ones that bite.
Why a game doesn't appear
In rough order of likelihood:
- Wrong extension for that system. Each system accepts a fixed set of
extensions; a file with any other extension is invisible to ES. Check the
accepted list:
SSHB "grep -A2 '<system>' /usr/share/emulationstation/es_systems.cfg | grep extension". A bare.binis a frequent offender — for many disc systems.binis not an ES extension (you need a.cueor.chd). - It's hidden.
<hidden>true</hidden>ingamelist.xml, or its whole system is in the ES HiddenSystems list. Hidden games still exist on disk — this is a feature, see curation below. - Extensionless ROM inside a zip. ES lists the
.zip, but the emulator refuses to load it because the inner file has no recognizable extension. See the formats reference — this fails silently (RetroArch exits ~1s, status 1, "Could not read content file"). - A custom system-list file overrode the stock list. If a whole swath of
systems vanished, suspect
es_systems_custom.cfg— see the landmine below.
gamelist.xml anatomy
Each system's /userdata/roms/<system>/gamelist.xml is per-game metadata:
<gameList>
<game>
<path>./Super Mario World (USA).sfc</path>
<name>Super Mario World</name>
<desc>...</desc>
<image>./media/images/Super Mario World (USA).png</image>
<hidden>true</hidden> <!-- present + "true" = hidden from menu -->
<favorite>true</favorite>
</game>
</gameList>
<path>is relative to the system dir and includes the extension. It's the join key to the file on disk.- Removing the
<hidden>element (or setting it to anything buttrue) unhides. - ES rewrites this file on exit. Never edit it while ES is running and then
let ES exit cleanly — it clobbers your edit. Stop ES or SIGKILL-restart it
(see
batocera-ops→ emulationstation reference). Back the file up first.
Curation: hide, don't delete
The core methodology for taming a large or messy library, e.g. building a
focused view for an arcade cabinet: set <hidden>true</hidden>, never rm.
Why hiding wins:
- Reversible in one flag. ROMs stay on disk; flip the flag to restore.
- Non-destructive — aligns with the
batocera-opsdoctrine on a shared machine. A wrong call costs a flag flip, not a re-download. - Composable — you can layer passes (per-game hides, cross-platform dedup, regional-variant dedup) and roll any one back independently by restoring that pass's gamelist backup.
Workflow:
- Back up the gamelist(s) you'll touch:
cp gamelist.xml gamelist.xml.bak-<tag>. - Stop ES (or plan a SIGKILL-restart) so your edits survive.
- Edit
<hidden>flags — scripted for anything past a handful. - Restart ES and verify counts via the API:
curl -s http://127.0.0.1:1234/systems/<system>/gamesand counthiddenentries.
Methodology detail (system-level HiddenSystems, cross-platform canonicalization / 1G1R, regional and format dedup) is in references/curation.md. It is method only — bring your own taste; there are no game lists here.
Multi-disc games
Multi-disc CD games (PSX, Saturn, 3DO, Sega CD…) each show every disc as its own
menu entry by default, cluttering the list. The clean fix — one visible entry
per game, remaining discs hidden, per-disc launch still possible — plus the
disc-swap mechanics that differ by emulator, is in
references/formats-and-quirks.md. A
ready-to-adapt implementation for 3DO is
scripts/fix-3do-multidisc.py. Do not reach for
.m3u on 3DO/Opera — that core doesn't support playlists (a documented trap
the script explains).
Format landmines
Full detail in references/formats-and-quirks.md; the ones that cost the most time:
es_systems_custom.cfgREPLACES the stock system list, it does not merge. Drop a custom system definition in ases_systems_custom.cfgand ES boots with only your custom systems — every stock system disappears. To add a system, use a differently-named merge file, notes_systems_custom.cfg.- Extensionless ROM inside a zip → silent load failure.
unzip -Z1 *.zipand check the inner suffix; rezip with a proper extension. - 3DO/Opera has no
.m3usupport; multi-disc needs the per-entry approach. - Bare
.bindisc images are invisible on systems whose ES extension list wants.cue/.chd. Generate a.cue.
Verifying dumps against DATs
To confirm your ROMs are known-good dumps (right data, not just right filename), verify against No-Intro DATs (cartridges, hash match) and Redump DATs (discs, extract + hash). Methodology, tiers, and known limits (GD-ROM CHDs that can't hash-verify, Sega CD CDDA mismatches) are in references/dat-verification.md, with a ready-to-run scripts/dat-verify.py.