Skip to content

feat(platforms): add CLI support for Linux through Proton#134

Merged
S1M0N38 merged 7 commits into
mainfrom
platforms-8g5v
Jan 13, 2026
Merged

feat(platforms): add CLI support for Linux through Proton#134
S1M0N38 merged 7 commits into
mainfrom
platforms-8g5v

Conversation

@S1M0N38
Copy link
Copy Markdown
Collaborator

@S1M0N38 S1M0N38 commented Jan 1, 2026

Summary

Implements Linux platform support for BalatroBot using Steam's Proton compatibility layer.

Closes #128

Changes

Configuration

  • Add steam_path field to Config dataclass
  • Add --steam-path CLI argument
  • Add BALATROBOT_STEAM_PATH environment variable

Linux Launcher (src/balatrobot/platforms/linux.py)

  • New LinuxLauncher class for running Balatro through Proton
  • Auto-detect Steam installation from known paths:
    • ~/.local/share/Steam (standard)
    • ~/.steam/steam (symlink)
    • ~/snap/steam/common/.local/share/Steam (Snap)
    • ~/.var/app/com.valvesoftware.Steam/.local/share/Steam (Flatpak)
  • Auto-detect Proton runtime (prefers Experimental, falls back to latest versioned)
  • Configure required Proton environment variables:
    • STEAM_COMPAT_CLIENT_INSTALL_PATH
    • STEAM_COMPAT_DATA_PATH
    • WINEDLLOVERRIDES="version=n,b" for lovely injection

Tests

  • Add TestLinuxLauncher with Linux-only tests (@pytest.mark.skipif)
  • Test path validation, environment building, and command construction

Usage

# Auto-detect Steam installation
balatrobot --platform linux

# Explicit Steam path
balatrobot --platform linux --steam-path ~/.local/share/Steam

# Via environment variable
BALATROBOT_STEAM_PATH=~/.local/share/Steam balatrobot --platform linux

Requirements

  • Linux with Steam and Proton installed
  • Balatro installed via Steam
  • Lovely injector (version.dll) in Balatro directory
  • Run Balatro once through Steam to create Proton prefix

Add steam_path field to Config dataclass and --steam-path CLI argument
for specifying Steam installation path on Linux systems.

- Add BALATROBOT_STEAM_PATH environment variable mapping
- Add --steam-path CLI flag with help text
Add LinuxLauncher class for running Balatro through Steam's Proton
compatibility layer on Linux systems.

Features:
- Auto-detect Steam installation from known paths:
  - ~/.local/share/Steam (standard)
  - ~/.steam/steam (symlink)
  - ~/snap/steam/common/.local/share/Steam (Snap)
  - ~/.var/app/com.valvesoftware.Steam/.local/share/Steam (Flatpak)
- Auto-detect Proton runtime (Experimental or latest versioned)
- Set required Proton environment variables:
  - STEAM_COMPAT_CLIENT_INSTALL_PATH
  - STEAM_COMPAT_DATA_PATH
  - WINEDLLOVERRIDES for lovely injection
- Launch via: proton run Balatro.exe

Closes #128
Update get_launcher() to return LinuxLauncher for 'linux' platform
instead of raising NotImplementedError.
- Add TestLinuxLauncher class with Linux-only tests
- Test validate_paths error cases (missing/invalid Steam dir)
- Test build_env includes Proton environment variables
- Test build_cmd returns correct proton run command
- Update test_linux_not_implemented to test_linux_returns_linux_launcher
Copilot AI review requested due to automatic review settings January 1, 2026 13:53
@S1M0N38
Copy link
Copy Markdown
Collaborator Author

S1M0N38 commented Jan 1, 2026

Hey @stirby 👋

Since you have Balatro installed with Proton on Linux, would you mind testing this PR?

Quick Test Instructions

# Checkout the PR
gh pr checkout 134

# Install dependencies and run all checks
make all

# Run platform tests specifically (Linux-only tests will run on your machine)
pytest tests/cli/test_platforms.py -v

# Run just the new Linux launcher tests
pytest tests/cli/test_platforms.py::TestLinuxLauncher -v

Manual Testing

# Test auto-detection (should find your Steam installation)
balatrobot --platform linux --debug

# Or specify Steam path explicitly
balatrobot --platform linux --steam-path ~/.local/share/Steam --debug

What to verify

  1. Steam path auto-detection works for your setup
  2. Proton runtime is detected correctly
  3. Balatro launches and the API becomes healthy
  4. The mod injects properly (lovely's version.dll)

Let me know if you hit any issues! 🎴

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements Linux platform support for BalatroBot by adding a new launcher that uses Steam's Proton compatibility layer to run the Windows version of Balatro on Linux. The implementation includes automatic detection of Steam installation paths, Proton runtimes, and game files, with comprehensive configuration options via CLI arguments and environment variables.

Key Changes:

  • Added LinuxLauncher class with auto-detection for Steam, Proton, and Balatro paths
  • Extended configuration system with steam_path field and BALATROBOT_STEAM_PATH environment variable
  • Implemented Proton environment setup with Wine DLL overrides for lovely injector support

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/balatrobot/platforms/linux.py New launcher implementation with Steam/Proton detection and validation logic
src/balatrobot/platforms/__init__.py Updated platform factory to return LinuxLauncher for Linux platform
src/balatrobot/config.py Added steam_path field to Config dataclass and environment variable mapping
src/balatrobot/cli.py Added --steam-path CLI argument for specifying Steam installation path
tests/cli/test_platforms.py Added basic test coverage for LinuxLauncher validation and command building

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/balatrobot/platforms/linux.py Outdated
Comment on lines +45 to +51
# Find versioned Proton installations (e.g., "Proton 9.0", "Proton 8.0")
proton_dirs = []
for entry in common.iterdir():
if entry.is_dir() and entry.name.startswith("Proton "):
match = re.match(r"Proton (\d+(?:\.\d+)?)", entry.name)
if match:
version = float(match.group(1))
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converting version strings to float for comparison can lead to incorrect sorting for versions with multiple decimal points. For example, "Proton 8.0.5" would be captured as "8.0" and converted to 8.0, while "Proton 8.1" would be 8.1. However, the regex r"Proton (\d+(?:\.\d+)?)" only captures one optional decimal component, so this limitation is consistent. Consider documenting this limitation or using a more robust version comparison approach if multi-decimal versions are expected in the future.

Suggested change
# Find versioned Proton installations (e.g., "Proton 9.0", "Proton 8.0")
proton_dirs = []
for entry in common.iterdir():
if entry.is_dir() and entry.name.startswith("Proton "):
match = re.match(r"Proton (\d+(?:\.\d+)?)", entry.name)
if match:
version = float(match.group(1))
# Find versioned Proton installations (e.g., "Proton 9.0", "Proton 8.0", "Proton 8.0.5")
proton_dirs = []
for entry in common.iterdir():
if entry.is_dir() and entry.name.startswith("Proton "):
# Capture one or more dot-separated numeric components after "Proton "
match = re.match(r"Proton (\d+(?:\.\d+)*)", entry.name)
if match:
version_str = match.group(1)
# Parse version into a tuple of integers for correct numeric sorting
version = tuple(int(part) for part in version_str.split("."))

Copilot uses AI. Check for mistakes.
Comment on lines +182 to +227
@pytest.mark.skipif(not IS_LINUX, reason="Linux only")
class TestLinuxLauncher:
"""Tests for LinuxLauncher (Linux only)."""

def test_validate_paths_missing_steam(self, tmp_path):
"""Raises RuntimeError when Steam installation not found."""
launcher = LinuxLauncher()
config = Config(steam_path=str(tmp_path / "nonexistent"))

with pytest.raises(RuntimeError, match="Steam directory not found"):
launcher.validate_paths(config)

def test_validate_paths_invalid_steam(self, tmp_path):
"""Raises RuntimeError when Steam directory has no steamapps."""
# Create a fake Steam directory without steamapps
steam_path = tmp_path / "Steam"
steam_path.mkdir()

launcher = LinuxLauncher()
config = Config(steam_path=str(steam_path))

with pytest.raises(RuntimeError, match="Invalid Steam directory"):
launcher.validate_paths(config)

def test_build_env_includes_proton_vars(self, tmp_path):
"""build_env includes Proton compatibility environment variables."""
launcher = LinuxLauncher()
config = Config(steam_path="/path/to/Steam")

env = launcher.build_env(config)

assert env["STEAM_COMPAT_CLIENT_INSTALL_PATH"] == "/path/to/Steam"
assert "compatdata/2379780" in env["STEAM_COMPAT_DATA_PATH"]
assert env["WINEDLLOVERRIDES"] == "version=n,b"

def test_build_cmd(self, tmp_path):
"""build_cmd returns proton run command."""
launcher = LinuxLauncher()
config = Config(
balatro_path="/path/to/proton",
love_path="/path/to/Balatro.exe",
)

cmd = launcher.build_cmd(config)

assert cmd == ["/path/to/proton", "run", "/path/to/Balatro.exe"]
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test coverage for LinuxLauncher is incomplete compared to other platform launchers. Consider adding tests for:

  • Missing Balatro.exe (similar to test_validate_paths_missing_balatro_exe in WindowsLauncher)
  • Missing version.dll (similar to test_validate_paths_missing_version_dll in WindowsLauncher)
  • Missing Proton runtime
  • Missing Proton prefix (compatdata directory)
  • Platform check validation (testing the RuntimeError when not on Linux)

Copilot uses AI. Check for mistakes.
- Add --steam-path option to CLI options table
- Add 'Linux Platform (Proton)' section with:
  - Auto-detected paths (Steam, Balatro.exe, version.dll, Proton)
  - Requirements (Steam, Proton, Lovely, Proton prefix)
  - Launch examples
Use tuple instead of float for semantic version comparison to correctly
handle multi-decimal versions like 'Proton 8.0.5'.

- Change regex from \d+(?:\.\d+)? to \d+(?:\.\d+)* to capture all parts
- Parse version as tuple: '8.10' -> (8, 10) for correct comparison
- Fixes: (8, 10) > (8, 9) vs incorrect float 8.10 < 8.9
Add test_validate_paths_missing_proton_prefix to verify LinuxLauncher
raises RuntimeError when compatdata directory doesn't exist.
@S1M0N38 S1M0N38 merged commit 30b38cc into main Jan 13, 2026
4 checks passed
@S1M0N38
Copy link
Copy Markdown
Collaborator Author

S1M0N38 commented Jan 13, 2026

This is PR was merge for error and manually reverted. We still need to add support for Linux through Proton.

@S1M0N38 S1M0N38 deleted the platforms-8g5v branch January 26, 2026 21:21
@charlesmerritt
Copy link
Copy Markdown

Do you happen to recall what wasn't working here? Is this still an open issue?

@S1M0N38
Copy link
Copy Markdown
Collaborator Author

S1M0N38 commented Mar 28, 2026

@charlesmerritt

  1. Nope. This PR was just created with an agent (I'm okay with agent PR). The problem is that I don't have a Linux x86 with Proton where I can test this PR.

  2. Yeah, this is still an open issue (see feat(balatrobot): CLI support for Linux through Proton #128).

If you have a Linux x86 with Proton where you can test the generated code, you can give a shot to this open issue. You can use the implementation for the other platform as an example. I think it's better to start a new PR forking the current main to avoid any merging conflicts.

@charlesmerritt
Copy link
Copy Markdown

I see, I’m going to be testing this on Steam Deck.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(balatrobot): CLI support for Linux through Proton

4 participants