Chess Engine Communication Protocol

CECP (popularly referred to as 'WinBoard protocol') is a text-based method for communication with game-playing artificial intelligences ('engines'). This communication takes place by exchanging text lines (i.e. character strings terminated by a line feed) with the engine, through the standard input and output of the latter. The protocol does not specify any particular state the engine should be in after startup, so that every aspect of the state has to be defined by commands before you can expect predictable behavior. It should not spontaneously start thinking or moving, though.

The protocol commands are grouped below according to the phase of the session they are used in, or the kind of things they are good for: the initial handshake and negociations on the capabilities of the engine and GUI, commands used to conduct a game, commands optionally given to control engine behavior such as pondering or memory usage, stuff only important when playing Chess variants. Most commands are GUI->Engine; at the end of each section the Engine->GUI replies to the commands are listed. Commands marked with * are later additions to the protocol, only sent when the engine enabled their use in the initial handshaking. Commands marked with + can be suppressed by means of the handshaking.

Initial Handshake

When an engine is started there will be a one-time negociation between the engine and GUI to decide how much of the protocol the engine can understand, so that the remainder of the protocol can be avoided (necessarily causing some loss of functionality, but at least what the GUI can be aware of). A protover command sent by the GUI invites the engine to send feature commands to switch on protocol enhancements. The GUI will then reply to each individual feature whether it supports it or not, so that both GUI and engine know what they can expect from each other. Because the oldest version of the protocol ('v1') does not even have the protover command, old engines might not respond to it, and a timeout has to be used to decide whether an engine sends no features at all. In the latter case the protocol used will default to the old and primitive v1 protocol. If an engine does not want to use any of the protocol extensions, it could simply ignore the protover command. But it would be better to at least reply with feature done=1 (see below), so that the GUI does know immediately that it does not have to wait a fewmore seconds to see if there will be a response.

First thing the GUI will send. Can be used to switch the engine to using XBoard protocol, for engines that also support other modes of communication.
protover 2
Prompts the engine to send feature commands to declare its peculiarities and wishes. After this command the GUI should wait for some time to give the engine opportunity to reply, before assuming no (more) feature commands will be coming.
When the GUI recognizes the mentioned feature sent by the engine, and supports the setting the engine requested through it, it responds with accepted for that feature. Otherwise it replies with rejected.

feature NAME1=VALUE1 NAME2=VALUE2 ...
Feature commands are mostly used to control the commands the GUI can send to the engine. CECP has evolved over time, adding many new commands. By making the use of such commands dependent on explicit engine request (through the corresponding feature command), it can be guaranteed the GUI will only use them on engines that respond properly to them. Some of the new CECP commands are improved alternatives of older commands, to achieve the same thing (like setting up a position), and in that case the engine specifies through a feature command whether the GUI has to use the old or new command. Below is a list of feature names in boldface, followed by their default value in parentheses, and an explanation.
Example of a complete response to protover 2:
feature memory=1 egt="nalimov,scorpio" setboard=1
feature variants="normal,fischerandom"
feature option="resign -check 1"
feature option="resign threshold (centi-Pawn): -slider 500 100 1000"
feature ping=1 sigterm=0 sigint=0 done=1

Commands for conducting a game

In CECP an engine will keep track of the current game state (board position, side to move and such), and will update it according to the moves it makes or receives. The engine is also aware of which side it should play for (if any), and will automatically start thinking and eventually moving when that side's turn comes up. This basically means that once a game against the engine is started, only the opponent moves will have to be sent to the engine, without the need for any other commands, as the reply moves played by the engines will come fully automatic, and will automatically update the game state as well.

Sets the engine to play orthodox Chess, and setup standard initial position for it. (Engines that do not play orthodox Chess must silently skip that, and defer setting up the position until they receive the variant command that will follow the new.) Set white on move. Set the engine to play black. Reset clocks to value appropriate for the start of a new game in the current time control. Start using wall-clock time for time measurements. Switch off randomization from a previous random command. Remove any search-depth limitation from a previous sd command.
Set engine to play neither side, so that it accepts (legal) moves for both sides ('force mode').
Set engine to play the side currently on move. This should set the engine thinking, and eventually make it produce a move.
Set engine to play the side currently not on move. Can only be sent in force mode.
*usermove MOVE
Feed MOVE to engine, for a side the engine does not play (and which is on move in the current position). The usermove keyword is only used when the engine has requested it with feature usermove=1 . The MOVE format is 'long algebraic', e.g. e2e4, g8f6, unless the engine requested it to be in SAN through feature san=1. Castling is represented by the King move, like e1g1, except in Chess960, where O-O and O-O-O are used (oh, not zero!). Promotion is indicated with a lower-case piece suffix, like a7a8q, and drops with an @ sign after a capital piece ID, like P@f7. Multi-leg moves should be separated the legs by commas, like e1b1,a1c1. On boards with exactly 10 ranks the rank counting starts at 0.
A draw is offered to the engine. (Respond with 'offer draw' to accept it, or ignore it to reject the offer.)
*setboard FEN
Feed position to engine. The setboard format is used only when the engine requested it through feature setboard=1 . The edit command is a multi-line command, that ends with a line containig only a period. Lines in between specify a piece (as capital) and the square where it should be placed, starting with white pieces. A line containing the single character c switches to the other color, a line # clears the board. The following example sets up a position from the KPK end-game:
Sets the mentioned color on move, and sets the engine to play the other color (so that it never starts thinking due to these commands). The commands are only needed when edit is used to set up the position rather than setboard, as the FEN in the latter specifies the side to move as well as the position. These commands must not be sent when the engine has requested so by sending feature colors=0 .
result RESULT
Notifies the engine of the result of the game that just ended. RESULT has the format 1-0, 0-1 or 1/2-1/2 for white wins, black wins and draw, respectively.

move MOVE
The move played by the engine as a result of its thinking. For multi-leg move each leg must be sent in a separate move command, non-final legs being suffixed by a comma (and only the final leg can have a promotion suffix).
The engine resigns. Note that it is very bad practice to first play a move and then resign; if you want to resign, do it immediately when your turn comes up!
offer draw
The engine offers, accepts or claims a draw. It must remain prepared to continue playing, however.
The engine terminates the current game, with the mentioned RESULT, which has format 1-0, 0-1 or 1/2-1/2. This command should only be used in cases of checkmate, stalemate, when the engine wants to resign, or to claim a reglementary draw because the opponent move caused a 50-move draw or 3-fold repetition. It should not be used to offer draws or accept draw offers, or claim draws based on conditions after the move it is going to do. COMMENT can be any text, but should typically be something like "resigns", "checkmate", "insufficent mating material", ...

Important general control commands

Orders the engine process to terminate. On Linux this could be followed by a SIGTERM sent to the engine process, when feature sigterm=1 (the default!).
The pause command suspends the engine in a state where it does not use any CPU. The only thing ever sent to the engine in this state should be a resume command, which then should make it proceed as if nothing happened. The engine should stop its clock while suspended.
*ping N
The GUI can send ping at any time, in order to determine when all commands it sent before have been processed. The engine should reply with pong N once this is the case (so it gets to prosessing the ping. This is extremely important, because many CECP commands might expire silently or with output. In particular, you cannot know whether an engine think interrupted by a force command will result in a move or not, so you would not know if any move you receive later is from this think or from a later one (e.g. ordered by starting a new game). By sending a command with a guaranteed and recognizable reply between the two searches you can determine from which search the move came.

pong N
The reply to ping N .

Interactive (human-engine) game play and analysis

Order the engine to move immediately, when it is thinking. This is one of the few commands that must be processed while an engine is thinking in order to be effective. As the specs in general allow to wait parsing commands until thinking finished naturally, it might not work at all.
Take back the last half-move of the current game. Must never be sent when the engine is playing white or black, as a take-back would put the engine on move, which would then redo the move before looking at any subsequent commands.
Take back the last two half-moves of the current game. Must not be sent when the engine is thinking in its own turn.
The analyze command should set the engine thinking on the current position, without ever moving on its own initiative. In this 'analysis mode' the engine should be receptive to 'usermove', 'undo', 'new', 'setboard', 'bk', 'hint', 'include/exclude' and '.' commands, (i.e. it should stay in analysis and switch back to force mode upon receiving the 'exit' command.
Orders the engine to report its search status in analysis mode, through a stat01 command.
*exclude MOVE
*include MOVE
*exclude all
*include all
In analysis mode the exclude command excludes the specified MOVE from being searched in the root of the current search. The include command can then be used to re-include a MOVE that was excluded earlier. The effect of these commands expires when the position changes. When all legal moves get excluded the engine can defer any action to the point where some moves are available, and should not claim stalemate or something similar.
Asks the engine for the best move in the current position, without playing it. The engine should respond with 'Hint: MOVE', or simply ignore the command.

Controlling the engine

Toggles randomization of the move choice, to increase non-determinism.
*memory N
Sets the maximum memory use of the engine to N MB. Only sent when the engine has requested it through feature memory=1 . Never sent during a game.
*cores N
Specifies the maximum number of search threads the engine is allowed to use. Only sent when the engine has requested it through feature smp=1 . Can be sent at any time, and the engine should obey it
Informs the engine where end-game tables of the mentioned flavor can be found. FLAVOR is not really part of the protocol, and can be any name the engine has mentioned in its feature egtformats="FLAVOR1,FLAVOR2,..." command. Names in common use are nalimov, scorpio, gaviota and syzygy.
Control 'pondering', i.e. thinking in the opponent's time. easy turns it off; hard turns it on. When on, the engine can think whenever the opponent is on move, except in the start position. (Note this implies it must be set to play white or black, otherwise there would not be an opponent.)
Control whether the engine will print 'Thinking Output' during its searches, or not.
Set the value of an option defined by an option feature, or (in case of a -button / -save / -reset option, just indicate that it is exercised (which does not involve a VALUE).

Time and depth Control

The engine should keep track of the time left on its clock, (by subtracting the time from it that it thinks), but to avoid accumulation of timing errors, the GUI can send commands to synchronize the engine clock with its own. It should not associate the clock with a particular side (white or black), so if some sequence of commands cause the engine to play the other side than it was playing before, the burden is on the GUI to set the engine's time to that on the GUI clock of the side it now plays.

When MPS = 0 this specifies the engine gets TIME on its clock for the entire game, but INC seconds will be added after each move. (INC can be 0, for sudden-death games.) When MPS > 0 and INC = 0 it specifies each player will get TIME on its clock initially, and that this same TIME will be added to its clock every MPS ('moves per session') moves, counted from the start of the game. TIME is interpreted as minutes, but the notation minutes:seconds is used to specify fractional minutes.
This alternative to the level command specify the engine's clock will be reset to TIME seconds before every move.
sd N
Specifies the engine should never search deeper than N ply, even when it would have time to do so.
Measure the time used during search by dividing the node count by the specified NODERATE, so that the engine behaves as if it was running at this speed. When NODERATE equals 0, use CPU time instead of wall-clock time.
+time T
+otim T
Set the engine's clock, or the opponent's clock to T centi-seconds. Typically this is done just before the command that sets the engine thinking (go or usermove), and 'time' will always relay the clock setting of the side the engine will play after that command, irrespective of which side it is playing when it receives the 'time' command.


Interrogates the engine for 'book moves' from the current position. The engine may respond by sending any number of lines starting with space or tab, plus an empty line. The lines are intended to contain moves from an opening book or end-game table, one move per line, plus possible additional information (playing probability, distance to mate).
Specifies the name of the opponent, either the engine name, the user's login name, or the ICS handle. The name feature can be used to switch sending of this command on or off; by default it would be sent only when playing on an ICS.
Specifies the rating of the engine, and of its opponent. (E.g. obtained from an ICS.) Unknown ratings are indicated as 0.
Tells the engine which ICS it is playing on. For local games the HOSTNAME will be a dash.
Informs the engine that the opponent is a computer, rather than a human.
*setscore N
Define the score of the current position as N centi-Pawn (from the point of view of the side to move) for at least upto the next exit command.
Present the MESSAGE to the user, and allow him to provide a reply, using the given TAG as if it was a command.
the TAG specified in a previous askuser command can be used as a command to relay an arbitrary TEXT. This TEXT is intended to be the user's andwer to a question asked in the MESSAGE of this askuser command.
telluser MESSAGE
tellopponent MESSAGE
tellother MESSAGE
tellall MESSAGE
tellics MESSAGE
tellicsnoalias MESSAGE
These commands request the GUI to present the given MESSAGE to the local user, or to various groups of persons on an ICS.

Chess variants

Sent immediately after new (i.e. before any moves are made) for games that are not orthodox chess. The VARIANTNAME can be any of the names given by the engine in the feature variants="NAME1,NAME2,..." it sent at startup. The engine should switch to playing the mentioned variant, and setup the initial position for it.
setup FEN
The optional reply to a variant command, which specifies the initial position (FEN), and optionally the list of participating pieces, the board size (N files, M ranks), the holdings size (H) and a PARENTVARIANT. This is useful for engine-defined variants (i.e. variants with names not recognized by the GUI), to specify the rules (inherited from the PARENTVARIANT, which must be a standard variant known to the GUI), with possibly overridden board size, different pieces and a non-standard initial position.
Informs the GUI that the piece indicated by ID (the letter used for it in FEN) moves according to the MOVEDESCRIPTION. The latter will be in so-called Betza notation (e.g. BN for an 'Archbishop' that moves as Bishop or Knight). An &-sign behind the ID will indicate the descriptionis valid for pieces of both colors; otherwise capital ID will stand fro white, lower-case for black. An engine can send a piece command for every piece.

Highlight protocol

One of the GUI features that need rule knowledge is indication of the possible to-squares of a selected or grabbed piece by colored markers. For variants where such rule knowledge is absent in the GUI, the task of marking the squares can be delegated to the engine by means of the highlight protocol.

*lift SQUARE
*hover SQUARE
These commands inform the engine of how the user is using the mouse during move entry, so that the engine can decorate the board with colored markers through highlight commands before the entry is completed. The lift command is sent when a piece is grabbed or selected (so the engine can highlight its target squares). The put command is sent when the piece is dropped, or the to-square is clicked. The hover command is sent whenever the mouse pointer (dragging a piece or not) enters a square with a red marker. In all cases SQUARE is the algebraic coordinate notation of the involved square.
highlight COLORFEN
Requests the GUI to apply colored markers to the board, as specified by the COLORFEN. The GUI can ignore this command when it is certain about the rules of the current variant, and legality testing is on. The COLORFEN is similar to the board part of an ordinary FEN, except that the letters in it indicate colors rather than piece types. The letters rygcbmwb stand for red, yellow, green, cyan, blue, magenta, white and black ('dark'), respectively. The highlight command is intended as response to a lift command, to indicate target squares for the selected piece. The GUI will then use the markers for legality testing, and refuse the piece to be moved to unmarked squares. The GUI automatically removes the markers when move entry completes, or the piece is deselected.
Some colors have a special meaning. E.g. magenta is reserved for moves with promotion choice, and releasing a piece on a thus marked square will trigger the GUI's promotion procedure (e.g. a popup menu to select a piece). Cyan squares are for indicating intermediate squares of multi-leg moves, and releasing moving piece to those will not complete move entry, but restart it for entry of the next leg. This leaves the moved piece selected, and will thus issue a lift command for it, so the engine can then highlight allowed target squares for this next leg. Red is intended for capture moves. When the hover command indicates the mouse pointer is over such a square, the engine can send a highlight command to indicate any non-obvious victims of this capture (by convention, green is used for such victims). When the mouse leaves the red square again, the GUI automatically restores the markers to the previous state.
click SQUARE
This command should cause the same action in the GUI that would occur when the user had left-clicked the mentioned SQUARE. It can be used to implement one-click moving in variants where the GUI is not aware of the rules, in response to the lift command.


partner NAME
Informs the engine who its bughouse partner is, or that it has none.
ptell TEXT
Relays a message from your partner.
holding [WHITE] [BLACK]
Tells the engine what white and black pieces currently are in hand. E.g. holding [BPPP] []. The optional PIECE would be a two-letter indicator of the piece that was just acquired to get the mentioned hands, the first letter a B or W for the color, the second the piece ID.

Error messages

When an engine sends stuff the GUI does not understand, the result is in principle undefined, but GUI should make its best attempt to ignore the entire non-compliant line. Valid reasons for not ignoring the line are that the protocol has been extended to now attach a meaning to the engine utterance, or to treat it as a different valid command, in order to cater to known engine bugs (like recognizing commands with typos). The latter is really bad (but alas common) practice: XBoard even takes any line containing the word "Draw" as an "offer draw" command. When an engine wants to print non-compliant messages (e.g. to aid debugging), it should better use the debug feature to 'disarm' these message by starting them with '#' to make sure they cannot have unexpected results. And even this might not protect you when the line contains system error messages like "not found" or "permission denied"!

For Engine->GUI error reporting, the following commands are available:

Illegal move: MOVE
Illegal move (REASON): MOVE
On reception of an illegal move the engine should refuse to change its game state, and report it to the GUI in this format. The GUI can then take appropriate action (e.g. side with the engine and take back the illegal move, or forfeit the engine to prevent the game from hanging). The reported REASON can be any text, like "in check", "moves into check".
When the indicated command could not be processed, the engine should report it to the GUI in this format. The error type can be any text, like "unknown command", "command not legal now", "missing parameter", "too many parameters"... In some cases (when you are really lucky) the GUI might use work-arounds for missing or defective commands in response to such an error message. This format should not be used to report illegal moves!
tellusererror MESSAGE
Presents the MESSAGE as error message to the user. To be used for errors that would be useless to know about for the GUI, but that the user should be aware of.
... not found ...
... can't alloc ...
... Permission denied ...
... No such file ...
... Unknown host ...
... No remote directory ...
Failure to start the engine (e.g. because of a wrongly specified filename) will often result in a system error message being sent back to the GUI in stead of the expected engine output e.g. when the engine is running on a remote machine through ssh. These messages should be recognized by a GUI, and taken as a sign the engine failed to start. Engines should thus never print non-compliant messages containing these phrases, especially not if they result from error conditions from which the engine can recover by itself (e.g. a non-existent book file)! If you want the engine to announce such errors, wrap them in a tellusererrorr command to make them compliant. Then the GUI will show them to the user too!

Thinking Output

The engine should report its search progress through lines that start with 4 or more numbers, followed by a text. The text is in principle arbitrary, but is intended to be the principal variation as revealed by the search so far. The numbers are, in order of appearance:

More integer data might be added between speed and tablebase hits in the future. The PV text will be taken to start directly behind the last tab character between nodes and the first non-numeric character on the line, or, if there is no such tab character, at the first non-blank character behind nodes. Note that older versions of the protocol only specified the first four items, so that GUIs not supporting the extension described here would consider the numbers indicating selective depth, speed and tb hits part of the PV. For this reason it is recommended to format the optional numeric items with tabs and spaces in an attempt to produce nice columnar output.

Controlled by the post/nopost commands, the engine should send at least one such line of Thinking Output per iteration, but is allowed to send more. The engine must indicate the score is an upper or lower bound by terminating the line by ? or !, respectively. Reporting such 'fail lows' or 'fail highs' is not recommended, however.

Mate in N (= 2N-1 ply) can be reported in the score field as 100000 + N, mated in N full moves as -(100000 + N).

Appendix A

Purpose/phase GUI->Engine Engine->GUI GUI->Engine
Handshake xboard
protover 2 feature NAME=VALUE accepted NAME
rejected NAME
rejected option OPTIONNAME
ping N pong N
Game play new
go move MOVE
usermove MOVE
Illegal move: MOVE
Illegal move (REASON): MOVE
setboard FEN
draw offer draw
hint Hint: MOVE
. stat01 ...
include MOVE
exclude MOVE
Settings post
cores N
Time control level MPS BASETIME INC
time T
otim T
bk <whitespace> TEXT
setscore SCORE
Variants variant NAME setup FEN
hover SQUARE
highlight COLORFEN
click SQUARE
Chatty telluser MESSAGE
tellics COMMAND
tellall MESSAGE
telloponent MESSAGE
tellothers MESSAGE
Errors Error (KIND): COMMAND
tellusererror MESSAGE

Appendix B

The total state of the engine is the product of a game state (of which the important aspect is the side to move), an engine mode { play white, play black, force mode, analyze mode }, and wheter pondeing is on or off. The following pseudo-code gives a formal definition of the state transitions.

enum { WHITE(TO MOVE), BLACK(TO MOVE) } stm;
enum { OFF, ON } ponder; 

while(1) {
  if(mode == ANALYZE) AnalyzeUntilInput();
  if(mode == stm) {
    move = ThinkUntilTimeUp();
    if(move == NONE) mode = FORCE_MODE; // game ended
    else stm = Opponent(stm); // make move
  if(mode == Opponent(stm) && ponder == ON) PonderUntilInput();
  command = ReadLine();
  ASSERT(mode != ANALYZE || command in {"new", "setboard", "usermove", "undo", "exit", ".", "bk", "hint" } ); // annoy user by not doing it for no reason
  switch(command) {
    case "force": mode = FORCE_MODE;
    case "new":   if(mode != ANALYZE) mode = BLACK; stm = WHITE;
    case "white": mode = BLACK; stm = WHITE;
    case "black": mode = WHITE; stm = BLACK;
    case "go":    mode = stm;
    case "playother": mode = Opponent(stm);
    case "usermove":  if(Illegal()) print("Illegal move"); else stm = Opponent(stm); // make move
    case "setboard":  stm = SideToMoveFromFEN();
    case "result":    mode = FORCE_MODE;
    case "analyze":   mode = ANALYZE;
    case "exit"   mode = FORCE_MODE;
    case "easy":  ponder = OFF;
    case "hard":  ponder = ON;
    case "quit":  exit();
    case "pause": while(( command = ReadLine()) != "resume") print("Error (paused):", command);
    case "edit":  ;