Thanks for taking the time to contribute! OpenROM is a community-driven project and every contribution matters — whether it's a bug report, a new format, or a fix for a typo.
- Reporting Bugs
- Suggesting Features
- Pull Requests
- Adding a New Conversion Format
- Building Bundled Tools (Linux)
- Code Style
Before opening an issue, please:
- Check that you're running the latest version of OpenROM.
- Search existing issues to make sure it hasn't been reported already.
When opening a bug report, include:
- OS and version (e.g. Windows 11, Ubuntu 22.04)
- Python version (
python --version) - Steps to reproduce — what file, what conversion, what settings
- Expected behavior vs what actually happened
- Log file — found in:
- Windows:
%APPDATA%\OpenROM\logs\ - Linux:
~/.config/openrom/logs\ - macOS:
~/Library/Application Support/OpenROM/logs\
- Windows:
Open an issue with the enhancement label and describe:
- What problem does this solve?
- What should the user experience look like?
- Any tools or references that could help implement it?
-
Fork the repository and create a branch from
main:git checkout -b feature/your-feature-name
-
Make your changes — keep commits focused and descriptive.
-
Test your changes before submitting:
- Run a real conversion end-to-end
- Check the live terminal log for errors
- Test on your OS if possible
-
Open a Pull Request against
mainwith:- A clear title describing what changed
- A short description of why
- Screenshots or terminal output if relevant
OpenROM's conversion logic lives in two files:
| File | What to edit |
|---|---|
core/detector.py |
Add the new extension to SUPPORTED_INPUT, CONVERSION_MAP, and COMMAND_TEMPLATES |
core/converter.py |
Add the conversion route in _dispatch() and implement the method |
core/detector.py:
SUPPORTED_INPUT = {
...
".xyz": "XYZ",
}
CONVERSION_MAP = {
...
"XYZ": ["CHD", "ISO"],
}core/converter.py:
def _dispatch(self, job):
...
if fmt == "XYZ" and tgt == "CHD":
return self._xyz_to_chd(job, src)
def _xyz_to_chd(self, job, src):
tool = get_tool_path("your_tool")
out = self._out_path(job, src, ".chd")
cmd = [tool, "-i", src, "-o", out]
self._log(f"[XYZ→CHD] {os.path.basename(src)}")
return self._run(cmd, job)Make sure the tool binary is available or document how to install it.
If you want to contribute pre-built Linux binaries to assets/linux/, here's how to build them cleanly using Google Colab (free):
sudo apt install mame-tools
cp $(which chdman) assets/linux/chdmangit clone https://github.com/kidoz/ecm ecm_src
echo '#define ECM_VERSION "2.0.0"' > ecm_src/include/version.h
gcc -O2 -x c -Dnullptr=NULL -Wno-incompatible-pointer-types \
-o assets/linux/ecm \
ecm_src/src/ecm.c ecm_src/src/eccedc.c \
-I ecm_src/include -lm
gcc -O2 -x c -Dnullptr=NULL -Wno-incompatible-pointer-types \
-o assets/linux/unecm \
ecm_src/src/unecm.c ecm_src/src/eccedc.c \
-I ecm_src/include -lmsudo apt install libuv1-dev liblz4-dev
git clone --depth=1 https://github.com/unknownbrackets/maxcso
cd maxcso && make -j$(nproc)
cp maxcso ../assets/linux/maxcsoDownload the official Linux binary from the
extract-xiso releases page
and place it at assets/linux/extract-xiso.
OpenROM follows a few simple conventions:
- Python 3.10+ — use modern syntax (
match,X | Yunions, etc.) - Type hints on all function signatures
- Log everything through
core/logger.py— never use bareprint()in core logic - No hardcoded paths — always use
core/config.pyfor tool and directory resolution - One class per file in
ui/— keep windows self-contained - Thread safety — any background operation goes in a thread; never block the UI
By contributing to OpenROM, you agree that your contributions will be licensed under the GPL v3 license.