Open-source project
CSSLab/maia-chess avatar
CSSLab/maia-chess

Maia Chess: human-like move prediction as Leela weights, not a full engine

Maia is a human-like neural network chess engine trained on millions of human games.

1,237 stars151 forksPythonGPL-3.0

At a glance

What is it?
CSSLab's maia-chess ships nine Leela Chess Zero weight files that predict the average move of a human at a target rating, plus the Python pipeline used to train more. It is a research artifact with a narrow interface: lc0 with search disabled.
Who is it for?
Adopt maia-chess if you need a move-prediction model calibrated to a human rating band and you already run lc0, or if you want to retrain from your own PGN corpus using the move_prediction scripts. Do not adopt it if you want a self-contained engine binary, a search-based opponent, or a supported library.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 114 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem Maia solves: modelling a rating band, not beating it

Standard chess engines optimise for the best move. That makes them useless as a stand-in for a human opponent at a given skill level, because a 1300 player does not play the best move, they play the move a 1300 player tends to play. Maia is trained on millions of human games to output that average move instead. The README states the models cover ELO 1100 to 1900, and that they are stronger than the rating they are trained on because they make the average move of a player at that rating. That sentence is the whole design intent. The target audience is researchers in computational social science and machine learning who need a behavioural model of human play, plus anyone building a sparring partner or a bot for a specific rating band. It is not aimed at players who want a stronger opponent.

Nine weight files and a body: how the models are packaged

The repository is not an engine. The README says the Maias are just brains (weights) and require a body to work, and that body is lc0. The nine final models are saved as Leela Chess neural networks in the maia_weights folder and attached to the v1.0 release, with files named maia-1100.pb.gz through maia-1900.pb.gz. Three of them have public Lichess bots: maia1 targets 1100, maia5 targets 1500, maia9 targets 1900. The rest, 1200 through 1800, exist as downloadable weights without a hosted bot. The data flow at inference is short: lc0 loads the .pb.gz file, receives a position over UCI, and returns a move. With a nodes limit of 1 there is no tree search to speak of, so the move comes from the network's policy output rather than from evaluation of continuations. For Python users there is a second path. move_prediction/maia_chess_backend contains a LeelaEngine class that wraps python-chess and reads config files at move_prediction/model_files/*/config.yaml. That class is the practical way to call the models from a script rather than from a UCI shell.

Running a Maia model with lc0 at one node

The README gives the exact invocation. After installing lc0, you point it at a weights file and then issue go nodes 1. The documented example is lc0 --weights=model_files/maia-1100.pb.gz, followed by go nodes 1, which in the sample output returns bestmove e2e4 at depth 1. The unusual part is the instruction to disable searching. Most engine deployments raise the node count; here the README says a nodes limit of 1 is what the authors use, because search would push the output toward stronger play and away from the human average. The sample output also shows the backend being selected automatically, in that case cudnn-auto switching to cudnn, so GPU acceleration is assumed by the example. There is no configuration file for inference beyond the weights path. If you want the Python route, the config files under move_prediction/model_files/ are what LeelaEngine reads, and python-chess is the board representation it wraps.

Training your own Maia from a PGN corpus

The move_prediction pipeline is the part that turns a PGN file into a new set of weights. The README lists the steps in order. First, environment setup: an optional conda environment from maia_env.yml, and packages from requirements.txt. Second, conversion, which requires two external tools on your PATH: pgn-extract and trainingdata-tool. You then run move_prediction/pgn_to_trainingdata.sh PGN_FILE_PATH OUTPUT_PATH. The README warns that this processing is both IO and CPU intense, and that the script splits the output into training and validation sets. If you want to train on everything, you copy the files from OUTPUT_PATH/validation into OUTPUT_PATH/training. Third, you edit move_prediction/maia_config.yml: input_train and input_test take glob paths into the two directories, the gpu field selects a device if you have more than one, and other training parameters such as the number of layers are set here too. Fourth, you run move_prediction/train_maia.py PATH_TO_CONFIG. Tensorboard logs land in runs/CONFIG_BASENAME/ and the finished model appears in models/CONFIG_BASENAME/, with the final checkpoint being the one with the largest number. The replication path for the paper's models is the same shape but starts from raw Lichess downloads between January 2017 and November 2019, and the README notes that the scripts may need to be run line by line because they have no flow control logic. It also names move_prediction/replication-move_training_set.py as the place where the main shuffling and game selection logic lives.

Determinism, missing opening books, and the limits of the release

The clearest limitation is stated by the project itself: the models play the same move every time. That is why the Lichess bots use opening books, and the README describes those books as still in development. If you deploy a Maia model without an opening book, you get a deterministic opponent that repeats the same first moves in every game, which is a poor fit for anything that needs variety. The second limitation is structural. Because the repository holds weights and training code rather than an engine, every deployment carries an lc0 dependency and a GPU-oriented backend in the documented example. There is no packaged binary and no inference server. Third, the model set stops at 1900 and starts at 1100; nothing in the material covers behaviour outside that band. Fourth, the last release is v1.0 from January 2021, and the README's own banner points readers to Maia-2 and Maia-3 in separate repositories for newer architectures, so this repository is the KDD-era code rather than the current line of work. Treat it as a stable artifact, not an actively evolving one.

Maia against Stockfish: average human move versus best move

The obvious comparison is Stockfish, and the difference is not strength but objective. Stockfish searches a game tree and returns the move with the best evaluated outcome; raising its skill level typically works by limiting depth or adding noise to the evaluation. Maia removes search almost entirely, with a nodes limit of 1, and answers from a network trained on human games. The practical consequence is that Maia's output distribution resembles human play at a rating, including the mistakes, while Stockfish's output distribution is a compressed version of near-optimal play. For a researcher measuring whether a model captures human decision-making, that distinction matters more than any playing strength number. For a user who simply wants a weaker opponent to practise against, Stockfish's skill setting is a single binary with no lc0 dependency, which is a simpler deployment even if the resulting play is less human. The README also notes the models are stronger than their target rating, so a Maia labelled 1500 will not necessarily lose to a 1500 human in the way the label suggests.

Licence, maintenance and the cost of staying on v1.0

The repository is GPL-3.0. If you redistribute a modified version or ship a product built on these weights and this code, the copyleft terms apply to the covered work, and the interaction between a GPL-3.0 model repository and a separately licensed inference engine such as lc0 is a question for your own counsel rather than something this review can settle. On maintenance, the material supports a narrow reading: one tagged release, v1.0 from January 2021, and a README that directs readers to Maia-2 and Maia-3 for newer work. The repository is not archived and shows a push in 2026, but nothing in the supplied material describes a changelog, a deprecation policy, or a support channel beyond the Lichess team and the project website. Upgrade cost is therefore mostly the cost of moving to the successor repositories if you want the Chessformer-based models, which the README describes as outperforming prior models with significantly fewer parameters. Staying here means accepting the 2021 training pipeline, including the pgn-extract and trainingdata-tool dependencies and the line-by-line replication scripts.

Editorial conclusion

Adopt maia-chess if you need a move-prediction model calibrated to a human rating band and you already run lc0, or if you want to retrain from your own PGN corpus using the move_prediction scripts. Do not adopt it if you want a self-contained engine binary, a search-based opponent, or a supported library. Before committing, confirm that lc0 with the cudnn backend loads maia-1100.pb.gz on your hardware, that go nodes 1 produces a legal bestmove, and that pgn-extract and trainingdata-tool are on PATH if you intend to build your own weights.

Official sources

  1. CSSLab/maia-chess on GitHub
  2. License: GPL-3.0
  3. Project website
  4. README
  5. Releases
Community notes

Community notes