Cross-platform, sophisticated frontend for the libretro API. Licensed GPLv3.
AGENTS.md
## Project
RetroArch is primarily written in C89. Preserve the existing language and style of the file being edited.
- New C code must be C89-compatible unless the surrounding code explicitly requires otherwise.
- Do not introduce C99/C11 features into C89 code.
- Existing files written in C++, Objective-C, or another language should remain in that language.
- Follow the conventions of surrounding code rather than introducing a new style.
- Prefer the smallest change that completely solves the task.
- Preserve existing architecture
Read CODING-GUIDELINES before changing code: brace style, declarations,
stack budgets and the never-block rule for the main thread are there.
Subdirectories with rules of their own carry their own AGENTS.md.
`tools/compile_commands.py`, after ./configure, writes compile_commands.json
for clangd and other code navigation.
## Threads
- Nothing may block: no sleeping, busy-waiting, wait-for-idle or round-trip
waits, least of all in the threaded video wrapper and the audio pipeline.
A design that needs to block is shaped wrong.
- Do not add locks. Use retro_atomic.h, the SPSC rings (retro_spsc.h,
retro_waitable_spsc.h) and retro_eventcount.h.
- Guard threaded code with HAVE_THREADS, and check it with a full
`./configure --disable-threads` build that links, not a single TU.
- No logging inside pacing or sync paths.
RetroArch contains deliberately complex, cross-file systems. Do not simplify, consolidate, refactor, or redesign an existing subsystem merely because its structure appears unnecessarily complicated.
Complexity may exist for compatibility, platform, driver, or architectural reasons.
When implementing a feature, find an existing feature with similar behavior and follow its implementation pattern. The current source tree takes precedence over historical examples.
Do not make unrelated cleanup or refactoring changes.
## Comments
Keep comments as short as possible.
- Prefer no comment when the code is self-explanatory.
- When a comment is necessary, prefer a few words or a few lines at most.
- Explain why something is non-obvious, rather than describing what obvious code does.
- Do not add comments merely because code was changed.
- Do not describe the previous implementation or behavior unless that historical context is necessary to understand the current code.
- Do not use comments as miniature documentation or change logs.
- Prefer clear names and straightforward code over explanatory comments.
Comments should describe information that will remain useful after the current change is forgotten.
## Commit messages
Keep commit messages concise and focused.
- Explain what changed and why.
- Prefer a short subject line and a brief body when additional context is useful.
- Do not enumerate every changed file or implementation detail.
- Do not describe intermediate attempts, discarded approaches, or the development process.
- Do not explain the previous implementation unless it is necessary to understand the change.
- Keep the complete commit message below approximately 600 words.
- A commit message is not a changelog or development diary.
## Menu changes
Adding or modifying a menu option commonly requires changes in several parts of the codebase.
Do not assume that a menu option can be implemented by modifying only the file where it is displayed.
### Before adding a menu option:
- Find an existing menu option with similar behavior.
- Trace its complete implementation through the menu, settings, configuration, and message systems.
- Identify every part of that pattern that applies to the new option.
- Implement the new option consistently across all required layers.
- Do not modify unrelated menu code.
#### Useful reference commits:
- 6e9aa66aea2b2b3d0687585e41bac658ac9ae252 โ SMB timeout/context settings exposed as menu options.
- 434f41b935232325ed13024786653f9dfef49643 โ CRT menu additions.
- 23170b82ec58c2b283a7132b85fa73e18050a5ae โ MIDI device dropdown menu items.
05faba73e3fed69a5e118df2cc28d31309089243 โ menu implementation example.
These are reference implementations, not fixed lists of files to modify. The required files depend on the feature.
## Shader and video backend changes
Shader functionality frequently crosses shared shader code and multiple video backends.
### When adding or modifying shader functionality:
- Find an existing shader feature with similar behavior.
- Trace the feature through the shared shader infrastructure.
- Identify every applicable shader implementation and video backend.
- Keep backend implementations consistent where the feature is supported.
- Do not update only the backend currently being tested if the feature is expected to work elsewhere.
- Check platform/backend-specific differences rather than blindly duplicating code.
#### Useful reference commits:
- da5ecaa45a862e51783eca1280f46fbfb7984ede โ OriginalAspect and OriginalAspectRot uniforms.
- 2a56a827e8a97a3838a9d455f1dca442c0ffbb07 โ frametime/original-FPS shader uniforms.
- 37cfa4857d064464754e800bad89ce69e81230fe โ sensor shader uniforms across multiple shader and video/input backends.
These commits demonstrate the breadth of changes that may be required. They are examples of implementation patterns, not instructions to reproduce their exact file lists.
## Historical commits
Historical commits may be used to understand established implementation patterns.
- Treat examples as references, not specifications.
- Prefer the current source tree when it differs from an historical commit.
- Do not copy historical changes mechanically.
- Do not reproduce obsolete workarounds merely because they appear in an old commit.
- Inspect surrounding current code before applying a historical pattern.
## Regression tests
Regression tests must build on both Windows and Linux.
- Do not use POSIX-only or Win32-only headers or APIs in test code without a working path for the other platform; prefer libretro-common facilities.
- Check that the test builds with a Linux toolchain and with mingw-w64 (MSYS2 MINGW64 or a cross-compiler) before submitting.
If a change touches code already covered by the GitHub CI workflow regression tests (`.github/workflows/`), run those tests locally and make sure they still pass before presenting the change.
- `tools/ci_local.py which <changed files>` lists the jobs that name them (through a sample's Makefile or a tools/ script too), the full-tree builds and the tree-wide checks.
- `tools/ci_local.py run <workflow> --job <job>` runs that job's own steps, with its configure line, flags, matrix and environment. `--dry-run` prints them, `--clean-copy` runs on a fresh worktree of HEAD plus your changes, and container jobs run in their image through docker or podman.
- Do not present a change while any of those tests fail.
- A workflow construct `ci_local.py` cannot read fails `tools/ci_local.py selftest`, which CI runs; extend the script in the same change.
## Never commit build output
Nothing built is ever committed: no executables, objects, libraries,
archives, generated images or captures. This includes every sample and
tool harness built under samples/, libretro-common/samples/ and tools/.
- Stage files by name (`git add path/file.c`), never a directory or
`git add -A`, so a build that ran after a `make clean` cannot slip in.
- Before every commit run `git status --short` and check that each
staged path is source, a Makefile, a script or documentation.
- A new harness whose executable name the `.gitignore` patterns do not
cover (`*_test`, `*_test_*`) gets its own ignore line in the same
commit that adds the harness.
## Scope of changes
Keep changes focused.
### Do not:
- reformat unrelated code;
- rename unrelated symbols;
- modernize C89 code;
- replace established patterns with preferred patterns;
- refactor neighboring code without a direct need;
- add documentation or comments solely to explain the current change;
- make speculative improvements.
If a task requires a broad change, make the breadth necessary for the feature rather than artificially minimizing the number of files changed.
A change touching many files is not inherently a problem in RetroArch. Missing a required layer of an established multi-file system is a problem.