BalatRobot

A bot that plays Balatro · v0.11.0

BalatRobot

A bot that plays Balatro by itself. No clicking, no macros. It reads the board, plays the hand, runs the shop, and keeps climbing antes until the score gets too big for the game to store.

  • 0human inputs
  • 7signals per joker
  • ante 39the deep end
  • pure pyruntime, no deps

No macros

It plays the whole game, unattended.

A Lua mod streams Balatro's live state to disk. BalatRobot reads it and makes every call itself: which cards to play, what to buy, when to skip a blind. It runs the whole loop with nobody watching, and learns a little from each run.

See it play

A real run, nobody touching it.

The game on the right, the agent's reasoning on the left. The gameplay isn't edited: it reads the board, picks the blinds, plays the hands, and shops on its own.

Live agent log (left) · Balatro (right). Recorded straight from agent.py --explain.

The loop

How a frame of Balatro becomes a move.

  1. Bridge

    A Steamodded Lua mod (balatro_solver.lua) exports the full game state to disk every frame.

  2. Read

    The Python agent parses that dump into a typed snapshot (GameStateV2): hand, jokers, shop, blind.

  3. Decide

    Three different methods split the work, each suited to its part of the game.

    • Card playdeterministic solver — near-optimal
    • Shop & metaThompson-Sampling bandit — Bayesian exploration
    • Pack picksexpected-value heuristic
  4. Act & learn

    It plays the move, records how it went, and updates its policy on the fly. No retraining run required.

The scoring brain

Every joker gets a number from 0–100.

That score is seven separate reads of the board, added up. Some come from what past runs learned; the rest are priors, so a joker it has never seen doesn't look like all the others. Above 50 it buys. Above 75 it commits, and will sell something to make room.

  • tslearned value (RL), deck-aware
  • powerraw x-mult / mult / chips punch
  • alignmenthow often it actually triggers
  • deck fitdoes your deck hold what it needs
  • synergypairings — and anti-pairings
  • tempoeconomy vs. scoring, by ante
  • buildfit with your emerging identity

The real target

Endless can't be won. Only how deep you get.

In Endless the blind keeps growing super-exponentially. By ante 39 the score it demands overflows a 64-bit float (more than 1.8 × 10³⁰⁸) and the game just prints naneinf — the deepest Endless can go.

So BalatRobot plays for one thing: build a compounding x-mult engine early, keep it alive, and ride it toward ante 39. Scoring naneinf there is the run's iconic finish — LocalThunk left the overflow in on purpose.

Quickstart

Four steps to a hands-off run.

Linux · Steam/Proton · Python 3.11+ · Steamodded 1.0+

Runtime is pure-Python standard library. pytest only if you want to run the tests.