# FineChess...!!

> Source: <https://dev.to/manuelyator/finechess-45e7>
> Published: 2026-11-09 20:17:39+00:00

Stockfish can tell you that `17...Bh6` dropped your win chance from 72% to 31%.

What it *won't* tell you is the part that actually makes you better:

You were trying to create a kingside attack. That idea is fair but Black's reply `Bxd5` wins a pawn immediately, and the cleaner try was `Nf3`, checking every check before you commit.

That gap between **engine truth** and **human understanding** is why I built **FineChess**.

If you've ever clicked **Game Review** after a Chess.com or Lichess game, you know the ritual:

`Nf3 Bxd5 cxd5 Qe2`
The engine is brilliant at **measuring** decisions. Humans need help **interpreting** them.

Club players (roughly 800 to 1800, the range FineChess coaches for) don't lose because they can't read an eval graph. They lose because:

Existing tools give you a verdict. I wanted a **coach sitting across the board**.

So FineChess does three things traditional analysis usually separates:

FineChess doesn't ask the LLM to "look at a board and think." That would be asking a language model to do an engine's job.

Instead the pipeline is deliberately asymmetric:

```
PGN / Chess.com / Lichess
        │
        ▼
   Stockfish analysis
   (eval, multipv lines, mate scores)
        │
        ▼
   Move classifier
   (brilliant → blunder, win% loss)
        │
        ▼
   MoveFacts sheet  ← ground truth
        │
        ▼
   Coach Rex (LLM)  ← may only talk about these facts
```

For each position we run Stockfish (python-chess and a cached engine wrapper) and keep:

Results are cached by FEN and depth so replaying a game doesn't recompute the same positions forever.

Raw centipawn drops lie in unbalanced positions. Going from +600 to +400 looks huge on paper and often feels like "still completely winning" over the board.

So FineChess classifies with **win-probability loss** from the mover's perspective, then labels moves across the familiar spectrum: brilliant, great, best, excellent, good, book, inaccuracy, miss, mistake, blunder.

Brilliant detection is its own mini-pipeline: sacrifice candidates, SEE filters, PV lookahead, and guards against calling something "brilliant" when you were already completely winning.

Before Coach Rex speaks, the backend builds a strict JSON fact sheet, roughly:

That sheet is the coach's **only allowed chess reality**.

Rex's system prompt is blunt about it:

ENGINE FACTS are ground truth. Never invent moves, evaluations, or lines that are not in them.

And the answer shape is coaching, not commentary:

No "centipawns." No lecture. Roughly club-player English in about 120 words.

That is the whole bet of FineChess:

**Stockfish decides what is true. The LLM decides how to teach it.**

Move-by-move analysis is only half the product.

FineChess also has a **global coach** that remembers patterns across your games: recurring weaknesses, opening mastery gaps, fix plans, recent accuracy. When you ask something like:

"I keep hanging pieces after I castle queenside. What should I watch for?"

the coach shouldn't answer from generic LLM chess folklore.

So we retrieve.

Under `backend/knowledge/` we keep public-domain chess literature (starting with Capablanca's *Chess Fundamentals* from Project Gutenberg). At startup the service:

`.txt` book`CHESS KNOWLEDGE REFERENCE`
The instruction to the model is intentionally narrow:

Use them to ground your explanation. Explain in your own coaching voice but let these principles guide your reasoning.

Why TF-IDF instead of a fancy vector database on day one?

Because chess coaching retrieval is often **lexical and conceptual** ("isolated pawn", "opposition", "back rank"), the corpus is small and high-signal, and a local sklearn index is fast, free, and easy to reason about. We can graduate to embeddings later. The product win was already having **literature in the loop**.

So FineChess uses grounding at two layers:

| Layer | Source of truth | Purpose | 
|---|---|---|
| Move coach (Rex) | Stockfish `MoveFacts` | Don't invent tactics | 
| Global coach | Player memory and RAG literature | Don't invent principles | 

Both are anti-hallucination strategies. They just fight different failure modes.

Here's the uncomfortable truth about putting an LLM next to a chessboard:

**It will confidently invent a move that isn't legal, wasn't played, and wasn't in the engine line, and it will sound *great* doing it.**

Early prototypes of FineChess did exactly that.

Rex would say you "dropped a rook" when the PV only lost a pawn.

Or cite `Qh5` as the refutation when Stockfish's best line never touched the queen.

Or end a sentence on `17...` like a broken PGN printer.

That is not a tone problem. That is a **trust** problem. One fake move and the coach is dead.

Coach Rex now runs a cheap but ruthless grounding check *after* generation:

`played_san`, `best_san`, `best_line_san`, or `played_line_san`
There is also a separate claim verifier path for structured tactical claims (legality, hanging pieces, simple SEE-style material checks) used when generating richer mistake explanations, with verifier outcomes logged so we can see whether an explanation passed, retried, or fell back to facts.

In other words:

The model is allowed to be eloquent.

It is not allowed to be creative about the board.

That single constraint changed FineChess from "fun demo" into something I'd trust with my own blunders.

A second, quieter challenge was **latency**. Users click a move and expect a coach, not a research paper. So Rex asks for short answers, uses tight timeouts, and always has a fact-sheet fallback. Correct and slightly plain beats poetic and wrong every time.

Under the hood it's FastAPI, Stockfish, Gemini/Groq coaching, Supabase auth/data and a React analysis UI. On the surface it should feel like a sharp human coach who somehow watched every game you've uploaded.

If you've ever stared at an eval bar and thought *"okay but what was I supposed to think?"* that's the product.

**Live app:** [https://finechess.vercel.app](https://finechess.vercel.app)

Import a recent loss. Click the move that hurt. Ask Rex why.

I'd love feedback from other builders working on grounded LLM systems, especially if you've fought the same "confident nonsense" problem in a domain where facts are non-negotiable.

```
Engine truth  →  Fact sheet  →  LLM narration  →  Grounding check
Literature    →  TF-IDF RAG  →  Coach principles
Player memory →  Pattern context → Personalized habits
```

Chess improvement doesn't need more numbers.

It needs numbers that can explain themselves.
