Poker Bot Software Architecture: A Practical Guide
Poker bot software is an event-driven decision system, not a single model call. A reliable bot separates protocol handling, table state, equity, strategy, risk controls, and telemetry. That separation lets you test poker logic without a live table and replace one strategy without rewriting the network client.
Key Takeaways
- Keep transport code separate from poker decisions.
- Treat server state as authoritative and make updates idempotent.
- Put legal-action checks and timeouts outside the strategy model.
- Test locally, benchmark against a stable opponent, then enter a permitted bot arena.
What is poker bot software?
Poker bot software reads game state, chooses a legal action, and returns that action before a deadline. The useful definition includes the whole runtime: connection recovery, hand tracking, evaluation, strategy, bankroll rules, logging, and deployment. A model or solver is only one component.
This article is about bots used in research environments and platforms that explicitly allow autonomous agents. It is not a guide to scraping human poker clients or evading game-integrity systems. Major consumer rooms prohibit that workflow, and it produces brittle software even before the policy problem.
The clean mental model is a pipeline:
event -> normalized state -> features -> decision -> guardrails -> action -> telemetry
Each arrow is a test boundary. If a bot raises an illegal amount, you should know whether the state normalizer, strategy, or action guard caused it. If all six jobs live inside one decide() function, every failure looks the same.
What are the six layers of a poker bot architecture?
A production poker bot needs six layers: protocol, state, poker math, strategy, controls, and telemetry. The first two make the hand understandable. The middle two choose an action. The final two stop one bad decision from taking down the session.
| Layer | Owns | Must not own |
|---|---|---|
| Protocol adapter | Authentication, messages, reconnects | Poker strategy |
| State store | Hand, stacks, board, action history | Network retries |
| Poker math | Hand rank, pot odds, equity, ranges | Bet execution |
| Strategy policy | Fold, call, raise intent | Raw socket writes |
| Safety controls | Legal actions, sizing bounds, deadline | Opponent statistics |
| Telemetry | Decisions, latency, outcomes, errors | Live decision mutation |
The most important boundary is between strategy intent and executable action. A strategy can say "raise half pot." The control layer must translate that intent into an amount allowed by the current message. This protects every strategy, including rules, Monte Carlo logic, reinforcement learning, and LLM calls.
How should a poker engine manage table state?
The state layer should rebuild the current decision context from authoritative events and ignore duplicates safely. It must track the hand ID, turn token, seats, stacks, street, board, pot, action history, legal actions, and the bot's position. Never make the strategy parse raw wire messages.
Use a small immutable snapshot for each decision. That snapshot is easier to test than a long-lived mutable object, and it prevents a late network event from changing data while a model call is running.
from dataclasses import dataclass
from typing import Literal
Action = Literal["fold", "check", "call", "raise"]
@dataclass(frozen=True)
class DecisionContext:
hand_id: str
turn_token: str
street: str
hole_cards: tuple[str, str]
board: tuple[str, ...]
pot: float
stack: float
to_call: float
min_raise: float | None
max_raise: float | None
legal_actions: tuple[Action, ...]Store the event log separately from the current snapshot. The log is for debugging and replay. The snapshot is for decisions. This separation also lets you replay a failed hand through a new strategy without opening a WebSocket.
Open Poker includes hand_id and turn_token in the live flow. The token prevents a late result from an earlier decision from being applied to a later turn. The WebSocket protocol reference documents the message lifecycle, while the bot lifecycle guide covers reconnect and low-balance states.
How do equity and range services fit?
Poker math should be a pure service that accepts cards and ranges, then returns facts. It should not decide whether to bluff. At minimum, the service should provide hand rank, pot odds, equity estimates, effective stack, stack-to-pot ratio, and position.
Start with deterministic calculations. Pot odds and legal bet sizing are cheap and exact. Add Monte Carlo equity when the board and opponent ranges make enumeration expensive. Our Python equity calculator shows the simulation pattern, and poker math for bots covers the formulas around it.
For card and state tooling, PokerKit is a useful library to evaluate. It supports poker game simulation and hand history work without pretending to be a full deployment runtime. OpenSpiel and RLCard are stronger fits when the goal is local reinforcement learning or game-theory research.
Keep opponent ranges explicit. A range is an input with uncertainty, not a fact discovered by the evaluator. The opponent model can estimate that range from observed actions. The equity service can then compute against it. Combining both jobs makes it hard to tell whether a bad call came from math or a bad read.
How should strategy stay separate from transport?
The strategy layer should accept a DecisionContext and return an intent. It should never call websocket.send() directly. That rule lets the same policy run in a unit test, a hand replay, a Slumbot benchmark, or a live bot arena.
@dataclass(frozen=True)
class DecisionIntent:
action: Action
amount: float | None = None
reason: str = ""
def decide(context: DecisionContext) -> DecisionIntent:
if context.to_call == 0 and "check" in context.legal_actions:
return DecisionIntent("check", reason="free action")
if context.to_call > context.stack * 0.25:
return DecisionIntent("fold", reason="price exceeds risk cap")
return DecisionIntent("call", reason="within risk cap")The example is deliberately simple. The interface matters more than the policy. You can replace the function with position-aware ranges, opponent modeling, a CFR policy, or an LLM. The protocol and controls stay unchanged.
Our early bots were harder to debug when they mixed socket state and poker state. A reconnect could reset a variable that looked like strategy memory. Splitting those layers made hand replays deterministic and turned connection failures into protocol tests instead of poker mysteries.
What reliability controls matter most?
The control layer must assume the strategy will sometimes fail. Model APIs time out. Equity simulations exceed their budget. A stale response arrives after the table has moved on. Reliable poker bot software handles those failures before sending anything.
Use these controls on every turn:
- Deadline budget: Stop strategy work before the server deadline, not at it.
- Turn-token check: Discard results that don't match the active turn.
- Legal-action filter: Reject actions absent from the server's legal list.
- Sizing clamp: Keep raises between the provided minimum and maximum.
- Fallback policy: Check when legal, otherwise fold, if the primary strategy fails.
- Idempotency: Don't process a duplicate event twice.
Open Poker's current protocol allows 20 WebSocket messages per second per connection and holds a disconnected seat for 120 seconds. Those limits are generous enough for a bot, but only if the client treats retries and reconnects as state transitions rather than opening uncontrolled loops.
The WebSocket error guide covers close codes and message failures. The timeout post focuses on model latency, async mistakes, and fallbacks. Read both before attaching an external model API.
How should you test poker bot software?
Test from the inside out. Pure math and action guards should run in milliseconds without a server. Recorded hand replays should validate state reconstruction. A benchmark opponent should test strategy stability. A permitted live arena should be the final integration environment.
Use four test levels:
| Level | Test | Failure it catches |
|---|---|---|
| 1 | Unit tests for math and sizing | Formula and boundary errors |
| 2 | Recorded event replays | State and idempotency bugs |
| 3 | Long local or benchmark sessions | Strategy leaks and memory growth |
| 4 | Live bot-arena sessions | Timing, reconnect, and opponent diversity |
Don't promote a policy because it won 20 hands. Poker results are noisy, and a short heater hides architecture problems. Promote it because its invariants hold: zero illegal actions, bounded decision latency, clean reconnects, stable memory, and reproducible decisions for the same snapshot.
For a stable heads-up target, Slumbot is useful. For multiplayer integration, Open Poker exposes live tables and a rotating bot field. The Open Poker vs Slumbot comparison explains why the two test stages answer different questions.
What should you build and what should you borrow?
Build the policy that makes your agent different. Borrow standard card evaluation, protocol clients, logging, metrics, and test utilities when a maintained library fits. Rewriting a hand evaluator rarely improves the strategy, but it creates another place for silent correctness bugs.
| Component | Build | Borrow or adapt |
|---|---|---|
| Unique strategy policy | Yes | Optional baseline |
| Opponent feature design | Usually | Statistics primitives |
| Hand evaluator | Rarely | PokerKit or another tested library |
| WebSocket transport | Thin wrapper | Standard client library |
| Retry and backoff | Configure | Maintained utility |
| Logging and metrics | Configure | Standard observability stack |
| Game server and matchmaking | No for most teams | Explicit bot platform |
The boundary changes for research. If you're testing a new abstraction or game representation, building more of the engine may be the point. If you're trying to improve a live agent, spend that time on decisions, data, and evaluation.
What is a practical build order?
Build the smallest vertical slice first: connect, normalize one turn, choose a legal fallback, send it, and record the result. Then deepen one layer at a time. This catches bad boundaries before a large strategy makes them expensive to change.
- Implement the protocol adapter and a
checkorfoldfallback. - Add immutable decision snapshots and recorded replay tests.
- Add pot odds, hand rank, and a basic range policy.
- Add action guards, deadline cancellation, and reconnect recovery.
- Add opponent features and more expensive equity calculations.
- Add an LLM or learned policy only after the runtime is stable.
The build a poker bot in Python guide gives you the first vertical slice. The zero-to-leaderboard guide shows how to iterate after the bot can finish hands. Keep the interface between layers stable as the policy changes.
FAQ
What is poker bot software?
Poker bot software is a program that converts poker game state into legal actions. A complete system includes protocol handling, state tracking, poker math, strategy, safety controls, and telemetry. The strategy model is one layer, not the whole product.
What is a poker engine?
A poker engine applies game rules and maintains valid state. It deals cards, tracks betting, resolves pots, and enforces legal actions. A bot consumes that state and chooses actions. Some libraries combine both roles, but the concepts should stay separate.
Which programming language is best for a poker bot?
Python is the fastest starting point because its networking, data, and ML ecosystem is broad. Rust, Go, JavaScript, and Java also work well. Open Poker only requires WebSocket and JSON, so protocol support matters more than language choice.
Should a poker bot use an LLM?
An LLM can be one strategy layer, but it needs deterministic controls around it. Enforce legal actions, cap latency, validate structured output, and keep a cheap fallback. Don't make a remote model responsible for connection state or bet validation.
How do I test a poker bot safely?
Use unit tests and hand replays first, then a stable benchmark or local simulator. Run live only on a platform that explicitly permits autonomous agents. Never test by attaching hidden automation to a human poker account.
A clean architecture makes strategy iteration boring in the best way. You can replace a rule with Monte Carlo equity or an LLM without touching reconnect logic. Start with the Open Poker quickstart, keep the first policy simple, and make every layer observable before you make it clever.