Thanks for your interest in helping! This guide explains how to get help and send a change. For coding guidelines — how to build and test, and the project's hard rules (Qt, filesystem, threading, line endings, ...) — see AGENTS.md. It was written for AI coding agents, but it applies to human contributors too.
We welcome bug fixes, new programs, and new features to existing programs.
Ask questions on our Discord server. Discussion about the program is usually in #automation-chat and #automation-help.
- New program: pitch it in Discord first. A new program is a lot of code the
maintainers have to live with, so we want to agree on the idea and its scope before it
is written. Follow the patterns in
CodingAgentContext/AutomationProgramPatterns.md. - Improvement to an existing program: usually fine to just send as a PR.
- Bug fix or improvement in shared code (inference, navigation, controllers,
CommonFramework,Common/Cpp, ...): shared code has a much higher quality bar because of its blast radius. Check which programs use the code you are touching, and make sure the change is correct for all of them. - Big changes or refactors: pitch them in Discord first, and keep them out of behavior-change PRs — no unprompted refactoring of infra inside a fix or feature.
- One fix or one feature per PR; keep diffs small.
- Moves and refactors go in their own PR, separate from behavior changes.
- We prefer smaller PRs over bigger PRs.
- CI builds on Windows (clang-cl) with
/W4 /WX— every compiler warning is an error — in addition to Linux/clang. Warnings that a macOS or Linux build does not report are caught there, so assume the strictest flags apply. - Unit tests are welcome for logic changes (the test suite runs in CI and in the GUI's "Unit Test Runner" program).
- Tests are strongly recommended for new inference classes. Include images that should be detected and, where practical, images that should not be detected.
- Tests are especially important when changing an existing inference class to fix a detection problem. You likely already have an image that demonstrates the failure. Add it as a regression test that fails before the fix and passes afterward, so the same problem can be caught if it returns. Run the existing tests for the affected inference code to check that the change preserves other expected behavior.
- Test images are stored in the separate CommandLineTests repository. Add images there and the corresponding test code and test cases in this repository.
- If you also tested on real hardware, say so in the PR description: what you ran, and for how long.
- Our devs work on the repo in their free time, so reviews can take a week or more — don't open more PRs while waiting on one.
- New contributors are asked to have at most two PRs open at any time; drafts count toward that limit. Work that is stacked on not-yet-merged work can live in your fork until it is ready.
- The limit is for ramping up: It lifts once you become a regular and trusted contributor.
Due to the advance of AI technology, many GitHub repo maintainers are overwhelmed with AI generated PRs. We have the following policy as a response:
- If you use AI, you need to understand what the AI writes and can defend its decisions.
- Run and test the change yourself before sending it.
- Don't let an agent open PRs or reply to reviews on your behalf.
- When sending a pull request (PR), don't let AI generate a long description. Write your own PR description or edit an AI generated one. Keep it short, easy to read and on the point, and mention that a tool helped and which one.
- AGENTS.md contains the project's build/test steps and hard rules, so coding agents follow the same rules as human contributors.
Follow the conventions of nearby code. The notes below cover formatting and the recurring patterns used by automation programs; the hard rules in AGENTS.md also apply. For background, see the wiki's development knowledge guide and Git contribution guide.
- Use four spaces for indentation, no tabs, and preserve the file's existing line endings (usually CRLF). Avoid reformatting unrelated code.
- Always use braces and multiline bodies for conditionals and loops, even for a single
statement; do not write single-line
ifstatements, with or without braces. Do not usegoto. Put opening braces on the same line with no space between)and{, as inif (condition){; write}else{and}else if (condition){. See the explicit control flow formatting rules. - Types generally use
PascalCase; functions and local variables usesnake_case. Ordinary member variables generally use anm_prefix. Program option members useUPPER_SNAKE_CASE, such asNUM_ROUNDSorGO_HOME_WHEN_DONE, even when mutable. - Game files use names such as
PokemonLZA_RestaurantFarmer.hand.cpp, under the corresponding game namespace insidePokemonAutomation::NintendoSwitch. Follow the existing file-header andPokemonAutomation_<Name>_Hinclude-guard conventions. - Follow Include Sort Order: library and framework
headers precede game headers, and same-folder headers come last. A
.cppfile's own header is normally last. The guide covers exceptions, including panel lists whose includes follow registration order. Include what you use and remove unused includes.
- A typical single-console program has a
ProgramName_Descriptorderived fromSingleSwitchProgramDescriptorand aProgramNamederived fromSingleSwitchProgramInstance, withusing Descriptor = ProgramName_Descriptor. The descriptor holds metadata and creates statistics; the instance holds options and implementsprogram(env, context). Use the corresponding multi-console framework when needed. See Automation Program Patterns for a basic scaffold, and current programs for the APIs in use. - Keep the main loop readable by extracting meaningful steps into helpers. Reuse existing navigation, battle, box, and inference routines before adding another implementation. Helpers used by several programs belong in a shared game module. Document their starting screen, ending screen, return values, and failure behavior so callers can compose them.
- Keep screen recognition in
Inference/, reusable option definitions inOptions/, and program orchestration inPrograms/. A screen detector typically implementsStaticScreenDetector; a watcher, often usingDetectorToFinder, adds detection over time. Use existing image, OCR, and overlay helpers rather than embedding detection code in the main program loop. - Program code must remain Qt-free. Use the option and session abstractions instead of creating widgets or storing program state in UI objects. Follow the UI/state separation rules in AGENTS.md when working on shared infrastructure.
- Add new source and header files to
SourceFiles.cmake. Register a new program in its
game's
*_Panels.cpp; current single-console panels usemake_SingleSwitchProgram<ProgramName>().
- Use the existing option types, initialize them in the constructor, and register them with
PA_ADD_OPTION. Give options clear labels, useful defaults, and bounds where applicable. ChooseLockModedeliberately: unlock an option during a run only if the program safely handles changes. When several decisions depend on one value, read it once for that step. - Use the descriptor's
StatsTrackerand its atomic counters for progress and errors; callenv.update_stats()at meaningful progress points. Useenv.log()or the console logger for messages that help explain the current action or a failure. - Use the framework's notification options and send helpers for status, completion, and
errors. Reuse options such as
GoHomeWhenDoneOptionandDeferredStopButtonOptionwhere appropriate. A deferred stop should be checked at a safe boundary, with itsResetOnExitguard so the button state is reset even if the run throws.
- Send input through the controller context and existing
pbf_*/ssf_*helpers. Prefer explicit durations such as160msor10sso the units are clear. Commands are queued: usecontext.wait_for_all_requests()before making a decision that depends on those commands having finished. - For programs with feedback, use detectors and
wait_until()/run_until()to recognize game states and drive transitions. Handle both detected states and the no-detection result. Keep delays needed for animation or movement, and explain unusual timings or game-specific assumptions. - Give waits and recovery attempts a timeout or retry limit, and report failure when it
is reached. Use cancellable waits such as
context.wait_for(); CPU-only loops that do not otherwise reach a cancellation point must checkthrow_if_cancelled(). Follow AGENTS.md for thread pools and synchronization.
- Use the project's exceptions for failures. For an unexpected game state, use
OperationFailedExceptionorOperationFailedExceptionWithScreenshotas appropriate, with a message describing the action and what failed. Preserve screenshots or other diagnostic context when useful. - Recover from
OperationFailedExceptiononly where there is a concrete recovery action, such as returning to a known screen and retrying. Bound repeated recovery attempts and propagate the failure when recovery is exhausted. If a catch only records statistics or diagnostics, rethrow afterward. Let cancellation andProgramFinishedExceptionpropagate; do not swallow them in a general retry loop. - Before sending a change, remove obsolete commented-out code and temporary debugging output. Explain non-obvious game behavior and helper contracts in comments.
By contributing, you agree that your code is released under the MIT license, unless the file says otherwise. See README.md for the dependency license rules.