Texas Hold'em poker in your terminal. Designed so a programmer working in Cursor CLI / Claude Code / Codex can pop open a second terminal, play a few hands, and get back to coding.
v0.1 ships solo mode: you vs N rule-based bots, in a single process.
The architecture deliberately reserves seams for future modes:
- Human takeover of an agent seat (and vice versa) — swap a seat's
DecisionSourceat runtime.- Networked multiplayer — replace the in-process orchestrator with a WebSocket-backed transport. The engine code does not change.
- Autochess mode — let LLM agents drive every seat with no human intervention. Already runnable today via
--watch.
See DESIGN.md for the full design / product / architecture document.
npm install
npm run build
node dist/cli/index.jsOr interactively during development:
npm run solo# Menu: choose Human vs Codex AI
node dist/cli/index.js
# Direct heads-up: you vs your local Codex CLI
node dist/cli/index.js codex
# You + 3 bots, default 1000 buy-in / 5/10 blinds
npx tsx src/cli/index.ts solo
# You + Codex + 2 rule bots
npx tsx src/cli/index.ts solo --codex --bots 2
# 5 bots, deeper stacks
npx tsx src/cli/index.ts solo --bots 5 --buyin 2000 --blinds 10/20
# Watch mode: just bots playing each other (autochess preview)
npx tsx src/cli/index.ts solo --watch --bots 4 --hands 50
# Plain text output (good for piping / CI / non-TTY shells)
node dist/cli/index.js solo --watch --text --hands 20When stdin is not a TTY (piped, CI, etc.), Holdem CLI automatically falls back to text mode so it never crashes.
Menus and action bars support arrow-key selection:
- Up/Down or Left/Right: move selection
- Enter: confirm selected mode/action
Direct hotkeys also work during a hand:
| Key | Action |
|---|---|
| F | Fold |
| C | Check / Call |
| B | Bet (prompts for amount) |
| R | Raise to (prompts for amount) |
| A | All-in |
| Q | Quit |
In bet/raise prompts you can type a number, or one of the shortcuts:
min, max, pot, half, all.
src/
engine/ # Pure-function poker engine (no IO, no networking)
cards.ts # deck + crypto-secure shuffle
hand-eval.ts # 7-card hand evaluation (wraps pokersolver)
pot.ts # main pot + side pots
betting.ts # legal actions, action application, min-raise rules
street.ts # street advancement (burn + deal)
showdown.ts # showdown / award uncontested
state.ts # HandState factory + reducer
view.ts # per-seat sanitized projection
player/ # The architectural keystone
decision-source.ts # DecisionSource interface (every seat is one)
bot-strategy.ts # Pure rule-based decision function
bot.ts # BotDecisionSource
human.ts # HumanDecisionSource (TUI bridge)
server/ # Orchestration (in-process for v1, WS later)
orchestrator.ts # drives the engine, asks sources for actions
events.ts # GameEvent typed event stream
log-renderer.ts # text-mode renderer (autochess + non-TTY)
tui/ # Ink (React) terminal UI
cli/ # `holdem` entry point + arg parsing
test/ # vitest tests for engine and integration
DESIGN.md # Full product/architecture document
The whole game is (state, action) → state. The engine is pure: no IO,
no networking, no time. The orchestrator owns one canonical HandState
at a time, asks each seat's DecisionSource for an action when it's that
seat's turn, applies it via the engine, and emits typed events. A
DecisionSource can be a human (bridged to keyboard via the TUI), a
rule-based bot, or — in a future version — a remote player on a WebSocket
or an LLM agent in a subprocess. The orchestrator does not care which.
npm testCritical paths covered: 7-card evaluation (incl. A-2-3-4-5 wheel, ties), side pot layering with all-in vs folded chips, min-raise rules including partial-all-in not reopening the betting, full bots-only game with chip conservation invariants.
- Milestone 2 — Subprocess agent adapter (stdin/stdout JSON protocol),
plus direct OpenAI / Anthropic SDK adapters. Same
DecisionSourceinterface, just new implementations. - Milestone 3 — WebSocket transport + room manager. The orchestrator already emits typed events; the TUI already projects views per seat. The switch is mostly plumbing.
- Milestone 4 — Autochess mode: lock the inputs, configurable agent personas via prompt, terminal-only spectator UI, end-of-game report.
- Milestone 5 —
cursor-agent/claude/codex execadapters.
- Strict NLHE cash-game rules. Includes burn cards, dealer button rotation, heads-up special rules (BTN posts SB, BTN acts first preflop and BB acts first postflop), partial all-in NOT reopening the betting for already-acted players (per WSOP / TDA rules), proper layered side pots, and odd-chip-to-leftmost-of-button on chops.
- The server-authoritative model is enforced in v1 even though everything is
in-process: clients (the TUI, bot sources) only ever receive a
PrivateViewwith their own hole cards visible. This makes the eventual WebSocket port trivial — there's nothing to redact later. - Crypto-secure RNG is used for shuffling.
- All bot timing is configurable; default 350ms simulated think time so the TUI doesn't feel robotic.
MIT — pending.