The agent's tools and settings
Tools
| Tool | Description | Parameters |
|---|---|---|
| balatro_exec | Run async JavaScript against Balatro through balatrobot; `bal` is in scope. Use `return <value>` for results. Read the state (`await bal.state()`), then act: `bal.select()`, `bal.skip()`, `bal.play([i, ...])`, `bal.discard([i, ...])`, `bal.cashOut()`, `bal.buy({card|voucher|pack: i})`, `bal.sell({joker|consumable: i})`, `bal.reroll()`, `bal.pack({card: i, targets} | {skip: true})`, `bal.use(i, [targets])`, `bal.rearrange({hand|jokers|consumables: [order]})`, `bal.nextRound()`, and after a game over `bal.restart()`. Every action returns the state the game settled in. |
|
| balatro_documentation | Return the complete supported JavaScript API reference for the `bal` object used inside balatro_exec. Call this when exact methods, arguments, option fields, or result types are needed. | none |
| balatro_screenshot | Capture a full-resolution screenshot of Balatro. By default it is returned as an image. Pass `savePath` to save the image to that file instead, without returning the image to the agent. |
|
Instructions
AGENTS.mdBalatro, AI assisted
You play Balatro through three tools: balatro_documentation (read it first), balatro_exec (JavaScript with bal in scope) and balatro_screenshot. The game is turn-based and waits between your actions; take the time you need, but every action counts. Play the run that has been started for you until the goal in your first message is reached (the whole game: beat the boss blind of ante 8). If the run ends in a game over, call bal.restart(): it starts a new run with the same deck and stake; the new run counts from the beginning and the session clock keeps running. When the goal is reached the session ends by itself. Do not start runs any other way, do not change settings, and do not look up information outside the game.
What the documentation tool returned
documentation.mdThe whole text
Balatro API
bal is in scope in balatro_exec. Balatro is turn-based and waits for you: nothing happens between your actions. Every action returns the game state after the game settled.
State
await bal.state() (alias bal.observe()) returns the game state as balatrobot reports it:
state: where the game is.BLIND_SELECT(choose to play or skip the next blind),SELECTING_HAND(play or discard cards),ROUND_EVAL(the round is won; cash out),SHOP,SMODS_BOOSTER_OPENED(a booster pack is open; pick from it or skip),GAME_OVER.ante_num,round_num,money,deck,stake,seed,won(true once the boss blind of ante 8 is beaten).round:hands_left,hands_played,discards_left,discards_used,reroll_cost,chips(scored this round).blinds:small,big,boss, each withtype,status(SELECT,CURRENT,UPCOMING,DEFEATED,SKIPPED),name,effect,score(chips needed),tag_name,tag_effect(the tag for skipping it).hands: per poker hand itslevel,chips,mult,played,played_this_round.- Card areas, each
{ count, limit, highlighted_limit, cards }:hand,jokers,consumables,cards(the deck), and in the shopshop,vouchers,packs;packwhen a booster pack is open. Areas that are empty and not always present are left out. - A card:
id,key(for exampleH_Afor the Ace of Hearts,j_joker,c_fool),set,label,value(suit,rank,effect: what it does, in the game's words),modifier(seal,edition,enhancement,eternal,perishable,rental),state(debuff,hidden,highlight),cost(buy,sell). used_vouchers.
Suits are H, D, C, S; ranks 2-9, T, J, Q, K, A.
Actions
Indices are 0-based positions in the area as the state lists it.
await bal.select(): play the blind that is up (BLIND_SELECT).await bal.skip(): skip the small or big blind for its tag (BLIND_SELECT). The boss blind cannot be skipped.await bal.play([i, ...]): play 1 to 5 cards fromhand(SELECTING_HAND).await bal.discard([i, ...]): discard cards fromhand(SELECTING_HAND).await bal.cashOut(): collect the round's reward and go to the shop (ROUND_EVAL).await bal.buy({ card: i }),bal.buy({ voucher: i }),bal.buy({ pack: i }): buy fromshop,vouchersorpacks(SHOP). A bought pack opens at once.await bal.pack({ card: i }): take cardifrom the open pack;bal.pack({ card: i, targets: [j, ...] })when that card needs cards fromhandas targets;bal.pack({ skip: true })to take nothing (SMODS_BOOSTER_OPENED). Tarot, Planet and Spectral cards from a pack are used at once; Jokers go tojokers, playing cards to the deck.await bal.sell({ joker: i }),bal.sell({ consumable: i }).await bal.use(i, [j, ...]?): use consumablei, with cards fromhandas targets when it needs them.await bal.rearrange({ hand: [...] }),bal.rearrange({ jokers: [...] }),bal.rearrange({ consumables: [...] }): the new order, as a permutation of the current indices. Joker order matters for some Jokers.await bal.reroll(): reroll the shop forround.reroll_cost(SHOP).await bal.nextRound(): leave the shop (SHOP).await bal.screenshot(): the game window as an image (the state is the ground truth; the picture is for orientation).await bal.restart(): only after a game over (stateGAME_OVER): a new run with the same deck and stake. Every other action is refused until you restart.
An action that does not fit the game's state or rules is refused with an error that says why; read the state first. The run has already been started for you (deck, stake and seed are fixed); starting runs, returning to the menu, saving, loading and changing the game's values are not available.
Runtime and game settings
UPSTREAM.json
game-config
- balatro
- steam_app_id
- 2 379 780
- tested_version
- 1.0.1o-FULL
- lovely
- repo
- https://github.com/ethangreen-dev/lovely-injector
- version
- 0.9.0
- url
- https://github.com/ethangreen-dev/lovely-injector/releases/download/v0.9.0/lovely-x86_64-pc-windows-msvc.zip
- sha256
- 40b994a055ee75e5f2aba81e7ae06f2c17460e18cc346483089921899fadd1f7
- file
- version.dll
- license
- MIT
- steamodded
- repo
- https://github.com/Steamodded/smods
- version
- 1.0.0-beta-1814a
- commit
- f8e4ae060df0e42ce698ffaf901a39a6ef424c0f
- url
- https://codeload.github.com/Steamodded/smods/zip/f8e4ae060df0e42ce698ffaf901a39a6ef424c0f
- sha256
- 1cae496bfd1c5dbfbc5db1eb51137d822c44fb7758ba6beaf020e43f1b5f96db
- folder
- smods
- license
- GPL-3.0
- balatrobot
- repo
- https://github.com/coder/balatrobot
- version
- 1.5.2
- commit
- 9052d76f14723293f6c6b2cecaa791a5c4ae68f3
- url
- https://codeload.github.com/coder/balatrobot/zip/refs/tags/v1.5.2
- sha256
- 7b1352be6b79d3190a3ab7cc0c9a88b3af7d5247a0dc8a8be09252b0ee241d5e
- folder
- balatrobot
- files
- balatrobot.jsonbalatrobot.luaLICENSEsrc/lua/
- settings
6 fields
- BALATROBOT_AUDIO
- 1
- BALATROBOT_FAST
- 0
- BALATROBOT_HEADLESS
- 0
- BALATROBOT_RENDER_ON_API
- 0
- BALATROBOT_DEBUG
- 0
- BALATROBOT_GAMESPEED
- 4
- license
- MIT
- jackdaw
- repo
- https://github.com/TylerFlar/jackdaw-balatro
- license
- MIT, Copyright (c) 2026 Tyler Flar
- used_by
- bot.mjs (the scripted player's policy, ported from jackdaw/cli/smart_agent.py)
- note
- Not shipped and not installed: a 1:1 Python reimplementation of Balatro with a bit-exact PRNG, used to measure the policy over seeds before it touches the game. Its own validation bridge plays against live Balatro through the same balatrobot API this plugin uses.
config.template.toml
runtime-config
# AAS run configuration for Codex. Generated by `aas configure --runtime codex`; # machine paths are replaced with __RUN_DIR__ etc. when published as runtime-config/. # Derived from cozyblaze's portal-agent, run/config.template.toml # (MIT, Copyright (c) 2026 cozyblaze; the license text is published next to this file as LICENSE). model_reasoning_summary = "detailed" hide_agent_reasoning = false approval_policy = "never" default_permissions = "aas-run" web_search = "disabled" [windows] sandbox = "elevated" [tools] web_search = false [features] shell_tool = false unified_exec = false plugins = false apps = false browser_use = false computer_use = false image_generation = false multi_agent = false skill_search = false hooks = false [features.context_management] experimental_mode = true [apps._default] enabled = false [mcp_servers.node_repl] command = "node" enabled = false # The AAS broker. Node permission flags limit filesystem writes to the run # directory and reads to core plus the game plugin; hardening.mjs limits its # network access to the game's endpoint(s). [mcp_servers.balatro] command = "node" cwd = '__RUN_DIR__' args = [ '--permission', '--allow-fs-read=__REPO__/packages/core', '--allow-fs-read=__REPO__/games/balatro', '--allow-fs-read=__RUN_DIR__', '--allow-fs-write=__RUN_DIR__', '__REPO__/packages/core/src/broker.mjs', ] startup_timeout_sec = 60 tool_timeout_sec = 180 enabled_tools = [ "balatro_documentation", "balatro_screenshot", "balatro_exec", ] default_tools_approval_mode = "approve" [mcp_servers.balatro.env] AAS_GAME_MODULE = "__REPO__/games/balatro/plugin.mjs" AAS_RUN_DIR = "__RUN_DIR__" AAS_ALLOWED_ENDPOINTS = "127.0.0.1:12347" [permissions.aas-run] extends = ":workspace" description = "Write only inside the run directory; deny host reads and command networking." [permissions.aas-run.filesystem] ":root" = "deny" ":minimal" = "read" ":tmpdir" = "deny" ":slash_tmp" = "deny" [permissions.aas-run.network] enabled = false [shell_environment_policy] inherit = "core" ignore_default_excludes = false
LICENSE
runtime-config
MIT License Copyright (c) 2026 cozyblaze Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.