Library / SDK
thomasahle/sunfish avatar
thomasahle/sunfish

Sunfish is a chess engine small enough to read, and its own README disagrees with its manifest

Sunfish: a Python Chess Engine in 111 lines of code

3,291 stars582 forksPythonNOASSERTION

At a glance

What is it?
thomasahle/sunfish is a Python UCI chess engine whose stripped source is about 126 lines and whose packed form is about 3 kilobytes. The README asks you to install a test dependency the manifest says was never used, quotes two different Python floors, and describes an NNUE variant that keeps its whole network in one integer.
Who is it for?
Sunfish is worth your time if you want to read a complete chess engine in one sitting or use it as a base to experiment on, which is what its README says people have done with parallel search, evaluation functions and deep learning programs. Treat the line counts as an indicator rather than a specification: 126 lines is the comment and whitespace stripped source, the packed script reports 3310 bytes, and the NNUE variant adds a network.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 39 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 October 4, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Three numbers describe three different artifacts

The repository's short description calls this a Python chess engine in 111 lines of code. The README says that with comments and whitespace removed it takes just 126 lines, and links that claim to compressed.py, the stripped copy in the repository root. The packing section reports a third figure: building a self-extracting script prints Total length: 3310, and the surrounding text calls it about 3kb. None of the three contradicts the others, because each counts something different, a normal source file, the same file stripped of everything but code, and a shell stub with the engine embedded. What it does mean is that the headline number is not a property you can reproduce from the repository without deciding which artifact you are measuring. The stripped file is committed, so you can check the 126 yourself; the 3310 bytes depends on the packer, which lives in tools/build/pack.sh.

The engine has no dependencies, the play interface does

The manifest is careful about this split and says so in a comment. The engine module itself has no dependencies; the default sunfish entry point is the play interface, and that one needs python-chess, pinned exactly at chess==1.9.4. Two console scripts are installed. sunfish maps to sunfish_ui.fancy:run, which is the board you use to play, and sunfish-uci maps to sunfish:main, the protocol endpoint a GUI or a tournament tool talks to. Packaging declares py-modules as sunfish and packages as sunfish_ui, and it deliberately excludes the tools directory, with the stated reason that tools is far too generic a name for a distribution to claim in site-packages. The same package therefore ships two of the repository's directories and drops the third, which is why a from-source checkout can do things an installed copy cannot.

The test instructions install a package the manifest disowns

The testing section tells you to sync dependencies with uv sync, and gives the pip equivalent in a comment on the same line: pip install chess tqdm pytest pytest-asyncio. The manifest's own development group lists chess at 1.9.4, tqdm at 4.67.1, pytest and flake8, with a comment explaining what each is for, and then states that no async tests exist and pytest-asyncio was never consumed. So the documented pip fallback installs four packages where three are used, one of them pinned in the manifest and two of them not pinned there at all. Two smaller mismatches sit alongside. The test commands name python3.12 explicitly, while requires-python is 3.10 or newer, and a footnote elsewhere in the README says modern sunfish requires Python 3.8 or newer because the code uses the walrus operator. Three floors, one of them in the same file as the other two.

Packed to three kilobytes with a reduced UCI dialect

The packing section builds a single self-extracting executable from the engine:

bash
tools/build/pack.sh sunfish.py packed.sh

The script prints Total length: 3310 and the result is run as ./packed.sh. What it speaks is not the full protocol: the packed version uses a simplified UCI protocol defined by the TCEC 4k rules, and the sample session in the README shows how little of the protocol survives. The only command sent is go wtime 1000 btime 1000 winc 1000 binc 1000, and the reply is three lines: an info line at depth 1 with score cp 0 and a principal variation of d2d4, then bestmove d2d4. A GUI that expects options, multi-pv output or analysis windows will find none of them here. That is the point of the artifact, since 4k chess rules exist to make tiny engines comparable, but it does mean the packed build and the normal build are not interchangeable behind the same interface.

The launcher picks your interpreter, and the README corrects itself

Starting the engine is not a choice you make directly. The launcher at the top of sunfish.py runs with pypy3 if it is installed, which the README calls recommended and much stronger, and falls back to python3 otherwise. The package you installed is therefore not necessarily the one that ran, and the difference is quantified later in the README: on a fixed-depth battery with identical node counts, PyPy 3.11 searches about 2.7x faster than CPython 3.14, given as 81 vs 30 knps, worth on the order of 100 Elo at fast time controls. When something goes wrong, the documented path is to run the play interface with -debug to see the underlying error, and to check that python3 is on your PATH. On Windows, .py engines are launched through your current interpreter automatically. The README also carries its own erratum, noting that sunfish once ran fastest under PyPy 2.7 and that an older version of the same table said so.

The NNUE variant keeps its network in one Python integer

A second engine lives in nnue_4k/, described as a sunfish whose evaluation is the classic exact piece square score plus a trained neural residual. The engineering claim is the interesting part: the whole accumulator and the evaluation head are packed into one Python integer, so a wide network costs a handful of big-integer operations per node. Strength is stated as about 200 Elo over the classic engine at tournament time controls, and the engine still packs to a few kilobytes. The other sentence is a process claim: every quantized network is certified before it plays a game, on lane exactness, on incremental evaluation matching a from-scratch evaluation, and on exact antisymmetry. There is a third engine at the other end of the size range, an NNUE build that is 4096 bytes in total, which is why the README says the network itself is very small.

One rule is missing and the search is thin

The limitations section names one outright omission: sunfish supports all chess rules except the 50-move draw rule. Everything else on that page is a roadmap written as an invitation. The board is not a mutable array and has no fast piece enumeration; there is no dedicated capture generation, no check detection and no check evasions. The evaluation uses only piece square tables and does not distinguish midgame from endgame. Pruning is limited to null move, extensions are not used at all, and move ordering has no MVV/LVA or SEE. The search itself is MTD-bi, also known as C*, with what the README calls chess engine tricks filling out the rest. That list is the most useful thing in the file for anyone learning, because it is an honest inventory of what a few hundred lines of Python leave out.

The licence is a file reference, and the homepage differs

The licensing cannot be stated from what is available here, and it is worth saying why rather than guessing. The repository metadata carries no licence value, while pyproject.toml declares licence as a reference to the LICENSE.md file in the repository root. That file exists in the tree, but its terms are not part of the project files shown, so there is no way to tell from these which terms apply. The same manifest disagrees with the metadata about where the project lives: the registry homepage points at the Chess Programming Wiki page for Sunfish, while the manifest's own Homepage URL is the GitHub repository. Two smaller unexplained items sit in the root listing as well, a formal directory that no visible part of the README describes, and an AGENTS.md file.

Editorial conclusion

Sunfish is worth your time if you want to read a complete chess engine in one sitting or use it as a base to experiment on, which is what its README says people have done with parallel search, evaluation functions and deep learning programs. Treat the line counts as an indicator rather than a specification: 126 lines is the comment and whitespace stripped source, the packed script reports 3310 bytes, and the NNUE variant adds a network. Before you build on it, check three things the project states plainly. It does not implement the 50-move draw rule. Its evaluation is piece square tables with no midgame and endgame distinction, its only pruning is null move, and it uses no extensions. And the licensing cannot be confirmed from the project files, since the repository metadata carries no licence value while the manifest points at a LICENSE.md whose terms are not in the files shown here. Pick the interpreter deliberately as well, since the launcher prefers pypy3 when it exists and the README measures that preference as significant.

Frequently asked questions

How do I play against the sunfish chess engine?

Install it with pip install sunfish and run sunfish, or from a checkout run sunfish_ui/fancy.py -cmd ./sunfish.py. Two accounts also host it on Lichess, @sunfish-engine for the classic engine and @sunfish-nnue-engine for the stronger one. For an automated match, fastchess or cutechess-cli drive the UCI entry point sunfish-uci with arguments such as -each proto=uci tc=30+1 -rounds 10 -games 2.

What interface does the sunfish engine speak?

UCI. Point a GUI such as Arena, Cute Chess, PyChess or BanksiaGUI at the sunfish-uci command after installing the package, or at ./sunfish.py from a checkout. WinBoard and XBoard are reached through the PolyGlot adapter with the shipped tools/polyglot.ini configuration, which was tested against PolyGlot 2.0.4.

How do I install the dependencies needed to run sunfish's tests?

The README's line is uv sync, with pip install chess tqdm pytest pytest-asyncio as the comment alternative. The manifest's development group is narrower: chess at 1.9.4, tqdm at 4.67.1, pytest and flake8, with a note that no async tests exist and pytest-asyncio was never consumed.

Which Python versions does sunfish support?

The manifest requires Python 3.10 or newer. A footnote in the README says modern sunfish requires Python 3.8 or newer because the code uses the walrus operator, and its test commands name python3.12 specifically. The launcher also picks pypy3 automatically when it is installed, in preference to python3.

Does sunfish implement the fifty-move draw rule?

No, and that is the one rule it states it does not support. Other omissions are on the strength side: the evaluation uses only piece square tables with no midgame and endgame distinction, pruning is limited to null move, no extensions are used, and there is no dedicated capture generation or check evasion.

Official sources

  1. Issues
  2. Project website
  3. README
  4. Releases
  5. thomasahle/sunfish on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/thomasahle-sunfish.svg)](https://hysenlabs.com/projects/thomasahle-sunfish)