What "solved" means here
AtomicDB grows a persistent tree of Atomic Chess that the engine (Atomic-Stockfish) deepens node by node. A subtree becomes closed through four practical gates:
- TERMINAL: the position itself is checkmate, stalemate or a king explosion, verified by our own move generator (never by the engine).
- MATE_PV: the engine announces a mate and its full line is re-verified move by move down to the terminal. An exhaustive AND/OR pass labels short mates ANDOR; if its bounded certification budget is exhausted, the legal engine witness is labelled ENGINE. A mate score alone never closes anything.
- MINIMAX: three-valued backup over the COMPLETE list of legal moves (generated by us; the engine never filters legality).
- SOLVE: a df-pn prover running on a volunteer machine returns a proof certificate, and this server replays the ENTIRE strategy tree before anything closes, with its own move generator, a different implementation from the one that produced it. Every cited move legal, every defender node covering exactly the legal replies, every leaf genuinely terminal, no repetition on any branch. A certificate that fails is recorded and changes nothing.
The trust label is inherited through MINIMAX: ANDOR means the relevant continuations were exhaustively proved (or ended in a verified terminal/tablebase result); ENGINE means the practical result still depends on at least one engine witness. Distances such as ≤M4 are honest upper bounds, not exact distance claims.
Engine evaluations (the centipawn numbers) never close a node: they only order the exploration. Results are "practically solved", the standard used by the Fairy-Stockfish Solved-games wiki, and not game-theoretic proofs: position identity does not model repetition history (a known, declared limitation). A second-tier formal certification roadmap exists separately.
Contribute
No hardware needed: every unsolved position in the explorer has a Request analysis button. Requests jump to the front of the worker queue, so pointing the search at a line you care about is one click. Limits apply per visitor to keep the queue healthy.
Repeated visitor requests buy genuinely deeper searches: 128M, 512M, 2B and then 10B nodes. A healthy worker keeps a multi-hour lease alive explicitly, so a deep task cannot be assigned twice.
Asking for a position somebody else already asked for joins their request instead of queueing a duplicate: every account that asked is notified when the analysis lands, and the more people waiting on one request, the sooner it is served. Your own queue stays yours to order: while a request of yours is waiting, the position it was asked for offers a Move to front control that serves it before the rest of yours. It takes the place your own first request already held, so nobody else's request moves.
A request you have not been served yet is still yours to take back. Withdraw sits beside that same control on the position, and on every waiting row of your contributor page, which is the one place they are all listed together. Nothing has been spent on a waiting request, so withdrawing costs nothing and puts nothing on your record; the ladder does not advance either, so the same rung is still there if you ask again. One click, and the page you came back to offers to undo it. If somebody else asked for the same position, withdrawing only takes your name off: the request stays in the queue under them. A request a worker has already started cannot be withdrawn, because the search is already running. Clear my queue, at the foot of the waiting list, does the same to everything you have waiting at once, with the same rule for shared requests; that one asks for confirmation and has no undo.
API
Two endpoints, one to read and one to ask. Both speak FEN and return JSON, and both are usable without an account.
Query: GET /atomicdb/api/query?fen=... returns the stored verdict, score and move list. Scores are from the side to move (chessdb.cn convention). Unknown positions return 404; use the request endpoint below, the FEN box or the explorer to add them to the tree.
The reply also carries an analysis block with the engine's own output on that position, or null where no engine has looked yet. lines is the current pass and previous the pass before it, kept whenever it was wider than the one that replaced it; each line carries its move, cp or mate (side to move, like the rest of the reply), the PV, the depth, seldepth and nodes the engine reported, and the untouched raw UCI info string it came from. budget_nodes is the node budget of the pass that produced lines. passes is one summary per pass, newest first: budget, width, evaluation, move, depth and whether that pass is the one on display, which is what shows how the evaluation moved as the search went deeper. Passes have only been recorded since 15 August 2026, so a position analysed before then has a series that starts partway through: passes_complete is false there, and no attempt is made to invent the missing entries.
Request: POST /atomicdb/api/request with fen queues analysis for that position, taking exactly the path the explorer button takes. Same budget ladder (128M, then 512M, 2B, 10B on repeat requests), same deduplication, same queue cap, and the same joining rule: if the position is already queued, you are recorded as another requester rather than queueing a duplicate.
Optional fields: username and password put the request on your account, which is what buys the notification when it lands, the affinity with your own workers, and your place in the fair share; without them the request is anonymous and served like a click without a session. budget picks a ladder rung, and is honoured for the same accounts the explorer's depth slider is offered to. Session cookies are deliberately ignored here, so a page in your browser cannot spend your queue behind your back.
The reply carries status, the position key and canonical fen, the task id and its budget_nodes when there is a live one, ahead (how many requests are served first), backed (true when you joined a request somebody else had already made), and seeded when the FEN was not in the tree and was added by this call. status is queued, already-queued, already-solved, expanded (the ladder here is spent, so the work went to the replies below), saturated (nothing left to buy here or below), or refused. A refusal explains itself in reason: an unreadable FEN or a bad budget give 400, wrong credentials 403, too many calls 429, and a full queue or a busy database 503 with a Retry-After.
The request endpoint allows 60 calls per hour per account, or per address when no credentials are sent. It is a limit on this door only: the explorer button has no hourly limit and a day of browsing does not eat into the allowance of a script on the same account.
To contribute compute, create an account via the OpenBench registration (instant activation), then run the analysis worker. All you need is python3: the worker downloads the reference engine on first run (sha256 verified; Windows and Linux x86-64 prebuilts, CPU from ~2013 onwards):
The worker is a single self-contained file (it also lives in the OpenBench repo under Client/ if you prefer git). It checks the official HTTPS source for updates at startup and between completed task batches, validates the new file, keeps the previous version as a backup, and restarts itself without interrupting a search or an uncertain result submission. Use --no-auto-update only if you intentionally maintain a custom worker file.
Existing copies from before build 2026072201 need one final manual download because they do not yet contain the updater. From that build onward, no repeated download is needed.
Have your own Atomic-Stockfish build? Point at it with --engine path/to/binary.
-T is the engine thread count per task (any number, no need to be a multiple of anything) and --hash is the engine hash in MB. Memory does not scale with the node budget: the transposition table is fixed-size, so a 10B search uses the same RAM as a 128M one, it just runs longer; ~1 GB of free RAM per engine instance is enough to handle anything. What a bigger table buys is search quality on long runs (less entry overwriting): if you can spare the RAM, run --hash 4096 or --hash 8192. Budget roughly hash + 300 MB of RAM per engine instance. Tablebases are optional: without them your worker is still fully valid, the engine simply searches every position itself. If you have disk to spare, grab the atomic Syzygy set from tablebase.lichess.ovh/tables/atomic/ (3-4-5 is 1.3 GB, 6-wdl 91 GB, 6-dtz 129 GB) and add --syzygy dir1;dir2;dir3: the engine becomes tablebase-aware and reached endgames are closed exactly without costing a single node. Even 3-4-5 alone helps. Every completed batch is credited to your username.
Credits
Piece images: the cburnett set from lichess (CC BY-SA 3.0). Engine: Atomic-Stockfish. Rules oracle: pyffish (Fairy-Stockfish bindings).