Michael Paycer — SQL Server DBA and lifelong computer-chess tinkerer
Computer Chess · Automation

Scripting Stockfish

The thing nobody tells you about chess engines is that under the GUI they're just command-line programs that read text on stdin and write text back. Which means you can drive them from a script — batch-analyze a thousand games for blunders, stage a tournament between two engines overnight, tune the knobs like a config file. This is the page where computer chess and my day job stop rhyming and start being the same thing.

Computer Chess Cluster
This is the Automation page — part of Computer Chess, from a DBA's Chair. Companion reading: How Engines Were Built (where Fishtest/SPRT is the construction story) · Search vs. Evaluation · Glossary.
The Protocol

UCI in one screen

Every modern engine speaks UCI — the Universal Chess Interface. It's a plain-text protocol: the GUI (or your script) writes commands to the engine's standard input, and the engine writes analysis and its chosen move back to standard output. That's the entire model, and it's why any engine plugs into any GUI, and why any engine can be scripted. Here's a whole game of conversation with Stockfish:

uci # announce protocol; engine lists its options id name Stockfish 18 uciok isready readyok position startpos moves e2e4 e7e5 # set the board go depth 20 # think to 20 ply info depth 20 score cp 31 pv g1f3 b8c6 ... bestmove g1f3 # its move: Nf3

The engine is GUI-agnostic; the GUI is just a program feeding it these lines and drawing the result.

The DBA bridge

UCI is a text protocol over stdin/stdout — a REPL you can pipe. If you've ever driven sqlcmd from a script, fed it a batch, and parsed the result set, you already understand UCI: send position and go the way you'd send a query, read bestmove the way you'd read the output. The engine is a headless server; the GUI is one client among many, and your PowerShell script is another.

Driving It From a Script

Batch-analyzing a PGN for blunders

Because it's just stdin and stdout, you can wrap an engine in whatever language is handy. On Windows the obvious tool is PowerShell — and the task that pays for itself is scanning a pile of your own games for the moment each one went wrong. The loop is simple: for each position, ask the engine for its evaluation; when the score swings by more than a threshold between one move and the next, flag it. That's your blunder list, generated while you sleep.

# sketch: pipe UCI commands into Stockfish and capture the eval $sf = Start-Process stockfish.exe -NoNewWindow -RedirectStandardInput ... "position fen $fen`ngo depth 18" | Out-Engine $sf # parse 'info ... score cp N' → compare to previous ply → flag swings > 150cp
The DBA bridge

This is an ETL job. Extract positions from the PGN, transform each into an engine evaluation, load the swings into a report. Swap "PGN" for "query log" and "centipawn swing" for "duration regression" and you've written a nightly job that flags which statements got slower after a deploy. Same shape, same scheduled-off-hours instinct.

Engine vs. Engine

Gauntlets with cutechess-cli

The 2004 version of me ran these by hand in the Fritz GUI, one match at a time — 20/1, 3/1, 5/0, on down to 1/0 bullet — just to see which settings won. The grown-up tool is cutechess-cli, a command-line harness that pits two engines against each other for as many games as you like, at any time control, with opening books and adjudication, and prints the score and the error margin. One line stages a hundred-game match; a loop stages a round-robin.

cutechess-cli -engine cmd=stockfish -engine cmd=fritz \ -each tc=40/60 proto=uci -games 100 -pgnout results.pgn Score of Stockfish vs Fritz: 58 - 32 - 10 [+0.63]
First-hand memory

This is the direct descendant of what I actually did as a college student: stage a gauntlet across every time control and watch. The difference is only automation and honesty — cutechess-cli gives you a score with an error bar, which is exactly the discipline my overnight Fritz matches were missing. Back then "it felt stronger" was the whole methodology.

The Centerpiece

Fishtest and SPRT — testing as engineering

Here's the idea that makes this the most professionally-resonant page in the cluster. Modern Stockfish did not get strong because someone was clever once. It got strong because the team built Fishtest: a distributed framework where thousands of volunteer machines play games to test every single proposed change, and the change is only accepted if it proves an Elo gain. The statistical stopping rule is SPRT — the Sequential Probability Ratio Test — which plays exactly as many games as needed to decide "this patch helps" or "this patch hurts," and no more. Nothing merges without passing. Today's open-source engines run the same play on OpenBench, Fishtest's offspring.

The DBA bridge · the one that matters

Fishtest is statistically-gated regression testing, and it's precisely how you should validate an index change or a query rewrite. You don't ship "it looks faster." You run the change against a workload, enough times to clear the noise, and you keep it only if the improvement is real and significant. SPRT is the formal version of the instinct every good DBA already has: measure, don't merge on vibes, and stop testing the moment the data has answered. A chess engine team independently reinvented A/B testing with an early-stopping rule and made it the law of the codebase — nothing gets in without proof.

The Knobs

The settings that actually matter

Drive an engine yourself and you meet the same handful of options that reward tuning — and they read like a database config screen:

  • Hash — the transposition-table size in MB. The single biggest memory lever; the college student I was maxed this at 256 MB, a modern box gives it gigabytes. Too small and the engine keeps re-solving positions it already saw. It's a cache-size setting, full stop.
  • Threads — how many CPU cores search in parallel. Your degree of parallelism.
  • MultiPV — how many best lines to report. Great for analysis, slower because it can't prune as hard.
  • SyzygyPath — where the endgame tablebases live, so the engine can probe them mid-search. A path to a precomputed lookup store.
The DBA bridge

Hash size, thread count, a path to a precomputed store: this is a sp_configure screen wearing a chessboard. Sizing the transposition table against available RAM is the same trade-off as sizing buffer pool or a plan cache — give it enough to stop thrashing, don't starve the rest of the machine.

None of this is exotic. It's a headless program, a text protocol, a scheduled batch job, a statistically-gated test, and a config file. Which is exactly why, more than twenty years after I first cranked the hash on a Pentium 4, this is the corner of computer chess that feels most like Monday morning.

Sources & Further Reading
  • UCI protocol specification (Rudolf Huber and Stefan Meyer-Kahlen, 2000) and the Stockfish command-line documentation.
  • cutechess-cli — the Cute Chess project documentation for engine-vs-engine tournaments.
  • Fishtest and the Stockfish testing framework; SPRT methodology — stockfishchess.org and the Chessprogramming Wiki (SPRT).
  • OpenBench — the open-source distributed testing framework used by many modern engines.
Keep Exploring the Cluster

From running engines to building them

Fishtest is also the hinge of how engines were constructed. Or drop down a level to what the engine is doing while it thinks.

How Engines Were Built →  ·  Search vs. Evaluation →  ·  Back to the Hub →