PokerKit: A Pure Python Engine for Poker Simulation and Hand Evaluation
An open-source Python library for poker game simulations, hand evaluations, and statistical analysis
At a glance
- What is it?
- PokerKit models poker hands as a state machine you drive card by card and action by action, with automations handling the bookkeeping. It is aimed at researchers and tool builders who need legal game logic for many variants, not at anyone who wants a solved strategy out of the box.
- Who is it for?
- Adopt PokerKit if you are building a poker AI research harness, a hand history replayer, or a training environment and you are willing to drive the state machine yourself. Do not adopt it if you need a ready-made bot, a fast evaluator for millions of hands per second, or a supported online casino backend; the README names casino implementation as a use case but gives no operational detail for it.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 25 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What PokerKit is for and who it is written for
PokerKit is a pure Python library for simulating poker games, evaluating hands, and supporting statistical analysis, developed by the Universal, Open, Free, and Transparent Computer Poker Research Group. The README lists its intended uses directly: poker AI development, tool creation, and online poker casino implementation. Those three audiences want different things. An AI researcher wants a legal environment that will not let an illegal action through and that can be stepped deterministically. A tool builder wants a way to replay a hand history and inspect what happened. A casino implementer wants something else again, and the README does not expand on what that would involve.
The topics attached to the repository point at the research side: imperfect-information-game, game-theory, reinforcement-learning, libratus, pluribus. Those names are the reference points the project positions itself against. What the library actually supplies is the rules layer. It deals cards, tracks stacks, enforces betting legality, and settles pots. It does not ship a strategy, a solver, or a trained model, and nothing in the README suggests otherwise.
The state machine you drive by hand
The central object is a game state created by a class method on a variant class, for example NoLimitTexasHoldem.create_state. You pass it a set of automations, then the variant's structural parameters, then the number of players. From that point the state is a machine that advances only when you call methods on it: deal_hole, burn_card, deal_board, fold, check_or_call, complete_bet_or_raise_to.
The README's first example walks through a four-runout all-in between Phil Hellmuth and Ernest Wiggins. Cards are dealt with string arguments such as 'JsTh' for a two-card holding, the board is dealt in chunks like '9hTs9s', and actions are called in seat order with a comment naming the player. Unknown cards are written as '??' or '????', which is how the library represents a card you either do not know or do not want to specify. Starting stacks for players whose stacks are not mentioned in the source material are set to math.inf, and the example prints state.stacks at the end, showing infinities preserved alongside the real numbers.
That design has a consequence worth naming. The library does not decide whose turn it is for you in the sense of driving the hand to completion. You must call the right method at the right moment, and the README examples are written as literal transcripts of televised hands, one call per action. This is a good fit for replay and for step-by-step agent interaction, and a poor fit for anyone who wants to hand over a list of actions and get a result back.
Automations, and why the examples enable seven of them
Every create_state call in the README passes a tuple of Automation members before the game parameters. The set used in the examples is ANTE_POSTING, BET_COLLECTION, BLIND_OR_STRADDLE_POSTING, HOLE_CARDS_SHOWING_OR_MUCKING, HAND_KILLING, CHIPS_PUSHING, and CHIPS_PULLING. These cover the mechanical parts of a hand: putting forced bets in, moving chips into the pot, revealing or mucking at showdown, killing losing hands, and distributing chips at the end.
Enabling them means the transcript only contains the decisions a human player made. You do not call a method to post the small blind or to push the pot; the state does it when the relevant transition is reached. The README does not document what happens if you omit any of these, and that is a real gap. A user who wants to model a dealer error, a misposted blind, or a tournament rule that changes how antes are collected will need to read the source, because the README only shows the fully automated path.
The parameters that follow the automation tuple are positional and unlabelled in the call itself, which is why the README annotates each one with a comment. In the Hellmuth example the order is: uniform antes flag (False), antes as a mapping ({-1: 600}), blinds or straddles as a tuple ((200, 400, 800)), min-bet (400), starting stacks as a tuple, and number of players (6). The -1 key for antes and blinds appears in the short-deck example as well, where blinds are given as {-1: 3000}. The README does not explain the key convention, so a reader has to infer it from the examples or find it in the documentation site.
Getting it installed and running a first hand
The installation instruction is a single line. The library requires Python 3.11 or above and is installed with pip install pokerkit. There is no compiled extension, no build step, and no service to start, which follows from the project being pure Python.
A minimal working script, assembled from the README's second example, looks like this. Import inf from math, and Automation and NoLimitTexasHoldem from pokerkit. Call NoLimitTexasHoldem.create_state with the automation tuple, a uniform antes flag, an ante amount, a blinds tuple, a min-bet, a starting stacks tuple, and a player count. Then deal hole cards, call actions, burn and deal the board, and read state.stacks at the end.
The second example is the Tom Dwan versus Phil Ivey million-dollar pot, run with three players, uniform antes of 500, blinds of (1000, 2000), a min-bet of 2000, and starting stacks of (1125600, inf, 553500). Antonius's stack is inf because the README says it is not mentioned in the source. The hand ends with Dwan all in and the river dealt, and the printed stacks are [572100, inf, 1109500]. The third example uses NoLimitShortDeckHoldem with antes of 3000 and blinds given as {-1: 3000}, which is the same create_state signature with a different variant class. Switching variants means switching the class, not rewriting the driving code.
Multi-runout is the feature that shows the design
The Hellmuth example is the most informative part of the README because it exercises something most poker libraries do not model. After the players are all in, the state calls select_runout_count(4) for Hellmuth and select_runout_count(None) for Wiggins. The README does not state what None means here, but the transcript then deals four separate turn-and-river pairs, each preceded by burn cards, and prints a single set of final stacks.
That sequence is the clearest evidence that the state machine tracks more than a single board. Pot settlement has to account for four boards, and the stacks printed at the end reflect the combined result. Modelling this correctly requires the library to keep the runout count as part of the hand state and to defer chip distribution until all runouts are dealt, which is a non-trivial piece of bookkeeping that a hand evaluator alone would not give you.
It also shows where the README stops short. There is no explanation of when select_runout_count is legal, what happens if players disagree, or how the pot is split when runouts produce different winners. Anyone building on this feature will be reading the source and the doctests, not the README.
Where PokerKit is the wrong choice
The README claims high-speed hand evaluations and 99% code coverage from static type checking, doctests, and unit tests. Coverage is a statement about test breadth, not about speed, and no benchmark figure appears anywhere in the supplied material. Treat high-speed as a relative claim against other pure Python evaluators, not against vectorised or C-backed ones. If your workload is evaluating millions of boards per second for a solver, a pure Python evaluator is unlikely to be the right layer, and the README gives you no numbers to check that against.
The second limitation is the driving model itself. Because you call methods in sequence, a bug in your harness that calls the wrong method at the wrong time is your bug, not the library's. The automations reduce the surface but do not eliminate it. There is also no described mechanism for serialising a state, forking it, or rolling it back, and those are exactly the operations a search-based agent needs. If your plan is to clone a state at every decision point and explore, the README does not tell you how, and the examples do not demonstrate it.
The third is the casino use case. The README lists online poker casino implementation among the intended uses, but nothing in the material addresses concurrency, persistence, audit trails, or regulatory requirements. Listing a use case is not the same as supporting it.
How it differs from a standalone hand evaluator
The obvious alternative for the hand-evaluation half of the job is a dedicated evaluator library, the kind that takes seven cards and returns a rank. Those libraries do one thing: they map a card set to a comparable value. They have no concept of a pot, a betting round, a stack, or whose turn it is.
PokerKit is the other layer. It owns the game state and calls an evaluator internally when it needs to compare hands at showdown. The difference in approach matters when you pick. If you already have a fast evaluator and you only need to rank boards, adding PokerKit means adopting a state machine you will not use. If you need to know whether a raise was legal, how much is in the pot, or what the stacks look like after four runouts, an evaluator cannot answer any of those questions, and that is the gap PokerKit fills.
The trade-off runs the other way too. A dedicated evaluator can be optimised in isolation, replaced, or written in C. PokerKit's evaluator is part of a larger state object, and the README does not describe an interface for substituting your own. If evaluation speed is the bottleneck in your pipeline, that coupling is a constraint, not a feature.
Licence, releases, and what maintenance looks like
PokerKit is MIT licensed. That permits commercial use, modification, and redistribution provided the copyright notice and permission notice are included. This is not legal advice, and if you plan to embed the library in a product, particularly in a regulated gambling context, the licence is only one of several questions you will need answered by someone qualified to answer them.
The release history supplied shows v0.7.5 on 2026-08-22, v0.7.4 on 2026-05-22, and v0.7.3 on 2026-01-16. That is a rough cadence of one release every three to four months, and the version numbers are still in the 0.7 range, which means the project has not declared a stable API. Pinning a version in your dependency file is the practical response; an upgrade that renames a parameter in create_state will break every call site, and the README's examples pass those parameters positionally with comments rather than keywords.
Because the library is pure Python and has no runtime dependencies described in the material, the cost of an upgrade is mostly the cost of re-reading your own call sites. The cost of not upgrading is missing variant fixes you cannot enumerate from the README. The repository is not archived and the last push is dated the same day as the v0.7.5 release, so there is no sign of abandonment in the supplied data.
Editorial conclusion
Adopt PokerKit if you are building a poker AI research harness, a hand history replayer, or a training environment and you are willing to drive the state machine yourself. Do not adopt it if you need a ready-made bot, a fast evaluator for millions of hands per second, or a supported online casino backend; the README names casino implementation as a use case but gives no operational detail for it. Verify first that the variants you care about are covered, that Python 3.11 or above is available in your environment, and how you will handle the automation set, because the README's examples depend on seven automations being enabled together and the behaviour without them is not described.
Community notes