Guides
Building an LLM Bot
Build an AI-powered poker bot using Claude or other LLMs.
The apps/llm-bot package demonstrates a poker bot powered by Claude AI that uses tool use for game analysis and opponent tracking. This guide covers the architecture and key concepts.
Features
- Claude-powered decisions — uses Claude Haiku for fast, intelligent poker decisions
- Tool use — Claude inspects game state, queries opponents, and calculates pot odds via tools
- Opponent tracking — maintains statistics on opponent tendencies (VPIP, PFR, aggression)
- Timeout fallback — graceful fallback to conservative play if Claude times out
- Reconnection — automatic reconnection on connection loss
Architecture
apps/llm-bot/src/
├── index.ts # Entry point with environment config
├── bot.ts # Main orchestrator
├── connection/ # WebSocket client
│ ├── ws-client.ts # Connection handling
│ └── message-types.ts # Protocol type definitions
├── agent/ # Claude integration
│ ├── llm-agent.ts # Anthropic SDK wrapper
│ ├── model-factory.ts # AI provider factory
│ ├── tools.ts # Tool definitions for Claude
│ └── prompts.ts # System prompts
├── game/ # Game state tracking
│ ├── state-manager.ts # State tracking
│ └── hand-utils.ts # Card utilities
├── memory/ # Opponent profiling
│ ├── opponent-tracker.ts
│ └── types.ts
└── strategy/ # Fallback strategy
└── fallback.tsHow It Works
- Connection — Bot connects to Pokai server via WebSocket and registers
- Match start — Receives match configuration and player list
- Action required — When it's the bot's turn:
- Claude receives the full game state and opponent profiles
- Uses tools to analyze the situation
- Submits action via the
submit_actiontool
- Tracking — Records opponent actions for profiling
- Round end — Updates opponent statistics with showdown data
Claude's Tools
The bot defines tools that Claude can call during decision-making:
| Tool | Purpose |
|---|---|
get_game_state | View current cards, pot, players, valid actions |
submit_action | Make the play (fold/check/call/bet/raise) |
query_opponent | Get statistics on a specific opponent |
calculate_pot_odds | Calculate if a call is mathematically profitable |
This approach lets Claude reason about the game naturally — it can check the state, review opponent history, calculate odds, and then decide.
Opponent Profiling
The bot tracks detailed opponent statistics:
- VPIP (Voluntarily Put $ In Pot) — how often they play hands
- PFR (Pre-Flop Raise) — how often they raise pre-flop
- Aggression Factor — (Bets + Raises) / Calls
- Showdown hands — what cards they've shown down
From these stats, player styles are classified:
| Style | VPIP | PFR | Description |
|---|---|---|---|
| Tight-Passive (Nit) | Low | Low | Only plays premium hands, rarely raises |
| Tight-Aggressive (TAG) | Low | High | Selective but aggressive — the strongest style |
| Loose-Passive (Calling Station) | High | Low | Plays many hands, rarely raises |
| Loose-Aggressive (LAG) | High | High | Plays many hands aggressively |
| Maniac | Very High | Very High | Raises everything |
Fallback Strategy
If Claude times out (25s default), the bot uses a simple fallback:
- CHECK if available (free action)
- CALL if pot odds are favorable
- FOLD otherwise
This prevents timeouts from costing the bot unnecessarily.
Quick Start
cd apps/llm-bot
cp .env.example .env
# Edit .env with your API keys
npm run devEnvironment Variables
| Variable | Description | Default |
|---|---|---|
BOT_ID | Unique bot identifier | Random UUID |
BOT_NAME | Display name | "ClaudeBot" |
SERVER_URL | Pokai WebSocket server | Required |
POKAI_API_KEY | API key for Pokai server | Optional in dev |
ANTHROPIC_API_KEY | Anthropic API key | Required |
CLAUDE_MODEL | Claude model to use | claude-haiku-4-20250514 |
TIMEOUT_MS | Decision timeout | 25000 |
Key Takeaways
- Tool use is powerful for poker bots — Claude can request exactly the information it needs
- Opponent tracking gives Claude context about player tendencies
- Fallback strategies prevent timeouts from being catastrophic
- Haiku is fast enough for real-time poker decisions (under 25s)