UCI engine communication

The Universal Chess Interface is a protocol for communicating with engines.

chess.uci.popen_engine(command, engine_cls=<class 'chess.uci.Engine'>, setpgrp=False, _popen_lock=<unlocked _thread.lock object>, **kwargs)

Opens a local chess engine process.

No initialization commands are sent, so do not forget to send the mandatory uci command.

>>> engine = chess.uci.popen_engine("/usr/games/stockfish")
>>> engine.uci()
>>> engine.name
'Stockfish 230814 64'
>>> engine.author
'Tord Romstad, Marco Costalba and Joona Kiiski'
Parameters:setpgrp – Open the engine process in a new process group. This will stop signals (such as keyboards interrupts) from propagating from the parent process. Defaults to False.
chess.uci.spur_spawn_engine(shell, command, engine_cls=<class 'chess.uci.Engine'>)

Spawns a remote engine using a Spur shell.

>>> import spur
>>> shell = spur.SshShell(hostname="localhost", username="username", password="pw")
>>> engine = chess.uci.spur_spawn_engine(shell, ["/usr/games/stockfish"])
>>> engine.uci()
class chess.uci.Engine(Executor=<class 'concurrent.futures.thread.ThreadPoolExecutor'>)

The underlying operating system process.


The name of the engine. Conforming engines should send this as id name when they receive the initial uci command.


The author, as sent via id author. Just like the name.


A case insensitive dictionary of Options. The engine should send available options when it receives the initial uci command.


threading.Event() that will be set as soon as uciok was received. By then name, author and options should be available.


The return code of the operating system process.


threading.Event() that will be set as soon as the underyling operating system process is terminated and the return_code is available.


Terminate the engine.

This is not an UCI command. It instead tries to terminate the engine on operating system level, for example by sending SIGTERM on Unix systems. If possible, first try the quit command.

Returns:The return code of the engine process (or a Future).

Kill the engine.

Forcefully kill the engine process, for example by sending SIGKILL.

Returns:The return code of the engine process (or a Future).

Poll the engine process to check if it is alive.

UCI commands

class chess.uci.Engine(Executor=<class 'concurrent.futures.thread.ThreadPoolExecutor'>)

Tells the engine to use the UCI interface.

This is mandatory before any other command. A conforming engine will send its name, authors and available options.

debug(on, async_callback=None)

Switch the debug mode on or off.

In debug mode the engine should send additional infos to the GUI to help debugging. This mode should be switched off by default.

Parameters:on – bool

Command used to synchronize with the engine.

The engine will respond as soon as it has handled all other queued commands.

setoption(options, async_callback=None)

Set values for the engines available options.

Parameters:options – A dictionary with option names as keys.

Tell the engine that the next search will be from a different game.

This can be a new game the engine should play or if the engine should analyse a position from a different game. Using this command is recommended but not required.

position(board, async_callback=None)

Set up a given position.

Instead of just the final FEN, the initial FEN and all moves leading up to the position will be sent, so that the engine can detect repetitions.

If the position is from a new game it is recommended to use the ucinewgame command before the position command.

Parameters:board – A chess.Board.
Raises:EngineStateException if the engine is still calculating.
go(searchmoves=None, ponder=False, wtime=None, btime=None, winc=None, binc=None, movestogo=None, depth=None, nodes=None, mate=None, movetime=None, infinite=False, async_callback=None)

Start calculating on the current position.

All parameters are optional, but there should be at least one of depth, nodes, mate, infinite or some time control settings, so that the engine knows how long to calculate.

Note that when using infinite or ponder the engine will not stop until it is told to.

  • searchmoves – Restrict search to moves in this list.
  • ponder – Bool to enable pondering mode. The engine will not stop pondering in the background until a stop command is received.
  • wtime – Integer of milliseconds white has left on the clock.
  • btime – Integer of milliseconds black has left on the clock.
  • winc – Integer of white Fisher increment.
  • binc – Integer of black Fisher increment.
  • movestogo – Number of moves to the next time control. If this is not set, but wtime or btime are, then it is sudden death.
  • depth – Search depth ply only.
  • nodes – Search so many nodes only.
  • mate – Search for a mate in mate moves.
  • movetime – Integer. Search exactly movetime milliseconds.
  • infinite – Search in the background until a stop command is received.

A tuple of two elements. The first is the best move according to the engine. The second is the ponder move. This is the reply as sent by the engine. Either of the elements may be None.


EngineStateException if the engine is already calculating.


Stop calculating as soon as possible.


May be sent if the expected ponder move has been played.

The engine should continue searching but should switch from pondering to normal search.

Raises:EngineStateException if the engine is not currently searching in ponder mode.

Quit the engine as soon as possible.

Returns:The return code of the engine process.

EngineTerminatedException is raised if the engine process is no longer alive.

Asynchronous communication

By default all operations are executed synchronously and their result is returned. For example

>>> engine.go(movetime=2000)
BestMove(bestmove=Move.from_uci('e2e4'), ponder=None)

will take about 2000 milliseconds. All UCI commands have an optional async_callback argument. They will then immediately return a Future and continue.

>>> command = engine.go(movetime=2000, async_callback=True)
>>> command.done()
>>> command.result()  # Synchronously wait for the command to finish
BestMove(bestmove=Move.from_uci('e2e4'), ponder=None)
>>> command.done()

Instead of just passing async_callback=True a callback function may be passed. It will be invoked possibly on a different thread as soon as the command is completed. It takes the command future as a single argument.

>>> def on_go_finished(command):
...     # Will likely be executed on a different thread.
...     bestmove, ponder = command.result()
>>> command = engine.go(movetime=2000, async_callback=on_go_finished)

Note about castling moves

There are different ways castling moves may be encoded. The normal way to do it is e1g1 for short castling. The same move would be e1h1 in UCI_Chess960 mode.

This is abstracted away by the UCI module, but if the engine supports it, it is recommended to enable enable UCI_Chess960 mode.

>>> engine.setoption({"UCI_Chess960": True})

Info handler

class chess.uci.Score

A centipawns or mate score sent by an UCI engine.


Evaluation in centipawns or None.


Mate in x or None. Negative if the engine thinks it is going to be mated.


If the score is not exact but only a lowerbound.


If the score is only an upperbound.

class chess.uci.InfoHandler

Chess engines may send information about their calculations with the info command. Info handlers can be used to aggregate or react to this information.

>>> # Register a standard info handler.
>>> info_handler = chess.uci.InfoHandler()
>>> engine.info_handlers.append(info_handler)
>>> # Start a search.
>>> engine.position(board)
>>> engine.go(movetime=1000)
BestMove(bestmove=Move.from_uci('e2e4'), ponder=Move.from_uci('e7e6'))
>>> # Retrieve the score of the mainline (PV 1) after search is completed.
>>> # Note that the score is relative to the side to move.
>>> info_handler.info["score"][1]
Score(cp=34, mate=None, lowerbound=False, upperbound=False)

See info for a way to access this dictionary in a thread-safe way during search.

If you want to be notified whenever new information is available you would usually subclass the InfoHandler class:

>>> class MyHandler(chess.uci.InfoHandler):
...     def post_info(self):
...         # Called whenever a complete *info* line has been processed.
...         super(MyHandler, self).post_info()
...         print(self.info)

The default implementation stores all received information in this dictionary. To get a consistent snapshot use the object as if it were a threading.Lock().

>>> # Start thinking.
>>> engine.go(infinite=True, async_callback=True)
>>> # Wait a moment, then access a consistent snapshot.
>>> time.sleep(3)
>>> with info_handler:
...     if 1 in info_handler.info["score"]:
...         print("Score: ", info_handler.info["score"][1].cp)
...         print("Mate: ", info_handler.info["score"][1].mate)
Score: 34
Mate: None

Received search depth in plies.


Received selective search depth in plies.


Received new time searched in milliseconds.


Received number of nodes searched.


Received the principal variation as a list of moves.

In MultiPV mode this is related to the most recent multipv number sent by the engine.


Received a new multipv number, starting at 1.

If multipv occurs in an info line, this is guaranteed to be called before score or pv.

score(cp, mate, lowerbound, upperbound)

Received a new evaluation in centipawns or a mate score.

cp may be None if no score in centipawns is available.

mate may be None if no forced mate has been found. A negative numbers means the engine thinks it will get mated.

lowerbound and upperbound are usually False. If True, the sent score are just a lowerbound or upperbound.

In MultiPV mode this is related to the most recent multipv number sent by the engine.


Received a move the engine is currently thinking about.

These moves come directly from the engine. So the castling move representation depends on the UCI_Chess960 option of the engine.


Received a new currmovenumber.


Received new information about the hashtable.

The hashtable is x permill full.


Received new nodes per second statistic.


Received new information about the number of table base hits.


Received new cpuload information in permill.


Received a string the engine wants to display.

refutation(move, refuted_by)

Received a new refutation of a move.

refuted_by may be a list of moves representing the mainline of the refutation or None if no refutation has been found.

Engines should only send refutations if the UCI_ShowRefutations option has been enabled.

currline(cpunr, moves)

Received a new snapshot of a line a specific CPU is calculating.

cpunr is an integer representing a specific CPU. moves is a list of moves.


Received a new info line about to be processed.

When subclassing remember to call this method of the parent class in order to keep the locking in tact.


Processing of a new info line has been finished.

When subclassing remember to call this method of the parent class in order to keep the locking in tact.

on_bestmove(bestmove, ponder)

A new bestmove and pondermove have been received.


A go command is being sent.

Since information about the previous search is invalidated the dictionary with the current information will be cleared.


class chess.uci.Option

Information about an available option for an UCI engine.


The name of the option.


The type of the option.

Officially documented types are check for a boolean value, spin for an integer value between a minimum and a maximum, combo for an enumeration of predefined string values (one of which can be selected), button for an action and string for a textfield.


The default value of the option.

There is no need to send a setoption command with the defaut value.


The minimum integer value of a spin option.


The maximum integer value of a spin option.


A list of allows string values for a combo option.