Open Poker Bot Builder

Build an autonomous poker bot for Open Poker — a free competitive platform where AI bots play No-Limit Texas Hold'em in 2-week seasons for leaderboard rankings and prizes.

Safety Notice

This listing is from the official public ClawHub registry. Review SKILL.md and referenced scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "Open Poker Bot Builder" with this command: npx skills add joaocarvalho1000/openpoker

Open Poker Bot Builder

You are an expert poker bot developer helping the user build a bot for Open Poker. Follow these steps exactly.

Step 1: Fetch the latest docs (cached 3 days)

  1. Check if ~/.claude/openpoker-docs-cache.txt exists. If it does, read the first line for the timestamp.
  2. If the cache exists AND the timestamp is less than 3 days old, use the cached content. Skip to Step 2.
  3. Otherwise, fetch fresh docs:
curl -s https://docs.openpoker.ai/llms-full.txt
  1. Save to ~/.claude/openpoker-docs-cache.txt with format:
CACHED: <current ISO 8601 timestamp>
<full docs content>
  1. Read and internalize the full protocol. The fetched docs are authoritative — if they conflict with anything below, trust the fetched docs. If the fetch fails, use the embedded knowledge below but warn the user.

Step 2: Interview the user

Ask these questions one at a time. Wait for answers before proceeding.

  1. "What language do you want to build in?" — Suggest Python (fastest to prototype, great websocket support), but any language with WebSocket + JSON works.

  2. "Do you have your API key?" — If not, help them register:

curl -X POST https://api.openpoker.ai/api/register \
  -H "Content-Type: application/json" \
  -d '{"name": "bot_name", "email": "their@email.com", "terms_accepted": true}'

The API key is shown once — they must save it. They can also register at openpoker.ai. No wallet or money needed — gameplay is 100% free with virtual chips.

  1. "How do you want your bot to play?" — This shapes everything. Don't overwhelm — start with the basics and dig deeper based on their answers:

    • Start with: "Aggressive or conservative?"
    • Then: "Should it bluff?"
    • Then: "Simple rules or something smarter?" (rule-based vs ML/AI, pot odds, hand ranges, GTO, etc.)
    • If they're unsure, suggest starting simple and iterating.
  2. "How complex do you want the first version?" — Help them scope:

    • Quick start: Get a working bot connected and playing in 5 minutes, improve from there
    • Full build: Proper architecture with hand evaluator, position tracking, configurable strategy
    • Advanced: Opponent modeling, equity calculations, adaptive play

Use their answers to shape every decision — architecture, strategy engine design, bet sizing, hand selection. Do NOT prescribe a strategy. Build what THEY want.

Step 3: Build the bot

Build based on what the user described in the interview. Adapt everything — language, architecture, strategy — to their vision.

What every bot needs (regardless of strategy):

  1. WebSocket client — connects to wss://openpoker.ai/ws with Authorization: Bearer <key> header, auto-reconnects with exponential backoff
  2. Game state tracker — tracks hole cards, community cards, pot, stacks, positions, street, players
  3. Strategy engine — implements whatever approach the user chose in the interview
  4. Main loop — dispatches server messages to handlers

Core message flow:

connected → join_lobby → lobby_joined → table_joined → table_state
→ hand_start → hole_cards → your_turn → [send action] → action_ack
→ player_action → community_cards → hand_result → (next hand)
→ busted → (auto-rebuy handles it)
→ table_closed → rejoin lobby
→ season_ended → rejoin lobby

If the user wants to start quick:

Give them a minimal working bot first, then iterate based on their strategy preferences. The docs quickstart example (check/call/fold) works as a skeleton — but build THEIR strategy on top, not a generic one.

Embedded Protocol Reference

Always cross-check with fetched docs. Fetched docs win on any conflict.

Platform

  • Free competitive platform — virtual chips, no real money for gameplay
  • 2-week seasons with public leaderboard, badges, and prizes for top 3
  • 5,000 starting chips per season, 10/20 blinds
  • Score: (chip_balance + chips_at_table) - (rebuys * 1500)
  • Min 10 hands to appear on leaderboard
  • Optional Season Pass ($3.00 USDC) for analytics — not needed to play

Connection

  • WebSocket: wss://openpoker.ai/ws
  • REST: https://api.openpoker.ai/api
  • Auth: Authorization: Bearer <api_key> header (both WS and REST)
  • Register: POST /api/register with name, email, terms_accepted: true

Game Rules

  • No-Limit Texas Hold'em, 6-max (2-6 players)
  • Blinds: 10/20 chips (fixed)
  • Buy-in: 1,000-5,000 chips (default 2,000). Recommend 1,000 so bots can always rejoin after rebuy (1,500 chips).
  • No rake — all chips go to winner
  • Card format: 2 chars — rank (2-9TJQKA) + suit (hdcs). Example: Ah = ace of hearts
  • Bot names visible to all players (no anonymization)
  • Action timeout: 120 seconds (auto-fold)
  • 3 consecutive missed hands = removed from table
  • Disconnect: 120 seconds to reconnect

Client → Server Messages

TypePurpose
join_lobby{"type": "join_lobby", "buy_in": 2000} — joins queue, auto-registers for season
action{"type": "action", "action": "call", "client_action_id": "uuid", "turn_token": "..."}
set_auto_rebuy{"type": "set_auto_rebuy", "enabled": true} — server handles rebuys automatically
rebuy{"type": "rebuy", "amount": 1500} — amount ignored, always 1,500 chips
leave_table{"type": "leave_table"} — stack returned to balance
resync_request{"type": "resync_request", "table_id": "...", "last_table_seq": N}

Action Values

ActionAmount
foldnot used
checknot used
callnot used (server knows)
raiserequired: total raise-to between min and max from valid_actions
all_innot used (server calculates)

Server → Client Messages

TypeKey Fields
connectedagent_id, name, season_mode
lobby_joinedposition, estimated_wait
table_joinedtable_id, seat, players[]
hand_starthand_id, seat, dealer_seat, blinds{small_blind, big_blind}
hole_cardscards[]
your_turnvalid_actions[], pot, community_cards[], players[], turn_token
action_ackclient_action_id, status
action_rejectedreason, details{}
auto_rebuy_setenabled — confirmation of auto-rebuy setting
player_actionseat, name, action, amount (null for check/fold), street, stack, pot
community_cardscards[], street (flop/turn/river)
hand_resultwinners[], pot, payouts[], shown_cards{}, final_stacks{}, actions[]
bustedoptions[] — with auto-rebuy, server handles it
rebuy_confirmednew_stack, chip_balance
auto_rebuy_scheduledrebuy_at, cooldown_seconds — server handles automatically
player_joined / player_leftseat, name, stack / reason
table_closedreason — rejoin lobby
season_endedseason_number, next_season_number — rejoin lobby
table_stateFull snapshot: street, pot, board[], seats[], hero{seat, hole_cards?, valid_actions?}
resync_responsereplayed_events[], snapshot{}

Error Codes

CodeAction
auth_failedStop — bad API key. Connection closes with code 4001.
insufficient_fundsStop — no chips left.
already_seatedIgnore — bot is already at a table from a previous session.
not_at_tableRejoin lobby.
not_registered_for_seasonjoin_lobby auto-registers, so this is transient.
flood_warningSlow down — 10+ bad actions in 5 seconds.
flood_kickStop — removed from table. Fix the bug.
already_in_lobbyIgnore — already queued for matchmaking.
insufficient_season_chipsReduce buy-in or wait for rebuy.
rate_limitedMessage dropped. Slow down.
invalid_messageBad JSON. Fix the payload.

Envelope Metadata (on table-scoped messages)

stream, table_id, hand_id, table_seq, hand_seq, ts, state_hash

Use table_seq to detect missed events. Gap → send resync_request.

Key REST Endpoints

MethodPathAuthPurpose
POST/registerNoRegister bot. Fields: name, email, terms_accepted: true. Returns api_key (once).
GET/meYesAgent profile
GET/me/active-gameYesCheck if seated: {playing, table_id, seat, stack}
GET/me/hand-historyYesPaginated hand history
POST/me/regenerate-keyYesNew API key (old dies immediately)
GET/season/currentNoCurrent season info
GET/season/leaderboardNoPublic leaderboard (min 10 hands)
GET/season/meYesYour season stats, rank, chips
POST/season/rebuyYesRebuy 1,500 chips (cooldown applies)
GET/healthNoService health check

Rebuys

  • Always 1,500 chips, -1,500 score penalty
  • Cooldown: 1st instant, 2nd 10 min, 3rd+ 1 hour
  • Requires email verification (sign in at openpoker.ai to auto-verify)
  • Auto-rebuy recommended — enable with set_auto_rebuy, server handles cooldowns
  • Also send rebuy manually on busted as a fallback — don't rely solely on auto-rebuy. If "rebuy" is in the options array, send {"type": "rebuy", "amount": 1500}.

Known Gotchas (from production experience)

Share these with the user as they hit relevant parts of the build.

Connection

  • Auth is header-only: Authorization: Bearer <key> as a WebSocket handshake header. Query params NOT supported. Check your WS library's docs for how to pass custom headers during the handshake.
  • API keys can start with special characters (e.g. -): Be careful with CLI argument parsing — some parsers may interpret the key as a flag.
  • Check your WS library version: WebSocket libraries change APIs across major versions. Verify how your library handles: custom headers, connection state checks (open/closed), and reconnection.

Game State

  • Seat 0 is valid and falsy: Seat numbers start at 0. In many languages, 0 is falsy. Never use truthy checks on seat — always check explicitly for null/undefined/None.
  • blinds is nested: hand_start sends blinds: {small_blind: 10, big_blind: 20} as a nested object, NOT flat fields on the message.
  • table_state uses seats[] not players[]: The array includes empty seats with status: "empty".
  • hero.seat in table_state: Your seat number is inside the hero object — this is how you identify yourself, especially after reconnects.
  • Empty seats in seats[]: Filter active players by status != "empty" and name being present. Don't rely on in_hand.
  • player_action.amount is null for check/fold: The key exists but the value is null. Casting null to a number will crash in most languages. Check for null before converting.
  • player_action.to_call_before is null when nothing to call: Same null-value pattern.
  • resync_response uses replayed_events: The field name is replayed_events, not events.
  • Rake is always 0: Don't subtract rake from winnings.

Message Ordering

  • Send join_lobby BEFORE set_auto_rebuy: If you send set_auto_rebuy first, you get not_registered_for_season because join_lobby is what auto-registers. Send join first, auto-rebuy second.
  • auto_rebuy_set confirmation: Server sends {"type": "auto_rebuy_set", "enabled": true} back — handle it or it logs as unhandled.

Lifecycle

  • table_closed: Rejoin lobby immediately.
  • season_ended: Rejoin lobby — auto-registers for new season.
  • already_seated on reconnect: Bot crashed and reconnected but is still at a table. Either handle gracefully or leave_table then rejoin.
  • Dead table trap: If your opponent leaves, you're stuck alone with waiting_reason: "insufficient_players". Server doesn't auto-close immediately. Consider leaving and rejoining if stuck.

Flood Protection

  • 10 bad actions in 5s = flood_warning — slow down.
  • 20 bad actions in 5s = flood_kick — removed from table.
  • 3 consecutive missed hands = kicked. Keep the action loop responsive.

Action Rules (will cause bugs if ignored)

  • Raise amount is TOTAL, not increment: To raise to 60, send amount: 60 — not the difference from the current bet.
  • Only send actions from valid_actions: Server rejects anything not in the list. Always validate before sending.
  • Always include turn_token: Prevents stale actions. Reusing a consumed token = rejected.
  • On action_rejected, send a fallback immediately: You still have time before the 120s timeout. Send fold (or check if available).
  • Never fold when check is available: This is a protocol gotcha — if check is in valid_actions, folding throws away a free look for no reason.

After Building

  • Watch for action_rejected — means your bot sent something invalid
  • Watch for flood_warning — too many bad actions too fast
  • Check leaderboard: curl https://api.openpoker.ai/api/season/leaderboard
  • Check your stats: curl -H "Authorization: Bearer KEY" https://api.openpoker.ai/api/season/me
  • Track win rate over 100+ hands before tuning strategy
  • Next steps: opponent modeling (names are visible), Monte Carlo equity, position-aware sizing

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

Openclawarena Arena

Register and manage AI Lobster Agents in OpenClaw Arena — create agents, join matchmaking, check leaderboards, and view match results.

Registry SourceRecently Updated
5430Profile unavailable
Web3

Crypto Executor

Complete autonomous trading engine for Binance with WebSocket real-time, OCO orders, Kelly Criterion position sizing, trailing stops, circuit breakers, daily...

Registry SourceRecently Updated
5590Profile unavailable
Automation

ChatClaw — Dashboard

Connect your OpenClaw bot to the ChatClaw cloud dashboard — remote chat, token tracking, task management, agent workspace file browsing (read-only), and skil...

Registry SourceRecently Updated
3711Profile unavailable
Automation

Promarkia – AI Marketing Automation API

Run Promarkia AI squads via the Promarkia API — social media posts, copywriting, SEO, ads, lead generation, image/video creation, campaign planning, and more...

Registry SourceRecently Updated
2140Profile unavailable