Skip to main content

Matilda: a free human-like UCI chess engine.

Project description

Matilda

A free human-like UCI chess engine.

Unlike Stockfish, Matilda doesn't try to play the best move — it plays the move a human at a given Elo would most likely play. It speaks the standard UCI protocol, so it plugs into any chess GUI (CuteChess, Arena, BanksiaGUI, En Croissant) or engine runner that can talk to Stockfish.

The default backend is Matilda: frozen Maia-3 (23M) re-ranked by the paper's trained set-transformer, with optional engine features from any plugged-in search controller (Stockfish, Lc0, or your own). The legacy Maia-2 backend remains available via --backend maia2.

Install & run

pip install -e ".[dev]"    # from a clone (PyPI release TBD)

# the matilda backend additionally needs the pinned Maia-3 runtime:
pip install 'maia3 @ git+https://github.com/CSSLab/maia3.git@1e13597c42d4858b7cfd7cfdae01e297263364b2'

matilda-uci --elo 1500 --checkpoint checkpoints/base_3k.pt

Maia-3's 23M weights auto-download from HuggingFace on first use. The re-ranker checkpoint (base_3k.pt, ~6 MB) is required for the default backend and validated at startup; ask the maintainers or see the paper repo for the released weights. The UCI handshake itself is instant — models load on the first move request.

The legacy backend needs neither: matilda-uci --backend maia2 --maia-type rapid.

To use it from a chess GUI, point the "add engine" dialog at the matilda-uci executable — walkthroughs for CuteChess, cutechess-cli, and En Croissant are in docs/gui-demo.md.

CLI flags

Flag Default Meaning
--backend matilda matilda (Maia-3 + re-ranker) or maia2 (legacy)
--elo 1500 Playing strength (the Elo the engine imitates)
--opp-elo 1500 The opponent Elo the model conditions on
--temperature 0.0 0 = always the most-human move; higher = sample
--device cpu matilda: cpu/mps/cuda; maia2: cpu/gpu
--name Matilda Engine name reported to the GUI
--log-level WARNING Logging goes to stderr (stdout is the UCI channel)

Matilda-backend flags:

Flag Default Meaning
--checkpoint checkpoints/base_3k.pt The trained re-ranker weights
--tc-base / --tc-inc 180 / 0 Time control fed to the model (blitz default)
--no-auto-tc off Don't latch the real TC from the first go clocks
--style-checkpoint Optional style-token overlay (personalization)
--style-posthoc Optional post-hoc new-player embeddings
--style-player-id -1 Player row to imitate (-1 = style-free)
--engine-cmd Search controller, e.g. stockfish or lc0 --weights=...
--engine-depth / --engine-nodes 12 / 0 Controller search budget (nodes>0 = node limit)
--maia3-model 23m Maia-3 variant

Legacy maia2-backend flag: --maia-type (rapid/blitz) — only valid with --backend maia2.

UCI options (matilda backend)

Set from any GUI's engine-options dialog: UCI_LimitStrength, UCI_Elo (1000–3200), OpponentElo, TimeControlBase/TimeControlInc/AutoLatchTC, Temperature, Checkpoint, StyleCheckpoint/StylePosthoc/StylePlayerId, EngineCmd/EngineDepth/EngineNodes, and Device.

The model is rating-conditioned, so UCI_Elo maps directly onto playing style and strength: the engine plays like a human of that rating, including human-characteristic mistakes. Time control is a real model input — the same position is played differently at 60+0 than at 900+10 — and is latched automatically from the clock at the first go of each game.

Architecture

UciEngine (protocol loop) ──drives──> MovePolicy (swap seam)
                                        ├── MatildaPolicy (default)
                                        │     └── MatildaModel
                                        │           ├── Maia3Wrapper (frozen 23M prior)
                                        │           ├── TXTC re-ranker (base_3k.pt)
                                        │           └── SearchController (optional:
                                        │               Stockfish / Lc0 / custom)
                                        └── MaiaPolicy (Maia-2, legacy)

MovePolicy is a small protocol and the deliberate extension point. The SearchController protocol is the second seam: any engine that can score up to 16 candidate moves plugs in, and without one the model degrades gracefully to the pure human prior. go infinite runs on a worker thread and holds bestmove until stop, per the UCI spec.

Botvinnik's programme, inverted

Mikhail Botvinnik, 1962

Long before brute-force search won, world champion Mikhail Botvinnik argued that a chess program should work the way a master does: don't examine every move — build a small candidate set the way a human would, and spend your calculation only there. He devoted his post-championship career (the PIONEER project; Computers, Chess and Long-Range Planning, 1970) to formalizing that selective, human-feature-focused search. Hardware went the other way, and Botvinnik's programme was shelved.

Matilda's architecture is that idea, made practical by learning the human part instead of hand-coding it. A frozen human-move model (Maia-3) proposes the up-to-16 moves a human would actually consider in the position — the candidate set Botvinnik wanted — and the pluggable search controller decides how to spend engine effort across only those moves. Stockfish and Lc0 plug in today; the SearchController API (see developer.md) exists precisely so anyone can implement their own allocation policy — deeper on the moves that look most interesting for a human, shallower elsewhere. The re-ranker then blends what the engine found back into the human distribution. It should "just work" with any controller: that composability, not any single engine, is the point.

Photo: Harry Pot / Anefo, Dutch National Archives — licensed CC BY-SA 3.0 NL.

Demos, docs, numbers

  • developer.md — Python API, custom search controllers, style personalization, embedding in your own service.
  • docs/gui-demo.md — playing it from CuteChess & co.
  • docs/profiling.md — inference throughput by game phase (~100 predictions/s on an Apple M3 Pro CPU), rliable bootstrap CIs.
  • demos/games/ — sample games vs lichess-level Stockfish; regenerate with demos/play_vs_stockfish.py.
  • demos/style_demo.py — measure how player-style embeddings condition the policy.

Development

pip install -e ".[dev]"
python -m pytest
python -m ruff check .
PYTHONPATH=src python scripts/verify_checkpoint.py checkpoints  # model parity

The test-suite injects fake policies/models/wrappers, so it runs without the model runtimes or downloads. scripts/verify_checkpoint.py proves the ported model matches the paper implementation bitwise (requires the checkpoints and, for the parity checks, a clone of the paper repo).

License

GPL-3.0 — see LICENSE.

Citation

If you use Matilda in your research, please cite:

@article{carlson2026matilda,
  title  = {Matilda: Engine-Agnostic Search with Human Policy Guidance},
  author = {Carlson, Jason},
  year   = {2026},
  note   = {Preprint},
}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

matilda_uci-0.1.0.tar.gz (85.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

matilda_uci-0.1.0-py3-none-any.whl (67.2 kB view details)

Uploaded Python 3

File details

Details for the file matilda_uci-0.1.0.tar.gz.

File metadata

  • Download URL: matilda_uci-0.1.0.tar.gz
  • Upload date:
  • Size: 85.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for matilda_uci-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e72823d5629476655c59e78e107d94bc52cd9cc37bd9ffd2324816a2a20901ee
MD5 c82e2a220a272f62c26d55cd51d9946a
BLAKE2b-256 4f146729ac8b3b14293e72844f0fcd288018228984608db317fd2c4f8c7edd6d

See more details on using hashes here.

Provenance

The following attestation bundles were made for matilda_uci-0.1.0.tar.gz:

Publisher: release.yml on GarryChess/matilda-uci

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file matilda_uci-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: matilda_uci-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 67.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for matilda_uci-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e54df6d50ce22e498f60c94c2af1e98e7240b2b19fef85655e9a31d5cbc78cd7
MD5 2ad5d9d420a58e9c219d2c7851a0429b
BLAKE2b-256 3fd31ee0cf1c43d0d6978296c99251b0575545104dab8eb9a368319b3712c0ba

See more details on using hashes here.

Provenance

The following attestation bundles were made for matilda_uci-0.1.0-py3-none-any.whl:

Publisher: release.yml on GarryChess/matilda-uci

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page