CLI tool
thomas-mauran/chess-tui avatar
thomas-mauran/chess-tui

chess-tui puts a local game, an engine and Lichess behind one keyboard

Play chess in any terminal. Rust TUI, Stockfish, Lichess.

1,208 stars86 forksRustMIT

At a glance

What is it?
chess-tui is an MIT licensed Rust terminal chess application built on ratatui that plays two player locally, against any UCI engine such as Stockfish, and online through Lichess with a token, with configurable depth and difficulty, custom skins and a keymap where the arrow keys or hjkl move the cursor.
Who is it for?
chess-tui fits a developer who wants to play chess from a terminal, whether against a friend on the same machine, against a local engine, or against a human on Lichess, and it fits someone who wants a chess UI they can theme and drive from the keyboard without a mouse. It does not fit a player who wants a native desktop client with an animated board, and it does not fit a hosted platform that wants the whole thing behind a web interface.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

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

Editorial analysis

One application, three opponents

chess-tui is a free, open-source terminal chess game, and the description sets the scope. Play with a friend locally, against any UCI chess engine such as Stockfish, or online via Lichess. It runs on macOS, Linux and Windows.

The three modes are worth separating, because they have quite different requirements and quite different failure modes.

Local two player needs nothing beyond the program itself, so it is the mode that always works and the mode the installation instructions lead with.

The engine mode needs an external binary that speaks the Universal Chess Interface protocol, which is the near-universal protocol engines use. The quick start shows the three ways to point at one.

bash
# Simple engine path
chess-tui -e /path/to/engine

# Engine with command-line arguments (e.g., GNU Chess with UCI mode)
chess-tui -e "/opt/homebrew/bin/gnuchess --uci"

# Stockfish example
chess-tui -e /opt/homebrew/bin/stockfish

The -e flag takes the whole command as a string, which is why the GNU Chess example includes --uci inside the quotes, since that binary needs to be told to speak the protocol.

The Lichess mode is the third and it is the one with a credential.

bash
chess-tui -l YOUR_LICHESS_TOKEN_HERE

A personal access token from Lichess is passed with -l, and the documentation has a Lichess setup page for it. The Lichess section of the docs covers seek game, join by code, ongoing games and puzzles, so it is a full client rather than a read-only board.

Beyond the opponents there is a settings layer, and the other options are listed. The --depth flag sets the engine depth, --difficulty takes easy, medium, hard or magnus, and --no-sound turns off the audio.

The keymap is designed for the keyboard, not the mouse

The controls table is short and it is the clearest statement of the interface model.

| Key | Action | |---|---| | Arrow keys or h/j/k/l | Move cursor | | Space | Select piece / move | | Esc | Deselect or close popup | | ? | Help menu | | s | Cycle skins | | b | Back to menu | | q | Quit |

The first row is the one that defines the design. The arrow keys work and the vi style hjkl works, and the same action does both, so the program is usable by a mouse-free terminal user and by someone who never touches a mouse at all. A chess board needs a cursor, and putting the cursor movement on hjkl makes the whole application drivable from a keyboard with no modifier keys and no pointer.

Space for select and move is the natural choice for a grid, because a chessboard is a grid of cells and the arrow keys already navigate it. Escape deselecting or closing a popup is the expected behaviour for a layered interface, and it is also the escape hatch from the piece selection state, which is the one that catches new users, because selecting a piece and then a destination is a two-step action.

The ? help menu is there because there is a full keymap to learn, and the README says to press ? in-game for the full list. The other two keys are conveniences, s cycling skins and b going back to the menu, and q quitting.

The features section also shows a helper menu, a separate popup with a demonstration gif, and custom skins with a demonstration of skins and piece styles. So the application is not a bare board, it has the menu structure a chess application needs, with the board as one screen among several.

The Lichess menu has its own gif too, which shows that the online mode is a mode of the same interface rather than a separate application.

The dependency list shows what the application actually does

The Cargo.toml is short and the dependencies map directly onto the features.

The interface is ratatui at 0.30.0 with the serde feature, and the badges in the README confirm the choice with a Built With Ratatui badge. The cursor and board are drawn by ratatui, and throbber-widgets-tui at 0.11.0 provides the loading spinner, which you would expect in an application that waits on a network call to Lichess or on an engine to think.

The chess rules are not implemented here. shakmaty at 0.27.3 is a well known Rust chess library and it handles the move legality, the check and mate detection and the position representation. That is the right division, because the rules are the part that is well specified and heavily tested by other people, and the interesting part of this project is the interface.

The engine protocol is handled by ruci at 2.1.0 with the engine-sync feature, and the topics list includes uci, so that is the UCI implementation.

The network client is reqwest at 0.13 with the blocking, json and form features, and the form feature is for the Lichess API, which is a form-encoded API. The blocking client in an async application is a deliberate choice for a program that is fundamentally a request and response loop.

The rest is ordinary. clap at 4.6.1 with derive for the command line, dirs at 7.0.0 for the configuration and skin directories, toml at 1.1.2 for the configuration file, serde and serde_json for serialisation, log with simplelog for logging, chrono for timestamps, and rand at 0.10.1.

The audio is optional and behind a feature flag. rodio at 0.22 is marked optional and the features section has sound = [rodio] with default = [sound], so sound is on by default and can be turned off at build time. The --no-sound flag is the runtime equivalent, so the choice exists at both levels.

The image and animation dependencies are for the richer presentation, with ratatui-image at 11.0.6 with default-features off and the crossterm feature, the image crate with default features off and png, and tachyonfx at 0.25.0 for the animation library. The release profile optimises for size with lto, codegen-units = 1, opt-level = z and strip, which is a sensible choice for a binary people install from a package manager.

The Docker image is a terminal program, and it says so

The Dockerfile is worth reading because it exposes the awkward parts of shipping a terminal application in a container.

The build stage is rust:1.88, and the ALSA development libraries are installed for rodio with the comment saying so. The dependency caching is done properly, with the Cargo.toml and Cargo.lock copied first, then a dummy src directory with a trivial main.rs so the dependencies compile in their own layer, then the real source copied over and rebuilt.

The runtime stage is debian:bookworm-slim with libssl3 for reqwest, libasound2 for the ALSA runtime and ca-certificates.

And then there is a detail that shows the author has actually run this. ALSA is configured to use a null device to suppress error messages when no audio hardware is available, which prevents ALSA from spamming stderr with errors in Docker containers, and the container writes a pcm.!default of type null into /etc/asound.conf and a matching ctl.!default entry.

That is a small thing that would otherwise produce a wall of ALSA errors in every container log, and it is exactly the kind of fix that only appears when someone has deployed the image.

The container is minimal in another sense, since the entrypoint is the binary itself and there is no shell, no editor and no package manager in the image. A container that runs a terminal program is of limited use on its own, since there is no terminal in it, and the realistic use is running it with a pty attached from a client, or using the image as a build environment for the release artefacts. The Cargo.toml excludes the Dockerfile from the published crate, so it is a repository artefact rather than something a cargo user receives.

Skins, a PGN sample, and recorded tapes for the demos

The repository listing is interesting because the examples directory contains more than screenshots.

Alongside the gifs for the two player demo, the engine games against a white and a black bot, the helper menu, the Lichess menu, the skins and the main ratatui interface, there are .tape files. A tape file is the script format used by VHS, the tool that records terminal sessions into a gif, so the demos are generated from reproducible recordings rather than captured by hand.

That is a good practice for a terminal application in particular, because a gif of a terminal is only convincing if it was made by running the program, and a tape file is the recipe for that. The tapes and the gifs sit side by side, and the Cargo.toml excludes the gifs and the tapes from the published package, so the crate stays small and the recordings stay in the repository for regeneration.

There is also a sample.pgn, which is the standard text format for a chess game, and the topics include pgn and pgn-reader, so the project can read games in PGN.

The rest of the listing shows a project with its own documentation site, a website/ directory with the static assets and its own gifs, an assets/ directory, a scripts/ directory, a tests/ directory, a Dockerfile, and a cliff.toml, which is the configuration for git-cliff, the changelog generator that produces the release notes from conventional commits. There is a cargo-generate.toml as well, which is the template configuration for cargo-generate, so a new project can be scaffolded from the template.

The release history shows a steady cadence, with 2.6.2 on 2026-05-04, 2.7.0 on 2026-05-13 and 2.7.1 on 2026-05-21, and the last push to main on 2026-10-15.

Where chess-tui is the wrong choice

The first wrong case is a player who wants a graphical board. This is a text interface, and while the features list mentions custom skins and piece styles and the ratatui-image dependency suggests some image support, the board is drawn with characters in a grid. Somebody who wants to look at a board the way they would in a study app will find the terminal a limitation rather than a feature.

The second wrong case is a hosted platform. The application is a binary you install, not a service. The Dockerfile exists, but a container with a terminal program and no pty is not something you put in front of users, so a team wanting chess on the web is building a different thing.

The third wrong case is a team that does not want a Rust dependency tree for a game. The dependency list is moderate rather than small, with ratatui, shakmaty, ruci, reqwest, rodio, image and tachyonfx, and the release profile is tuned for size at the cost of runtime speed with opt-level z. That is a reasonable trade for a distributed binary, and it is a trade a team that values speed would make differently.

The fourth wrong case is a Lichess user who does not want to hand over a token. The -l flag takes a personal access token, and while that is the normal way to use a Lichess client, a user who would rather not create a token is not served by this tool at all, since the online mode depends on it.

How it differs from a Lichess web client or a desktop GUI

The comparison worth making is with the obvious alternatives, and the difference in approach is what the terminal gives you and what it costs.

A Lichess web client is a full chess application with an animated board, clocks that count down with a little sound, a puzzle trainer, a study board, and analysis that runs in the browser with Stockfish in WebAssembly. It is free and it needs nothing installed, and it is a much better chess experience than anything you can draw in a terminal. The web client is also a web page, so it needs a browser and a network round trip to Lichess for most of what it does.

A desktop GUI client is the other comparison, and the difference is where the interface lives. A GUI client is a window, it takes the mouse, it renders an actual board, and it is the natural thing for a player. chess-tui trades all of that for three properties: the program is a single binary that starts instantly, it works over a serial line or an SSH session with no graphics stack, and the interface is scriptable in the sense that every action has a key and nothing depends on a pointer.

That last property is the one that has real value in a specific situation, which is a developer on a remote machine, in a terminal multiplexer, over SSH, wanting to make a move. In that situation a GUI client is awkward to run and the web client requires a browser on the other end. A TUI works over SSH natively.

The third difference is the engine. Because the engine is a subprocess you point at with -e, you can use any UCI engine and configure it with the flags the engine expects, which is what the --depth and --difficulty options are doing. A web client chooses the engine for you, and a desktop GUI often ships with one. Here the engine is a separate decision.

The fourth difference is the aesthetic. The custom skins and the piece styles and the animations are the project compensating for the medium, and a team that cares about how the game looks is better served by a GUI.

Editorial conclusion

chess-tui fits a developer who wants to play chess from a terminal, whether against a friend on the same machine, against a local engine, or against a human on Lichess, and it fits someone who wants a chess UI they can theme and drive from the keyboard without a mouse. It does not fit a player who wants a native desktop client with an animated board, and it does not fit a hosted platform that wants the whole thing behind a web interface. Before adopting it, note that the engine path is a command line to a UCI binary you install yourself, that the Lichess path needs a personal token, and that the current release is 2.7.1 from 2026-05-21 with the last push on 2026-10-15.

Frequently asked questions

How do I play against Stockfish in chess-tui?

Point the -e flag at the engine binary, for example chess-tui -e /opt/homebrew/bin/stockfish, or pass a full command with arguments such as chess-tui -e "/opt/homebrew/bin/gnuchess --uci". You can also set the engine depth with --depth and the difficulty with --difficulty easy, medium, hard or magnus.

How do I play online against Lichess from the terminal?

Pass your Lichess token with the -l flag, for example chess-tui -l YOUR_LICHESS_TOKEN_HERE. The documentation covers seeking a game, joining by code, ongoing games and puzzles, and the Lichess menu is reachable from the main menu.

How do I install chess-tui?

With Homebrew using brew install thomas-mauran/tap/chess-tui, with Cargo using cargo install chess-tui, or with the Debian package built from the GitHub release assets. The platform table also lists pacman -S chess-tui for Arch, nix-shell -p chess-tui or nixpkgs for NixOS, and cargo install for Windows.

What are the keyboard controls in chess-tui?

Arrow keys or h/j/k/l move the cursor, Space selects a piece or makes the move, Esc deselects or closes a popup, ? opens the help menu, s cycles skins, b goes back to the menu and q quits. Pressing ? in-game shows the full key list.

Can I play another human locally with chess-tui?

Yes, local two player mode is one of the listed features and needs nothing beyond the program itself, so it works without an engine or a network connection. There is also online multiplayer over a LAN or over the internet, for example with bore.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. thomas-mauran/chess-tui 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/thomas-mauran-chess-tui.svg)](https://hysenlabs.com/projects/thomas-mauran-chess-tui)

Was this useful?