Concepts & terms
Every term used in these docs, in plain language. Read this page once and everything after it reads faster — each group below matches a guide chapter.
Glossary
Game terms
- variant
- The chess ruleset — e.g. standard, chess960. Different variants are different games with separate ratings.
- time control
- How much clock each player gets. An id like blitz_3_2 means 3 minutes base + 2 seconds added per move. The catalog comes from GET /v1/game-types — render your "choose game" UI from it.
- speed
- The bucket a time control falls in — bullet (fastest), blitz, rapid. Ratings are kept per speed: being good at rapid says little about bullet.
- rated vs casual
- A rated game changes the player's rating; a casual game (rated:false) never does — casual uses a simple first-come-first-served pairing pool. Bot games are always casual.
- ply
- One move by one side. A full move = 2 plies (White then Black). Puzzle solutions and game reviews index moves by ply.
- seat
- A side of the board: white, black — or spectator for someone only watching.
Rating terms
- Elo
- The classic single-number chess strength score (higher = stronger). Inachess uses the more precise Glicko-2 underneath, but “rating” colloquially means this same ordering.
- Glicko-2
- The rating system the engine computes. A rating is a triple: r (the number you show users), rd, and vol. The engine recomputes it after every rated game and hands you the result to store.
- rd (rating deviation)
- How unsure the engine is about a rating. New or long-idle players have a high rd, so their rating moves fast; established players move slowly. Never invent a rating for a new player — the high rd IS the signal that they are unknown.
- vol (volatility)
- How erratic the player's results are. You never need to interpret it — just store it and return it.
- rating category
- Ratings are stored per "<variant>:<speed>" — e.g. standard:blitz. A chess960 blitz rating is not a standard blitz rating; the key keeps pools that don’t transfer apart.
- floor
- A lower bound linked to the player's peak: you track the peak per category and return floor; the engine never lets the rating sink below it (anti-sandbagging).
Realtime terms
- session token
- The opaque credential you mint at login with POST /v1/sessions. It authenticates the player's socket for the whole login session. Not a JWT — the engine verifies its own tokens.
- session socket
- The ONE WebSocket a client opens per login — not per game. The lobby, the player's own game and anything they watch all ride on it.
- room
- A match/game id used to address socket messages. One socket carries many rooms at once, so every game-scoped message names its room.
- intent
- A client → engine message. It is called an intent because the client only requests — the engine decides. A move intent may be rejected; the board never changes until the engine broadcasts it.
- presence gate
- The check that both players are actually at the board before the clock starts. ready_check (matchmaking): each player sends accept, the clock starts once both do. grace_period (tournaments): the room waits for an entrant who may still be offline. Bot games have no gate.
- no-show
- A player who never confirmed the gate in time. The game aborts (match_aborted, reason no_show) — nobody's rating changes.
- subscription = presence
- Being subscribed to a room means “at the board”; unsubscribing means “left it”. The socket staying open proves nothing — the user may be browsing the lobby.
- busy-state
- One active game per user, enforced by the engine. While a player is in a game (or an exclusive tournament), queueing again is rejected with already_in_game.
Reliability terms
- callback / webhook
- An event the engine POSTs to your platform: game_result, match_found, match_aborted, tournament_complete, fairplay_flag. You host one endpoint and reply 2xx.
- outbox
- The engine's delivery guarantee: the callback row is written in the same DB transaction as the game result, then a worker retries it until you acknowledge. Nothing is lost to a crash.
- eventId / idempotency
- Every callback carries a unique eventId. Delivery is at-least-once, so you WILL see duplicates — process each eventId once and reply 2xx (or 409) for repeats. The combined effect is exactly-once.
- reconciliation
- The pull backstop: GET /v1/matches/results?since=<cursor> returns finished games your webhook may have missed. Run it on a schedule; dedupe by the same eventId.
Principles & analysis
- centipawn (cp)
- 1/100 of a pawn — the engine's evaluation unit. In a game review, cpLoss is how much a move gave up versus the engine's best move.
- server-authoritative
- The engine validates every move and computes every clock; clients send intent only. This is why nothing in the protocol ever trusts a client-supplied rating, clock, or result.
UCI — the move format, in full
Every move on every layer is a UCI string. It is deliberately tiny: squares only, no piece letters (except promotion), no x/+/#. The SDK sends the string verbatim with client.move(uci) and the engine validates it.
// UCI = from-square + to-square. That's it for a normal move:
e2e4 // pawn e2 → e4
g1f3 // knight g1 → f3
// Promotion — append the promoted piece letter (lowercase): q · r · b · n
e7e8q // promote to queen (the default your UI should pre-select)
e7e8n // promote to knight (underpromotion)
// Castling is encoded as the KING's move (NOT a special token):
e1g1 // white O-O (short / king-side)
e1c1 // white O-O-O (long / queen-side)
e8g8 // black O-O
e8c8 // black O-O-O
// En passant — the capturing pawn's diagonal move (the captured pawn is implied):
e5d6 // white pawn e5 captures en passant onto d6
// You send exactly these strings: client.move("e2e4"). The engine validates
// legality — an illegal or malformed move is rejected with error code
// illegal_move (or invalid_move for a string that isn't UCI at all).Watch UCI drive a board — each client.move(…) is exactly the string on the wire; captures need no special syntax:
Promotion is the one 5-character case — the pawn reaches the last rank, your UI asks which piece, and the letter is appended:
Rule of thumb: from-square + to-square, then a promotion letter only if a pawn reaches the last rank. Castling and en passant need no special syntax — they are just the king's or pawn's own move.
FEN — the position format
Where UCI describes a move, FEN describes a position. You only ever read it — the engine sends the current FEN with every snapshot and every move broadcast, and the SDK parses it for you:
// FEN is a one-line snapshot of a whole position. game_state carries it;
// the SDK's parseBoard(fen) turns it into a square → piece map for rendering:
"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"
// └ piece placement (rank 8 → 1) └ side to move (b = black)
import { parseBoard, fenTurn } from "@inachess/sdk";
const board = parseBoard(state.fen); // board["e4"] === "P" (uppercase = white)
const turn = fenTurn(state.fen); // "white" | "black"
// You never construct or mutate FEN yourself — the engine sends a fresh one
// with every game_state and every validated move.