| name | balatrobot |
| description | Run and debug BalatroBot locally. Use when you need to start Balatro with the BalatroBot Lua mod, manually test or reproduce issues via the JSON-RPC HTTP API, inspect the newest session logs under logs/, and capture screenshots into logs/<session>/artifacts/ using only the balatrobot CLI (no curl, no uvx). Use when this capability is needed. |
| metadata | {"author":"coder"} |
BalatroBot debug/runbook
Ground rules
- Run commands from the repo root.
- Use
balatrobot ... only (no uvx, no curl).
- Run
balatrobot api ... requests sequentially (avoid concurrent calls).
- Prefer minimal, targeted changes while debugging; avoid large refactors.
Start BalatroBot
Choose a port (recommended)
Pick a random port in the range 20000-30000 to avoid the port staying busy for ~20-30s after restarting:
PORT="$((20000 + RANDOM % 10001))"
echo "Using PORT=$PORT"
Pick a new random PORT every time you restart balatrobot serve (crash/restart/kill/start).
Default profile (most cases)
Use headless mode unless explicitly asked to take screenshots:
balatrobot serve --port "$PORT" --headless --fast --debug
Screenshot profile (only when explicitly asked)
Use render-on-API mode for deterministic screenshots:
balatrobot serve --port "$PORT" --render-on-api --fast --debug
Call the API (no curl)
Run API calls in a second terminal while balatrobot serve ... is running.
Reminder: wrap JSON params in single quotes so you don't need to escape JSON double quotes.
balatrobot api health --port "$PORT"
balatrobot api gamestate --port "$PORT"
balatrobot api menu --port "$PORT"
balatrobot api start '{"deck":"RED","stake":"WHITE"}' --port "$PORT"
balatrobot api select --port "$PORT"
balatrobot api play '{"cards":[0,1,2,3,4]}' --port "$PORT"
Filter responses with jq (optional)
The balatrobot api ... CLI prints the JSON-RPC result object to stdout on success (see docs/api.md), so jq filters target top-level fields like .state (not .result.state).
balatrobot api gamestate --port "$PORT" | jq -r '.state'
balatrobot api gamestate --port "$PORT" | jq '{state, round_num, ante_num, money, deck, stake, won}'
balatrobot api gamestate --port "$PORT" | jq '.round | {hands_left, discards_left, chips, reroll_cost}'
balatrobot api gamestate --port "$PORT" | jq '.hand.cards | map({id, key, label})'
balatrobot api gamestate --port "$PORT" | jq -r '.jokers.cards[].label'
On failure, balatrobot api ... prints a human-readable error to stderr and exits non-zero. To extract fields from that error output, capture stderr and use jq raw mode:
balatrobot api play '{"cards":[999]}' --port "$PORT" 2>&1 >/dev/null \
| jq -R 'capture("^Error: (?<name>.*?) - (?<message>.*)$")'
Always pass the same --port to both serve and api.
Logs and sessions
Session layout
Each balatrobot serve ... run creates:
logs/<session>/<port>.log (game + mod stdout/stderr)
<session> is a timestamp folder like 2025-12-29T19-18-18 (lexicographically sortable).
Find the current session
Pick the newest session directory (works because of the timestamp format):
SESSION="$(ls -1 logs | sort | tail -n 1)"
Use it to open/tail the log:
tail -f "logs/$SESSION/$PORT.log"
The log filename matches the port: logs/<session>/<port>.log.
Screenshots (write to logs//artifacts/)
Only do this when explicitly asked for a screenshot.
-
Start the server with the screenshot profile:
balatrobot serve --port "$PORT" --render-on-api --fast --debug
-
Create the artifacts directory under the newest session:
SESSION="$(ls -1 logs | sort | tail -n 1)"
mkdir -p "logs/$SESSION/artifacts"
-
Call the screenshot endpoint with an absolute path inside that folder:
balatrobot api screenshot "{\"path\":\"$(pwd)/logs/$SESSION/artifacts/screenshot.png\"}" --port "$PORT"
Debug workflow (tight loop)
- Reproduce with the smallest possible sequence of
balatrobot api ... calls.
- Capture:
- the exact
balatrobot serve ... command,
- host/port,
- the session folder name,
- relevant excerpts from
logs/<session>/<port>.log,
- the JSON outputs (stdout) and errors (stderr) from
balatrobot api ....
- Read the most relevant code before changing anything.
- If needed, add minimal logging close to the suspected behavior, then re-run.
Where to look in the repo
- CLI entry points:
src/balatrobot/cli/serve.py, src/balatrobot/cli/api.py
- Game process + log session creation:
src/balatrobot/manager.py
- Lua HTTP server + dispatcher:
src/lua/core/server.lua, src/lua/core/dispatcher.lua
- API reference/spec:
docs/api.md, src/lua/utils/openrpc.json
- Endpoint implementations:
src/lua/endpoints/*.lua
Converted and distributed by TomeVault — claim your Tome and manage your conversions.