Thank you for your interest in contributing to AI Runner. This guide provides an overview of our project's conventions and practices.
- Fork or clone the
https://github.com/Capsize-Games/airunnerrepo and checkout thedevelopbranch. - Find an issue from the project board
- Create your own branch in the style of
[feature/bug/patch]/issue_number-description.
Example
git checkout develop
git pull
git checkout -b bug/321-some-broken-feature-fix- Make your changes and commit them to your new branch
- Push your branch to GitHub and open a pull request with
developas the base branch
- Submit a pull request (PR) with a clear title and description.
- Address any feedback provided during the review process.
- PRs must pass all tests and meet coding standards before being merged.
Full install instructions live in the README (Advanced Python Installation section). Two dev-environment notes that are easy to trip over:
-
NLTK import security guard:
nltk 3.10.1+refuses to load its data unless import-security is explicitly disabled in development. Set the environment variable in your dev shell (issue #2056):export NLTK_DISABLE_IMPORT_SECURITY=1 -
setuptools vs torch: the pinned torch line (
2.13.0+cu129) requiressetuptools>=77.0.3and has nosetuptools<82upper bound, so the latest setuptools is safe. If you use an older torch wheel that still declaressetuptools<82(e.g. some 2.11.x builds), pin it in your venv before runningpip check(issue #2057):pip install "setuptools<82"Verify the venv with
pip checkafter installing.
We follow the PEP 8 style guide for Python code. You can find the complete guide here. Additionally, refer to the Style Guide in the wiki for detailed coding standards specific to this project.
- Line Length: Limit lines to 79 characters.
- Indentation: Use 4 spaces per indentation level, never tabs.
- Naming Conventions:
- Variables and functions:
snake_case - Classes:
PascalCase - Constants:
UPPERCASE_WITH_UNDERSCORES
- Variables and functions:
- Imports:
- Group imports into standard library, third-party, and local imports, separated by blank lines.
- Use absolute imports whenever possible.
- Comments and Docstrings:
- Use Google-style docstrings for all modules, classes, and functions.
- Keep inline comments minimal and relevant.
- Formatting
- Use black for code formatting
- Use
self.loggerfor logging within classes. Examples: self.logger.debug("...")self.logger.info("...")self.logger.warning("...")self.logger.error("...")
We utilize a SignalMediator class to manage signal-slot connections across different classes without direct imports.
Example:
In the __init__ function of a class, connect a slot:
self.register(SignalCode.SOME_CODE_SIGNAL, self.on_some_signal)
Then, define the slot function:
def on_some_signal(self, message):
# Implement functionality here
...To emit the signal (from any class):
self.emit(SignalCode.SOME_CODE_SIGNAL, "Hello World!")
Note: We use the SignalCode enum to define signal codes. The message parameter is optional and can be any object type.
We employ a ServiceLocator class to call functions defined in one class from another class, avoiding direct imports.
Example:
Register a function:
self.register_service(ServiceCode.SOME_CODE, self.some_function)
Define the function:
def some_function(self, message):
# Implement functionality here
...To call the function (from any class):
self.get_service(ServiceCode.SOME_CODE)("Hello World!")
Widgets are stored under src/airunner/components/<feature>/gui/widgets (for
example src/airunner/components/chat/gui/widgets or
src/airunner/components/llm/gui/widgets). Each widget has a templates
directory which contains template files for the widget (see below).
- Widgets extend
BaseWidget, defined insrc/airunner/components/application/gui/widgets/base_widget.py. - Classes are named
ExampleWidgetwhereExampleis the name of the widget andWidgetis the suffix. - See existing widgets for examples of how to extend
BaseWidgetand use thewidget_class_attribute.
- Templates are stored in a
templatesdirectory inside of eachwidget(orwindows) directory. - Use
pyside6-designerto edit templates. - Build templates with
python scripts/build_ui.py(from the repo root). - See existing widgets for examples of how to use templates.
Icons are managed with Qt resource files which are in turn managed with
pyside6-designer and built with the same UI build script.
- Use svgrepo for icons.
- Icon source sets live under
src/airunner/gui/resources/icons/(for examplefeather/andlucide/), managed by the resource filesrc/airunner/gui/resources/feather.qrc. - The icon manager lives in
src/airunner/components/icons/managers/icon_manager.py. - Use
pyside6-designerto add or edit icons. - Build resources with
python scripts/build_ui.py.
- Repo-wide test discovery is configured in
pyproject.tomlwithtestpaths = ["src", "services/tests"], so a plainpytestrun collects both the in-repo GUI suite and the services-owned suite. - Run the unit suite with the repo test runner:
./venv/bin/python scripts/run_tests.py --unit
- Run services-owned tests directly, for example:
./venv/bin/python -m pytest services/tests/test_service_bootstrap.py -v
- The agent eval suite moved to its own repository: Capsize-Games/airunner-eval (issue #2194). See that repository's README for how to run it.
- Local dev helpers live in
scripts/dev/:run_services.shstarts the daemon,test_services.shhealth-checks it,stop_services.shstops it, andrun_gui.shlaunches the desktop client. These scripts run the split packages from a checkout without reinstalling: they setDEV_ENV=1and aPYTHONPATHcoveringservices/src,src, andnative/srcinside the repovenv(override the venv withAIRUNNER_DEV_VENV). airunner-common is a normal installed dependency, not a local path (issue #2197). - Write new tests for any new features or bug fixes. Follow the structure of
existing tests in
services/tests/andsrc/airunner/components/*/tests/.
- Documentation lives in the repo's
docs/directory (for exampledocs/architecture/) and on the Development Wiki. - Update or add relevant sections in the appropriate
.mdfiles. - Ensure that all new features are documented.
- Use clear and concise language.
- Use descriptive commit messages that explain the purpose of the change.
- Follow this format:
type: Short description Detailed explanation of the change (if necessary). - Example:
feat: Add support for Z-Image generation Added support for Z-Image models in the image generation pipeline.