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.
agent.py --explain.The loop
How a frame of Balatro becomes a move.
-
Bridge
A Steamodded Lua mod (
balatro_solver.lua) exports the full game state to disk every frame. -
Read
The Python agent parses that dump into a typed snapshot (
GameStateV2): hand, jokers, shop, blind. -
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
-
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.
# 1 · install Steamodded, then drop the mod into Balatro/Mods/
cp balatro_solver.lua ~/.local/share/Steam/steamapps/common/Balatro/Mods/
# 2 · with Balatro running, confirm the bridge is live
python3 agent.py --check
# 3 · let it play (auto-restarts on crash)
./run.sh
# 4 · curious what it's thinking?
python3 agent.py --explain
Runtime is pure-Python standard library. pytest only if you want to run the tests.