Pokurr is a local-first poker toolkit with three product pillars:
- offline poker analysis
- a local bot arena
- a self-improving bot research loop
It is built on:
- TypeScript for the CLI, runtime, and bot authoring surface
- Rust + WASM for fast hand evaluation and equity work
- Luca for source-mode command execution and packaging
If you only remember one thing: this repo should be useful before you ever touch the research roadmap.
There are two supported ways to use the project:
Use this while developing inside the repo:
luca poker ...Examples:
luca poker analyze equity AhKd QsQc
luca poker serve --port 3000 --seedLobby true
luca poker new-agent my-bot tagUse this for the standalone CLI experience:
pokurr ...Examples:
pokurr analyze equity AhKd QsQc
pokurr serve --port 3000 --seedLobby true
pokurr new-agent my-bot tagThe command surface is intended to be the same in both modes.
luca poker analyze equity AhKd QsQc --iterations 20000
luca poker analyze range "ATs+,AJo+" --vs "QQ+,AKs"
luca poker analyze hand AhQh --board Kh7d2h5h --potSize 42 --toCall 14What this gives you:
- hand-vs-hand equity
- range-vs-range comparison
- single-hand study in context
For a fuller study workflow, see docs/offline-analysis.md.
luca poker serve --host 127.0.0.1 --port 3000 --seedLobby true
luca poker register http://127.0.0.1:3000 --name my-bot
luca poker join ws://127.0.0.1:3001 --token <token> --agent ./my-bot
luca poker watch ws://127.0.0.1:3002What this gives you:
- a local server
- live bot play over WebSockets
- spectator and leaderboard surfaces
- a tight iteration loop for
strategy.ts
For the canonical local walkthrough, see DEMO.md.
luca poker new-agent my-bot tag
cd my-botEdit:
strategy.ts
Everything else is there to make that single file easier to reason about.
For the onboarding path, see docs/writing-a-bot.md.
Core commands:
luca poker analyze equity AhKd QsQc
luca poker analyze range "ATs+,AJo+" --vs "QQ+,AKs"
luca poker analyze hand AhQh --board Kh7d2h5h --potSize 42 --toCall 14
luca poker sim --situation docs/situations/turned-flush-draw.md --iterations 5000 --seed 42This is for:
- reviewing a hand
- comparing ranges
- studying board texture and draw structure
- building reusable situation docs
Core commands:
luca poker serve --host 127.0.0.1 --port 3000 --seedLobby true
luca poker register http://127.0.0.1:3000 --name my-bot
luca poker join ws://127.0.0.1:3001 --token <token> --agent ./my-bot
luca poker watch ws://127.0.0.1:3002
luca poker house status --server http://127.0.0.1:3000This is for:
- playing against house bots
- iterating on your own bot locally
- running demo nights with spectators and leaderboards
- validating strategy changes with real runtime behavior
This is the long-term differentiator:
- play a batch of hands
- bucket decision points
- estimate regret for legal alternatives
- write a markdown journal describing leaks
- update
strategy.tsin readable code - replay and compare
The research docs live here:
docs/regret-minimizer-plan.mddocs/planning/2026-03-28-regret-minimizer-roadmap.md
Important: this pillar should sit on top of a polished offline-analysis and local-arena product, not replace them.
bun- Rust toolchain (
rustup,cargo) wasm-packon yourPATH@soederpop/lucaCLI for source mode (npm i -g @soederpop/luca)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
rustup target add wasm32-unknown-unknown
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | shsudo apt-get update && sudo apt-get install -y build-essential pkg-config libssl-dev
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
rustup target add wasm32-unknown-unknown
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | shVerify:
rustc --version
wasm-pack --versionFrom the repo root:
bun install
bun run build:wasm
bun run testbun run compile
./dist/pokurr analyze equity AhKd QsQc --iterations 5000The compiled binary embeds the WASM path needed for standalone use.
Start here depending on your goal:
docs/offline-analysis.md— study workflows and reusable situationsdocs/writing-a-bot.md— scaffold, edit, run, debugDEMO.md— the canonical local demo/operator flowdocs/hosting-a-server.md— operator-focused persistent server notesdocs/strategy-globals-api.md— exhaustive VM global referencedocs/planning/— roadmap and planning materials
commands/poker.ts— main CLI command surfacesrc/cli.ts— standalone binary entrypointservers/poker-server.ts— local server runtimehouse/actors/— showcase house bot profilespackages/pokurr-core— TypeScript API and range/equity boundarypackages/pokurr-equity— Rust/WASM evaluatordocs/situations/— reusable study spotstest/— runtime and rules coverage
Build WASM artifacts:
bun run build:wasmRun full tests:
bun run testRun the Luca markdown demo:
bun run demo:js-apiCompile the binary:
bun run compileSingle benchmark:
bun run --cwd packages/pokurr-core benchmarkFull performance suite:
bun run --cwd packages/pokurr-core benchmark:suiteThe suite reports:
- average JS runtime
- average WASM runtime
- per-scenario speedup
- drift between JS and WASM outcomes
- weighted speedup summary
Current baseline in this workspace after the table-driven evaluator work:
- weighted suite speedup: about
217x - equity scenarios: about
39xto67x - range scenarios: about
1900x+
One constrained flop-board scenario can be faster in JS because of poker-tools short-circuit behavior. That is expected.
Consumer code should prefer @pokurr/core APIs such as equityEngine and Range.
Rust internals should remain behind @pokurr/equity.
When the local server is running, the main surfaces are:
//leaderboard/tournaments/spectator?tableId=<tableId>/spectator-debug?tableId=<tableId>/spectator-fixtures
Already solid:
- core game engine legality and tournament mechanics
- local server runtime
- house bot ecosystem
- performance test coverage
Actively being hardened:
- docs and first-time-user experience
- source/binary parity
- local bot authoring polish
Next capstone:
- regret-minimizer journals and strategy iteration loop