Docs

Bot Contracts

BotArena is turn-based. We send a JSON request every turn; you answer with a valid action before the deadline. Requests run in sandboxed containers with no external network, Python-first.

Request payload

Example for Rock-Paper-Scissors (RPS):

{
  "game": "rps",
  "turn": 12,
  "you": {
    "id": "blue",
    "last_action": "rock",
    "history": ["rock", "paper", "rock"]
  },
  "opponent": {
    "id": "red",
    "last_action": "scissors",
    "history": ["paper", "scissors", "scissors"]
  },
  "public_state": {
    "score": { "blue": 7, "red": 4 }
  },
  "time_budget_ms": 800,
  "trace_id": "match-3lkaq-turn-12"
}

Fields are stable across games: IDs for both bots, a public game state, and your response budget in milliseconds.

Response shape

{
  "action": "paper",
  "metadata": {
    "note": "Countering scissors streak"
  }
}
  • action must be one of the allowed moves for the game. Unknown values are rejected as illegal.
  • metadata is optional; it shows up in logs to help you debug intent.

Timeouts and illegal actions

  • Timeouts: when time_budget_ms is exceeded, we auto-submit a safe fallback (fold/check/idle) and mark the turn as a timeout.
  • Illegal action: invalid payloads are replaced with the safest legal move for the game plus a penalty.
  • Repeated violations can disqualify a match; keep handlers pure and fast.

Poker-style action map

For turn-based poker games the engine accepts structured actions. A single turn request might look like:

{
  "game": "poker",
  "turn": 24,
  "you": { "stack": 1480, "committed": 120, "last_action": "call" },
  "opponent": { "stack": 1620, "committed": 120, "last_action": "raise" },
  "public_state": {
    "street": "turn",
    "board": ["Qh", "9s", "4c", "2c"],
    "pot": 240,
    "bet_to_call": 120,
    "legal_actions": ["fold", "call", "raise"]
  },
  "time_budget_ms": 900
}

And the response:

{
  "action": {
    "type": "raise",
    "amount": 220
  },
  "metadata": { "style": "semi-bluff with backdoor clubs" }
}

Keep raise amounts within the legal range included in the request; the runner clamps anything outside the range to the nearest legal value and flags the turn as illegal.

Versioning your contract usage

  • Pin to the contract version exposed in the request header (e.g. x-botarena-contract: v1).
  • Prefer defensive parsing and defaults so your bot survives small schema additions.
  • Log your decision inputs (board, pot, legal actions) to replay why you chose an action.