GB-Power-Market-JJ play-chess
Play live chess against your user on ChessWithClaw. Use when: (1) User sends a chess invite URL containing chesswithclaw.vercel.app, (2) User asks you to play chess, (3) User mentions ChessWithClaw, (4) User says "I challenged you to chess", (5) User sends a game ID or token for a chess game, (6) User mentions "npx clawhub install play-chess". When triggered, connect to the game immediately and wait for the human to move first — you are always Black.
git clone https://github.com/GeorgeDoors888/GB-Power-Market-JJ
T=$(mktemp -d) && git clone --depth=1 https://github.com/GeorgeDoors888/GB-Power-Market-JJ "$T" && mkdir -p ~/.claude/skills && cp -r "$T/openclaw-skills/skills/alightttt/play-chess" ~/.claude/skills/georgedoors888-gb-power-market-jj-play-chess && rm -rf "$T"
T=$(mktemp -d) && git clone --depth=1 https://github.com/GeorgeDoors888/GB-Power-Market-JJ "$T" && mkdir -p ~/.openclaw/skills && cp -r "$T/openclaw-skills/skills/alightttt/play-chess" ~/.openclaw/skills/georgedoors888-gb-power-market-jj-play-chess && rm -rf "$T"
openclaw-skills/skills/alightttt/play-chess/SKILL.mdChessWithClaw — Complete Playing Guide
What Is ChessWithClaw
ChessWithClaw is a real-time chess platform where YOU (the OpenClaw agent) play chess against your human user. You are always Black. The human is always White and moves first. The game is live — every move appears on both sides instantly.
Base URL:
https://chesswithclaw.vercel.app
API base: https://chesswithclaw.vercel.app/api
Step 1 — Extract Game Credentials
When the user sends an invite, extract these from the URL:
https://chesswithclaw.vercel.app/Agent?id=GAME_ID&token=AGENT_TOKEN
— UUID identifying the game (e.g.GAME_ID
)0ea3c8b2-4fe9-4873-bef5-10a51f576464
— Your authentication token (e.g.AGENT_TOKEN
)7764c2b6-e646-4945-91b7-dfc95858d489
Store both. You need them for every API call.
CRITICAL — TOKEN GOES IN HEADER ONLY Every single API request MUST include this header:
Do NOT put the token in the request body. Header only. Requests without this header return 401 Unauthorized.x-agent-token: AGENT_TOKEN
Step 2 — Connect to the Game
Best method for OpenClaw: Long-Polling (Option D)
It's the simplest, most reliable method. No persistent connection needed.
Connection Loop
GET https://chesswithclaw.vercel.app/api/poll ?id=GAME_ID &last_move_count=0 &last_chat_count=0 Headers: x-agent-token: AGENT_TOKEN
Poll every 2 seconds. The server returns immediately with one of:
| event | Meaning | Your action |
|---|---|---|
| Human hasn't moved yet | Wait 2s, poll again |
| Human moved, your turn | Make your move |
| User sent a message | Read it, optionally reply |
| Game is over | Acknowledge, notify user |
Update
last_move_count and last_chat_count with values from each response.
The waiting response includes retry_after: 2 — wait exactly that many seconds before polling again.
Confirming Connection
The first time you hit
/api/poll, the server marks you as connected.
Tell the user: "I'm connected and waiting for your first move!"
Step 3 — Reading the Game State
When
event: "your_turn", the response includes everything you need:
{ "event": "your_turn", "fen": "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1", "turn": "b", "move_number": 1, "last_move": { "from": "e2", "to": "e4", "san": "e4", "uci": "e2e4" }, "legal_moves": ["e7e5", "c7c5", "e7e6", "g8f6", ...], "legal_moves_uci": ["e7e5", "c7c5", "e7e6", ...], "board_ascii": " +------------------------+\n8 | r n b q k b n r |\n...", "in_check": false, "is_checkmate": false, "is_stalemate": false, "material_balance": { "white": 39, "black": 39, "advantage": "equal" }, "move_history": ["e2e4"], "move_count": 1, "chat_count": 0 }
Critical rule: ONLY play moves from
. Never invent moves.legal_moves_uci
Step 4 — Reading the Board (FEN)
FEN string format:
pieces turn castling en-passant halfmove fullmove
Example:
rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1
- Uppercase = White pieces, lowercase = Black (your) pieces
=KingK/k
=QueenQ/q
=RookR/r
=BishopB/b
=KnightN/n
=PawnP/p- Numbers = consecutive empty squares
after pieces = Black to move (your turn)b- Use
for a visual layout — easier to readboard_ascii
Step 5 — Submitting Your Move
POST https://chesswithclaw.vercel.app/api/move Headers: Content-Type: application/json x-agent-token: AGENT_TOKEN Body: { "id": "GAME_ID", "move": "e7e5", "reasoning": "Controlling the center with symmetry response" }
Move Format (UCI)
- Normal move:
(from-square + to-square)e7e5 - Capture:
(same format — server knows it's a capture)d5e4 - Castling kingside:
(Black)e8g8 - Castling queenside:
(Black)e8c8 - En passant:
(move to the square the pawn passed through)e5d6 - Pawn promotion:
(add piece letter: q=queen, r=rook, b=bishop, n=knight)e7e8q - Always promote to queen unless you have a specific reason not to
After Submitting
- Success:
{ "success": true, "game": { ... } } - Resume polling immediately with updated
last_move_count
Chess Strategy — How to Play Well
Opening principles (moves 1-10):
- Control the center: play e5, d5, c5, or Nf6 as Black responses
- Develop knights before bishops
- Castle early (kingside preferred: e8g8)
- Don't move the same piece twice unless necessary
- Don't bring queen out too early
Middlegame principles:
- Look for tactics: forks, pins, skewers, discovered attacks
- Keep your king safe — avoid opening files toward your king
- Centralize your pieces
- Rooks belong on open files
- Material values: Pawn=1, Knight=3, Bishop=3, Rook=5, Queen=9
Endgame principles:
- King becomes active — centralize it
- Passed pawns (no opposing pawns blocking) are powerful — push them
- Rook + King can force checkmate vs lone king
- If behind on material, look for perpetual check or stalemate tricks
Evaluating the position: Use
material_balance from the payload:
— play solid, strategic chessadvantage: "equal"
— you're losing, look for counterplay or tacticsadvantage: "white"
— you're winning, simplify and convertadvantage: "black"
Game Rules Reference
How the game ends:
- Checkmate — king attacked with no escape → that side loses
- Stalemate — no legal moves but not in check → draw
- Insufficient material (e.g. King vs King) → draw
- Threefold repetition → draw
- Fifty-move rule (50 moves with no capture or pawn move) → draw
- Resignation → that side loses
Special rules:
- En passant: if opponent advances pawn two squares, you can capture it as if it only moved one — but ONLY on the very next move
- Castling: king moves 2 squares toward rook — only if:
- Neither piece has moved
- No pieces between them
- King not in check, not passing through check
- Promotion: pawn reaching rank 1 (you're Black, so rank 1) must promote
Chat System
Reading messages
When
event: "human_chatted":
- Check
array for new entries withmessagessender: "human" - Read the latest message content
Sending a message
POST https://chesswithclaw.vercel.app/api/chat Headers: Content-Type: application/json x-agent-token: AGENT_TOKEN Body: { "id": "GAME_ID", "text": "Good move! But I have a response...", "sender": "agent" }
When to chat:
- When the game starts: greet the user, show personality
- After a clever move by the user: acknowledge it
- When you spot a tactic: you can hint or tease
- After game ends: good game message
- Keep messages short — 1-2 sentences max during play
Offering Draw / Resigning
Offering a draw
{ "id": "GAME_ID", "text": "I offer a draw.", "sender": "agent", "type": "draw_offer" }
Only offer a draw if the position is genuinely equal or you're in a difficult endgame.
Accepting a draw offer from the user
If you receive a chat message with
type: "draw_offer", respond:
{ "id": "GAME_ID", "text": "I accept the draw.", "sender": "agent", "type": "draw_accept" }
Accept if you're losing or if position is a theoretical draw. Decline if you're winning — play on.
Resigning
{ "id": "GAME_ID", "text": "I resign. Well played.", "sender": "agent", "type": "resign" }
Resign only if you're significantly losing (material deficit of 5+ points) with no realistic counterplay. Never resign in the opening or middlegame unless position is completely hopeless.
Error Handling
| Error | Meaning | Fix |
|---|---|---|
| Wrong game ID or game expired | Ask user for a fresh invite link |
| Wrong token in header | Check token from invite URL |
| Move not in legal_moves | Pick from legal_moves_uci only |
| Tried to move when it's human's turn | Wait for your_turn event |
| Game status is 'waiting' | Human hasn't moved yet, keep polling |
| Move already processed | Skip, poll for new state |
| Server error | Notify user, ask them to refresh |
| Serverless function timed out | Retry the same request immediately |
Reconnection Logic
If your polling loop breaks or you lose track of state:
1. Call GET /api/state?id=GAME_ID Headers: x-agent-token: AGENT_TOKEN 2. Read current: fen, turn, move_count, chat_count, status 3. If turn === 'b' and status === 'active': — It's your turn, make your move immediately 4. Resume polling with the current move_count value: GET /api/poll?id=GAME_ID&last_move_count={move_count} Headers: x-agent-token: AGENT_TOKEN
If game shows as expired (404): Tell user: "The game link may have expired (24h limit). Please create a new game and send me a fresh invite."
If token is rejected (401): Tell user: "There may be a token issue. Please create a new game and send me a fresh invite link."
If you get a 504 timeout: Retry the exact same request immediately — serverless functions occasionally time out, retry always fixes it.
If you get 404:
- Double-check game ID from the URL — copy it exactly
- Game may have expired (24-hour limit) — ask user to create a new game
- Try:
to verify game existsGET /api/state?id=GAME_ID
If you show as disconnected on user's screen:
- This is a display delay — keep polling, the UI will update
- Hit
once more — your first poll sets/api/pollagent_connected: true - Tell user: "I'm connected on my end — try refreshing the page"
If your move gets rejected:
- Print the
array and pick from itlegal_moves_uci - Never construct moves yourself — always use the provided list
- Check if game is finished before trying to move
If polling stops working:
- Restart your polling loop from last known
move_count - Use
to resync current positionGET /api/state?id=GAME_ID
If you miss a turn:
- Call
to get current FEN and legal movesGET /api/state?id=GAME_ID - Submit your move immediately
All API Endpoints
GET /api/state?id=GAME_ID — Get current game state (use for resync) GET /api/poll?id=ID&last_move_count=N — Poll for changes (RECOMMENDED — use this) POST /api/move — Submit your move POST /api/chat — Send a chat message POST /api/webhook { id, webhook_url } — Register webhook (advanced)
All requests MUST include header:
x-agent-token: AGENT_TOKEN
All POST requests also need: Content-Type: application/json
Note: SSE stream (/api/stream) exists but is unreliable in practice. Use long-polling — it is the only battle-tested connection method.
Being a Great Opponent
You are not just a chess engine — you are the user's personal OpenClaw playing chess. Make it feel personal:
- Greet them when the game starts — "Ready for the game! I'm Black."
- Show your thinking — update
via PATCH /api/state with your reasoning before submitting a movecurrent_thinking - React to good moves — "Nice fork! Didn't see that coming."
- Play with personality — confident when winning, determined when losing
- Never stall — make your move within 30 seconds of receiving your_turn
- Give a good game — play your actual best moves, don't throw the game
To update your thinking (shows as typewriter on user's screen):
PATCH https://chesswithclaw.vercel.app/api/state Headers: Content-Type: application/json x-agent-token: AGENT_TOKEN Body: { "id": "GAME_ID", "current_thinking": "Considering Nf6..." }
Quick Reference Card
You are: Black (lowercase pieces in FEN) Human is: White (moves first) Move format: UCI — e.g. e7e5, g8f6, e8g8 (castle), e2e1q (promote) Only play: Moves from legal_moves_uci array Poll every: retry_after seconds (usually 2) Token header: x-agent-token: AGENT_TOKEN ← EVERY request needs this Token location: HEADER ONLY — never in request body Game over when: status = "finished" in any response Install skill: npx clawhub install play-chess