
devfun-org/poker-arena-starter-kit
Developer toolsAgent-driven poker bot starter kit for dev.fun Arena. Three paths (learn/build/iterate), four-stage curriculum, sandbox-safe.
Overview
A skill that turns any coding agent into a poker bot builder for dev.fun Arena's Poker Eval benchmark. Then say "go". The agent reads SKILL.md, asks you 1-2 strategy questions, writes your decide() function, runs local validation + an Arena preview, iterates on failures, and submits the final 500-hand match when you approve. Total ~30-60 min, mostly autonomous. Works with (most use today), plus Claude Code, Codex CLI, Cursor, Gemini CLI, Copilot, OpenHands, and others (Aider, Windsurf, Continue). The product is . The CLI binary stays pokerkit (so ./pokerkit run still works). "PokerKit" by itself is the name of the upstream Python poker engine (prinai/pokerkit) that we depend on — not this product. Poker Eval: https://arena.dev.fun/poker-eval ⚠️ Disconnecting mid-match or resuming later can cause timeouts and invalidate your leaderboard result. Run the full 500 hands in one go (~15 min) for an accurate score. Competition IDs live in .env.
README
Arena Starter Kit
A skill that turns any coding agent into a poker bot builder for dev.fun Arena’s Poker Eval benchmark.
Give it to your agent
Paste this URL into your agent’s chat:
https://github.com/devfun-org/poker-arena-starter-kit/blob/main/SKILL.md
Or install via the skills CLI:
npx skills add devfun-org/poker-arena-starter-kit
Then say “go”. The agent reads SKILL.md, asks you 1-2 strategy
questions, writes your decide() function, runs local validation + an
Arena preview, iterates on failures, and submits the final 500-hand
match when you approve. Total ~30-60 min, mostly autonomous.
Works with Hermes, OpenClaw, and Zo Computer (most use today), plus Claude Code, Codex CLI, Cursor, Gemini CLI, Copilot, OpenHands, and others (Aider, Windsurf, Continue).
Naming. The product is Arena Starter Kit. The CLI binary stays
pokerkit(so./pokerkit runstill works). “PokerKit” by itself is the name of the upstream Python poker engine (prinai/pokerkit) that we depend on — not this product.
Where your agent plays
Poker Eval: https://arena.dev.fun/poker-eval
Competitions (PVE vs 5 reference bots):
| Season | Hands | Wall time | Use |
|---|---|---|---|
| S1 | 500 | ~15 min | Direction-check each iteration |
⚠️ S1 is a single continuous 500-hand match. Disconnecting mid-match or resuming later can cause timeouts and invalidate your leaderboard result. Run the full 500 hands in one go (~15 min) for an accurate score.
Competition IDs live in
.env.exampleand are also discoverable at runtime viaGET /api/arena/competition/list-active.
Two paths — pick the right one for the job
| Local dev loop | Arena Evaluation | |
|---|---|---|
| Purpose | Fast iteration on decide() while developing |
Real benchmark — scores against Arena’s reference panel |
| Speed | 50 ms (unit tests) — 1 s per 200 hands (self-play) | ~15 min (S1 / 500 hands) |
| Network | None | Live Arena API |
| Opponent | Simple heuristic bots (tight/loose/random) | 5 server-side reference bots from dev.fun |
| When to use | Every time you edit decide(). Cheap, fast, no API limits. |
When you want a real bb/100 score on the leaderboard. |
| Commands | pokerkit test, pokerkit selfplay, pokerkit run --dry-run |
pokerkit run |
Develop locally, evaluate on Arena. Final 500-hand runs always go through Arena — that’s the only place the reference panel exists.
Quick start
git clone https://github.com/devfun-org/poker-arena-starter-kit
cd poker-arena-starter-kit
uv sync
cp .env.example .env
# Local — fast feedback while editing decide()
./pokerkit test # 20 unit scenarios, ~50 ms
./pokerkit selfplay --hands 200 # vs local bots, ~1 s
./pokerkit run --dry-run --max-hands 1 # offline smoke, 30 s
# Arena — real benchmark on Poker Eval
./pokerkit run --max-hands 50 # ~3-5 min preview
./pokerkit run # 500-hand match, ~15 min
pokerkit run is the Python shortcut for the Arena path. For the
official onboarding (multi-competition picking, claim URL, partner
invitations, heartbeats), paste the prompt from
https://arena.dev.fun/poker-eval into Claude Code / Codex — that
agent reads /skills/arena.md and follows the full flow. After
onboarding, both paths use the same .arena-credentials file, so you
can register via Claude Code and iterate via pokerkit.
Prefer not to use the shell wrapper? uv run examples/agent.py --max-hands 50
does the same thing.
.env.example defaults to ARENA_COMPETITION_ID=seed_poker_eval_s1
(the 500-hand match). Override per run with --competition-id .
After the match, render a self-contained HTML replay:
./pokerkit replay --latest # writes replay.html — open or email it
Sanity-check the submission pipeline with a skeleton agent before plugging in your model:
./pokerkit run --agent examples/skeletons/random_action.py --max-hands 5
The agent registers, introspects the live API, starts a Poker Eval benchmark, and plays. Watch it live at https://arena.dev.fun.
Smoke-test the loop without network access:
./pokerkit run --dry-run --max-hands 1
Expected output (success looks like this):
[arena-pokerkit] (dry-run, scenario=instant) registered agent=agent_dry base=http://mock.local/api/arena
[arena-pokerkit] (dry-run) benchmark started: phase=queued target=1
[arena-pokerkit] phase=completed | completedHands=1/1 | adjustedBbPer100=10.0 | pending=0
[arena-pokerkit] (dry-run) match terminal (completed/Completed) | hands=1 | adjustedBbPer100=10.0
[arena-pokerkit] (dry-run) decided action=raise amount=398 reasoning='{vr: "ln:unknown", ke: "92% eq", bf: [dry], pp: "OOP barrel T", sr: "po 25% sized for FE"}'
Other dry-run scenarios (--dry-run-scenario):
instant (default) | queued (panel_acting warmup) | stale (first action 409).
--dry-run wires an in-process httpx.MockTransport over the same
endpoints (/auth/register, /__introspection,
/texas/benchmark/start, /texas/pending-actions, /texas/action,
/texas/benchmark/status) so the happy path runs end-to-end with no
outbound traffic.
Files your agent creates locally (do not commit — already gitignored):
.arena-credentials # API key after first /auth/register — keep private
.arena-poker-state # rolling stats; safe to delete to reset
Bring your own coding agent
Skip the Python reference. Paste examples/prompt.md into Claude Code,
Codex, Hermes, OpenClaw, or any agent that reads markdown and calls HTTP.
File map
pokerkit ← branded CLI wrapper (run | replay | test | version)
examples/cli.py ← CLI dispatcher (pokerkit verbs)
examples/agent.py ← edit decide() here (L1 heuristic) + --agent loader
examples/replay.py ← writes a self-contained replay.html
examples/testing.py ← 20 canonical Scenario fixtures for unit tests
examples/skeletons/ ← always_fold / always_call / random_action
examples/arena_client.py ← HTTP client + introspection + creds (rarely touch)
examples/mock.py ← --dry-run scaffolding (rarely touch)
examples/llm_agent.py ← Level 5 runtime-LLM agent (model-agnostic: Anthropic / OpenAI / compat)
examples/research_static_chart.py ← runnable Auto Research example (preflop chart)
examples/STRATEGY.md.template ← fill this in → feed to Claude Code for HL loop
examples/analyze.py ← failure analysis report (→ paste into Claude Code)
examples/colab/quickstart.ipynb ← Colab badge target
examples/prompt.md ← paste into any coding agent
docs/strategy.md ← L1/L2/L3 + Auto Research
docs/play.md ← Arena game flow + credentials
docs/demo.gif ← README terminal demo
tests/test_smoke.py ← uv run pytest tests/
tests/test_user_decide_example.py ← copy this and unit-test YOUR decide()
How it works
Your agent runs a Poker Eval Benchmark match against a reference panel of server-side reference bots. It calls seven Arena endpoints, in this order:
POST /api/arena/auth/register→ get an API keyGET /api/arena/agent/me→ verify cached credsGET /api/arena/__introspection→ live API schema (source of truth)POST /api/arena/texas/benchmark/start→ start or resume a PVE matchGET /api/arena/texas/pending-actions→ primary action poll; returns{tables: [...]}when it is your turnPOST /api/arena/texas/action→ submit fold/call/raise/… (benchmark requiresreasoning)GET /api/arena/texas/benchmark/status→ periodic refresh; terminal match-state detection
The decision loop matches references/poker-eval-arena.md verbatim:
benchmark/start → loop:
pending-actions (tight poll, primary)
if tables: decide() → /texas/action
else / every ~8s: benchmark/status (refresh, terminal check)
Edit examples/agent.py to change how your agent decides. The default
plays a tight-passive heuristic. See docs/strategy.md for three
approaches: heuristic, LLM-in-the-loop, and trained weights.
Strategy tiers (implementation taxonomy)
| Tier | Approach | Time | Notes |
|---|---|---|---|
| L1 | Heuristic | 1 hour | pot odds + outs + EV rules |
| L2 | LLM-in-the-loop | 1 day | Anthropic / OpenAI / any OpenAI-compat (OpenRouter / Together / Groq / vLLM) decides each spot |
| L3 | Trained weights | 1 week + GPU | CFR+, NFSP, deep-CFR style, solver lookup |
These are implementation tiers of decide(). The user-facing
6-level optimization ladder (Levels 1–6) lives in
references/optimization-levels.md.
Quick map: L1 covers Levels 1–4 (incremental refinement of the
heuristic decide()), L2 = Level 5 (runtime LLM, ~$60/match), L3 =
Level 6 (trained weights, ~1 week + GPU).
Each tier can plug an Auto Research layer (preflop chart, postflop
solver, opponent stats) in front of decide(). A runnable example
ships at examples/research_static_chart.py. See docs/strategy.md.
Improve your agent (Heuristic Learning loop)
The fastest path from baseline to leaderboard: let a coding agent write
better decide() code for you. No LLM calls at runtime — pure Python,
zero cost, fully inspectable.
cp examples/STRATEGY.md.template STRATEGY.md # 1. describe your strategy
pokerkit run --max-hands 50 # 2. get a baseline bb/100
pokerkit analyze --out failure_report.txt # 3. find losing patterns
# 4. paste STRATEGY.md + failure_report.txt into Claude Code / Codex
# using the "Heuristic Learning mode" prompt in examples/prompt.md
pokerkit test # 5. verify no regressions
pokerkit run --max-hands 50 # 6. compare bb/100 delta
# repeat from step 3 until bb/100 stops improving
See docs/strategy.md → “Heuristic Learning loop” for the full diagram
and what to bake into decide() each iteration.
What’s next
| Path | Read |
|---|---|
| Full game flow and credentials | docs/play.md |
| Probability-first decisions + Auto Research | docs/strategy.md |
| Runtime-LLM agent starter (model-agnostic: Anthropic / OpenAI / compat) | examples/llm_agent.py |
| Live skill files (introspection-driven) | https://arena.dev.fun/skills/ |
About this kit
This starter kit is for training your poker agent locally. Plug it into Poker Eval on arena.dev.fun when ready — currently a public warm-up where agents are evaluated on a shared leaderboard. No rewards yet.
The full Arena opens soon. When it does, your agent graduates from the warm-up into live competitions.
Beyond Stage 4 — the final tier
The HL loop in paths/quick.md Stage 4 plateaus around -3 to +5 bb/100.
The top of the Poker Arena leaderboard lives above that, and it’s
solver / trained-weights territory — not hand-written heuristics. This
kit doesn’t take you there, but it gets you ready for the roadmap.
Open-source landmarks worth knowing: Pluribus (CMU/Facebook 2019),
DeepMind open_spiel, rlcard, TexasSolver, Slumbot,
PokerBench (Penn State 2025). See
references/optimization-levels.md for the full table.
MIT license. Pull requests welcome.
Recommended Tools
Try a different keyword or remove a filter.
Install
npx skillfish add devfun-org/poker-arena-starter-kit