Skip to content

Contributing

Guide for contributing to BalatroBot development.

Help Needed: Linux (Proton) Support

We currently lack CLI support for Linux (Proton). Contributions to implement this platform are highly welcome!

Please refer to the existing implementations for guidance:

  • macOS: src/balatrobot/platforms/macos.py
  • Windows: src/balatrobot/platforms/windows.py
  • Linux (Native): src/balatrobot/platforms/native.py

Prerequisites

  • Balatro (v1.0.1+)
  • Lovely Injector (v0.8.0+) - Installation
  • Steamodded (v1.0.0-beta-1221a+) - Installation
  • DebugPlus (v1.5.1+) (optional) - Required for test endpoints

Development Environment Setup

We use direnv to automatically manage environment variables and virtual environment activation. When you cd into the project directory, direnv automatically loads settings from .envrc.

Contains Secrets

The .envrc file may contain API keys and tokens. Never commit this file.

Example .envrc configuration:

# Load the virtual environment
source .venv/bin/activate

# Python-specific variables
export PYTHONUNBUFFERED="1"
export PYTHONPATH="${PWD}/src:${PYTHONPATH}"
export PYTHONPATH="${PWD}/tests:${PYTHONPATH}"

# BALATROBOT env vars
export BALATROBOT_FAST=1
export BALATROBOT_DEBUG=1
export BALATROBOT_LOVE_PATH='/path/to/Balatro/love'
export BALATROBOT_LOVELY_PATH='/path/to/liblovely.dylib'
export BALATROBOT_PARALLEL=1
export BALATROBOT_RENDER_ON_API=0
export BALATROBOT_HEADLESS=1
export BALATROBOT_AUDIO=0

Setup: Install direnv, then create .envrc in the project root with the above configuration, updating paths for your system.

Lua LSP Configuration

The .luarc.json file should be placed at the root of the balatrobot repository. It configures the Lua Language Server for IDE support (autocomplete, diagnostics, type checking).

Update Library Paths

You must update the workspace.library paths in .luarc.json to match your system:

  • Steamodded LSP definitions: path/to/Mods/smods/lsp_def
  • Love2D library: path/to/love2d/library (clone locally: LuaCATS/love2d)
  • LuaSocket library: path/to/luasocket/library (clone locally: LuaCATS/luasocket)

Example .luarc.json:

{
  "$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
  "workspace.library": [
    "/path/to/Balatro/Mods/smods/lsp_def",
    "/path/to/love2d/library",
    "/path/to/luasocket/library"
  ],
  "diagnostics.disable": ["lowercase-global"],
  "diagnostics.globals": ["G"]
}

Development Setup

1. Clone the Repository

git clone https://github.com/your-repo/balatrobot.git
cd balatrobot

Instead of copying files, create a symlink for easier development:

macOS:

ln -s "$(pwd)" ~/Library/Application\ Support/Balatro/Mods/balatrobot

Linux:

ln -s "$(pwd)" ~/.local/share/Steam/steamapps/compatdata/2379780/pfx/drive_c/users/steamuser/AppData/Roaming/Balatro/Mods/

Windows (PowerShell as Admin):

New-Item -ItemType SymbolicLink -Path "$env:APPDATA\Balatro\Mods\balatrobot" -Target (Get-Location)

3. Activate Virtual Environment

Activate the virtual environment to use the balatrobot command:

macOS/Linux:

source .venv/bin/activate

Windows (PowerShell):

.venv\Scripts\Activate.ps1

4. Launch Balatro

Start with debug and fast mode for development:

balatrobot --debug --fast

For detailed CLI options, see the CLI Reference.

5. Running Tests

Tests use Python + pytest to communicate with the Lua API. You don't need to have balatrobot running—the tests automatically start the required Balatro instances.

Separate Lua and CLI test suites

The Lua and CLI test suites must be run separately. Running them together (e.g., pytest tests) is not supported.

# Install all dependencies
make install

# Run all tests (runs CLI and Lua suites separately)
make test

# Run Lua tests (parallel execution recommended)
# Use -n 6 (or lower if your system is resource constrained)
pytest -n 6 tests/lua

# Run CLI tests (must be run separately)
pytest tests/cli

# Run specific test file
pytest tests/lua/endpoints/test_health.py -v

# Run tests with dev marker only
pytest -n 6 tests/lua -m dev

# Run only integration tests (starts Balatro)
pytest tests/lua -m integration

# Run tests that do not require Balatro instance
pytest tests/lua -m "not integration"

Available Make Commands

The project includes a Makefile with convenient targets for common development tasks. Run make help to see all available commands.

make help      # Show all available commands with descriptions
make install   # Install all dependencies (dev + test groups)
make lint      # Run ruff linter with auto-fix
make format    # Format code (Python, Markdown, Lua)
make typecheck # Run type checker (ty)
make quality   # Run all code quality checks
make fixtures  # Generate test fixtures (starts Balatro)
make test      # Run all tests (CLI + Lua suites)
make all       # Run quality checks + tests

Test Fixtures

The make fixtures command is only required if you need to explicitly generate fixtures. When running tests, missing fixtures are automatically generated if required.

Code Structure

src/lua/
├── core/
│   ├── server.lua       # HTTP server
│   ├── dispatcher.lua   # Request routing
│   └── validator.lua    # Schema validation
├── endpoints/           # API endpoints
│   ├── tests/           # Test-only endpoints
│   ├── health.lua
│   ├── gamestate.lua
│   ├── play.lua
│   └── ...
└── utils/
    ├── types.lua        # Type definitions
    ├── enums.lua        # Enum values
    ├── errors.lua       # Error codes
    ├── gamestate.lua    # State extraction
    └── openrpc.json     # API spec

Adding a New Endpoint

  • Create src/lua/endpoints/your_endpoint.lua:
return {
  name = "your_endpoint",
  description = "Brief description",
  schema = {
    param_name = {
      type = "string",
      required = true,
      description = "Parameter description",
    },
  },
  requires_state = { G.STATES.SHOP },  -- Optional
  execute = function(args, send_response)
    -- Implementation
    send_response(BB_GAMESTATE.get_gamestate())
  end,
}
  • Add tests in tests/lua/endpoints/test_your_endpoint.py

When writing tests for new endpoints, you can use the @pytest.mark.dev decorator to only run the tests you are developing with pytest -n 6 tests/lua -m dev.

  • Update src/lua/utils/openrpc.json with the new method

  • Update docs/api.md with the new method

Code Quality

Before committing, always run:

make quality  # Runs lint, typecheck, and format

Test markers:

  • @pytest.mark.dev: Run only tests under development with -m dev
  • @pytest.mark.integration: Tests that start Balatro (skip with -m "not integration")

Pull Request Guidelines

  1. One feature per PR - Keep changes focused
  2. Add tests - New endpoints need test coverage
  3. Update docs - Update api.md and openrpc.json for API changes
  4. Run code quality checks - Execute make quality before committing (see Code Quality Tools)
  5. Test locally - Ensure both pytest -n 6 tests/lua and pytest tests/cli pass

CI/CD Pipeline

The project uses GitHub Actions for continuous integration and deployment.

Workflows

  • code_quality.yml: Runs linting, type checking, and formatting on every PR (equivalent to make quality)
  • deploy_docs.yml: Deploys documentation to GitHub Pages when a release is published
  • release_please.yml: Automated version management and changelog generation
  • release_pypi.yml: Publishes the package to PyPI on release

For Contributors

You don't need to worry about most CI/CD workflows—just ensure your PR passes the code quality checks:

make quality  # Run this before pushing

If CI fails on your PR, check the workflow logs on GitHub for details. Most issues can be fixed by running make quality locally.