Kibitz User Guide

This guide covers everything you can click in the app and every feature that is currently CLI-only. It is also available inside the app: press Help & tour at the bottom of the navigation rail (Esc closes it).


The window at a glance

The rail, item by item

In the data tables used across the app (Database, Opening tree, Position search, Profile, Prep), some column headers sort: clicking one cycles ascending → descending → original order.


Home

The startup screen: your day at a glance, built only from real data — absent data produces absent panels, never invented widgets. Needs an open database ("Open a database to see your day." otherwise).

When nothing at all is due — no cards, no new games, no findings, no commitment — Home degrades to a short honest list ("Nothing due today. / No new games this week. / Build a profile to surface findings.") instead of padding the screen.


The Game view

Header bar

These three buttons are enabled only for games loaded from the database.

Board column

Keyboard map (Game view)

Global to the Game view, but ignored while you are typing in a text field, while a modifier key is held, and while a dialog (help, tour, promotion picker) is open. The status strip's right cell repeats the active screen's working shortcuts.

Explain panel

The Explain rail item (COACH) toggles the panel on or off. While it is on, the free static screen runs automatically at every ply — no keypress, and still no engine: the tactical screen is static analysis.

Panel anatomy:

Evidence overlay language

One shared vocabulary, identical in both themes and both board treatments:

Evidence renders at 44 % intensity by default and at 100 % for the hovered sentence.

Moves panel

A move-pair grid: number column, White's and Black's moves per row, NAG glyphs on the moves, and the per-move stored evals (muted = legacy import; hover any eval for its engine). Comments render as serif rows under their move; variations render as tagged rows — FRESH (named after one of the game's fresh engine identities), LEGACY (imported engine lines / pre-2020 years), or plain human lines.

Editing (database games only):

Below the Moves panel, the repertoire footer — "Mainline → repertoire" (or "Line (first N plies) → repertoire" after stepping forward) with as White / as Black — sends the current line to the Openings SRS trainer. Re-adding a line never duplicates cards.

Promotion picker

Wherever a board accepts moves — Game-view variations, Openings SRS, Tactics, Endgames — dragging a pawn to the last rank opens a picker: choose Q / R / B / N by click or keys 1–4; Esc cancels. Underpromotions are fully supported, including tactics puzzles whose solution underpromotes.

When does the engine run?

Stockfish is off by default and never runs behind your back — but an explicit click *is* an explicit engine request:

  1. Stepping through games, the Explain panel and Annotate's static comments never involve the engine.
  2. Re-analyze and Annotate (game view) run their jobs immediately on click — enqueue *and* start the worker — with an inline progress row in the game view. So does confirming a database-wide batch (Database header / Settings), and Run pending jobs in the Jobs view (or the CLI run-jobs) resumes anything left pending. The status strip's engine dot and batch progress show it happening.
  3. Live analysis (game view, next to Flip): an explicit toggle that runs infinite analysis on the position you're looking at, streaming depth, evaluation and the engine's line below the move controls. It follows you as you step through the game and stops the moment you switch it off, load another game, or leave the game view. It always starts off — the setting is deliberately not remembered between sessions.

STUDY views

Database

The database screen: filter bar, the games table, and the two database-wide batch actions.

Opening tree

Transposition-aware: counts merge every move order that reaches the position, and the header shows the measured query time in ms.

Which games reached a position you set up yourself.

For an arbitrary FEN from a script, the CLI find-fen does the same query.


COACH views

Explain

A toggle for the Game view's Explain panel (documented above), not a page. The badge shows whether it is on.

Profile

Engine-derived findings about one player — and every number on the screen is a control: clicking a motif cell, a structure bar, a phase tile or a rate tile re-targets the evidence aside on the right.

Opponent prep

A four-step workflow in a header stepper — ① Opponent → ② Fingerprint → ③ Weak lines → ④ Master games — with free backward navigation (click any reached chip; each chip shows its chosen value) beside a persistent aside.

  1. OpponentSearch local lists up to eight matching names from your own database with their game counts. Fetch from Lichess / chess.com are visible but honestly disabled in this stepper — pull the opponent's games in first via the Account syncs screen (or the CLI lichess-sync / chesscom-sync). Picking a name advances. (Home's "Prep an opponent" lands here pre-searched.)
  2. Fingerprint — their repertoire by ECO family for the chosen colour (as White / as Black): share of games, score bar against the 50 % tick (weak families — under 50 % on 3+ games — marked), and the book-exit column ("leaves book at Nf6 (ply 5, 12×)"). AVG ELO is an honest "—" (not recorded per family yet). Click a row to rank the weak lines.
  3. Weak lines — ranked — cards ordered by prep value: rank, the line name (opening name, ECO, or "Out of book"), "by ply N · plays …", the score chip ("38% in 21"), and a serif paragraph explaining *why* this spot is weak, citing real counts (plus a note when it is also a book-exit point). Click one to see its master games.
  4. Master games — games reaching the exact position, with the stated ranking rule: both players rated 2200 or above, strongest pairings first. Click a row to open it in the Game view at the prep ply.

The aside persists across steps: a board showing the position under discussion (with a caption naming the line, ply and score), a PROFILE FINDING about this opponent (from *their* profile only — an honest absence line otherwise), Open his profile (Profile with the opponent subject), and Study in game view. Starting a prep is recorded, which keeps Home's "no prep started for X yet" truthful.


TRAIN views

Openings SRS (Repertoire Trainer)

Spaced-repetition review of your opening repertoires, scheduled with FSRS-4.5. Each card is a position where it is your colour's turn plus the repertoire move you must know there. Layout: repertoire column | board | session aside.

Building a repertoire:

cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite \
  import-repertoire study.pgn white --name "main"

--name defaults to main; re-importing is idempotent (positions that already have a card are left untouched — first move in wins).

Reviewing:

Tactics

Puzzle drills over the Lichess puzzle database. Layout: mode column | board | WHY THIS PUZZLE reasoning aside. No engine is involved — solving is checked against the stored solution line. The header shows puzzle count, your tactics rating and attempt count.

The five modes (mode column; badges are real numbers or absent):

SolvingNext puzzle (⏎): the opponent's setup move plays after a beat, the clock starts (the clock renders only in the timed modes: speed and Woodpecker), and you play every solution move on the board, oriented to your side (opponent replies play automatically).

WHY THIS PUZZLE aside — a Coach | Neutral voice toggle (the same voice state as Explain), a voice-aware headline, and the body quoting the selector's per-pick reasoning verbatim in weakness mode ("picked because your games allow many … tactics (N allowed, M missed in your profile) — this puzzle's themes […] train that motif"). The facts block stays non-spoiling: MOTIF shows your profiled motif in weakness mode but otherwise says "revealed when solved" until you finish; SOURCE credits your profile or the Lichess puzzle id (CC0); RATING is the puzzle's. The footer tracks the session (solved/attempts) or the Woodpecker queue.

Importing puzzles — when no puzzles are imported yet, the board column offers the import: CSV path (default testdata/corpus/lichess_db_puzzle.csv) + Import CSV (puzzles below popularity 50 are skipped). Download lichess_db_puzzle.csv from database.lichess.org (CC0). The CLI import adds knobs:

cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite \
  import-puzzles lichess_db_puzzle.csv --min-popularity 50 --max-rows 100000

The rating is Elo-style against fixed puzzle ratings (K = 40 for your first 30 rated attempts, then K = 20); only rated, motif and weakness attempts move it.

Endgames

A rating-tiered curriculum of classic theoretical positions, played out against the toughest defence available and graded against tablebase truth, never an engine score. Layout: curriculum column | board | feedback aside.

Tablebases: the Syzygy directory resolves from the KIBITZ_SYZYGY environment variable, else by walking up to testdata/syzygy. The repo script

scripts/fetch_syzygy_test_files.sh

downloads the complete 3-man set (under 100 KB) — enough for the test suite, but most drills have more pieces and then fall back to the heuristic defender; point KIBITZ_SYZYGY at a 3-4-5-man set for tablebase-verified play across the whole curriculum.


DATA IN / OUT views

Import PGN / SCID

Note: pasting a PGN loads it for *viewing* — storing games in the database is a CLI import.

TWIC ingest

The full Week in Chess catalog — every issue from the earliest one the TWIC zip archive serves (issue 920, ≈ June 2012) through the latest known issue — with per-issue status. The rail badge shows the newest imported week ("wk NNNN").

TWIC data is for personal use only and is never bundled or redistributed; downloads go to your own database with full provenance. CLI equivalent: twic-sync (see "Downloading games" below).

Account syncs

Per-service cards for online accounts; the rail badge counts configured accounts. Usernames persist in the open database, and each service's last sync result (games imported / duplicates / failures, with its timestamp — or the error, verbatim) is stored and shown.

All syncs run one at a time on the background worker with a descriptive User-Agent; HTTP 429 rate limits are respected automatically (a sync can pause for a minute or more — the card says so rather than showing a fake percentage). CLI equivalents: lichess-sync / chesscom-sync / fics-sync.

Jobs

The engine job queue — the engine only ever runs through it:

Everything the engine does goes through this queue — annotate confirmations, re-analyze passes, database-wide batches. Nothing runs until you (or a batch confirmation) start the worker.


Status strip

Always visible along the bottom:


Settings

A single column of grouped cards; each row is label + explanation, the current value, and an action.


A URL hash applies once at startup, after the database opens:

#game=123&ply=24&theme=light&treatment=instrument&voice=neutral
#screen=profile&player=Carlsen, Magnus&claim=motif:WeakKing:allowed
#screen=prep&opponent=R. Halvorsen
#db=/path/to/other.sqlite&screen=home

Any subset works. Handy for demos, screenshots and shared findings.


End-to-end workflows

Start your day from Home

  1. Launch — the last database opens and Home greets you (with your commitment, if one is set in Settings → Schedule).
  2. Resume review continues the game you left; DUE TODAY → Review openings clears the SRS queue; Solve tactics drills weaknesses.
  3. A finding row under YOUR CHESS opens Profile with that claim's evidence preselected; NEW SINCE … rows open this week's imports.

Import games and browse them

  1. CLI: import-pgn / import-si4 (or a sync command) into a .sqlite file — see below.
  2. STUDY → Database → enter the path → Open (subsequent launches auto-open it).
  3. Filter, click a game, step through it in the Game view.

Run a database-wide annotate (or fresh analysis)

  1. STUDY → Database → Annotate database (or Fresh analysis pass; both also live in Settings → ENGINE & ANALYSIS).
  2. Read the estimate dialog — games to cover, estimated duration, and the quoted estimate basis — then Start. The jobs enqueue *and* the worker starts.
  3. Watch the inline job row (or Home's RUNNING panel / the status strip); Pause anytime — the run resumes exactly where it left off, and already-covered games are skipped on a re-run.

Annotate a single game and confirm tactics with the engine

  1. Load a game from the Database view.
  2. Header bar → Annotate — instant static comments; the engine checks run immediately (inline ANNOTATING row) and verdicts fold back automatically when the batch finishes. (Jobs → Run pending jobs still resumes anything paused or left over.)
  3. Edit by hand in the Moves panel (comments, NAGs, variations) and Save; Export PGN to take the annotated game elsewhere.

Drill a weakness end to end

  1. COACH → Profile → Build profile (evals from a Fresh analysis pass make the phase/conversion numbers live).
  2. Click the loudest number — say a motif's ALLOWED cell. The evidence aside shows the supporting games; open one to land on the exact ply where the weakness appeared.
  3. Press Train this weakness — Tactics opens in weakness mode, seeded with that motif (the SEEDED chip shows it).
  4. Solve — the WHY THIS PUZZLE aside quotes why each puzzle was picked, and every result feeds your tactics rating.

Prep for an opponent

  1. Home → "Prep an opponent" (or COACH → Opponent prep) → search, pick the name.
  2. Fingerprint their colour, click a weak family → ranked weak lines → master games; Study in game view opens the top game at the prep position.
  3. Open his profile for the full findings; the prep is recorded so Home stops nagging about it.

Build and train an opening repertoire

  1. Load a model game, step to where your line ends, and use "→ repertoire: as White / as Black" under the Moves panel — or bulk-import a PGN study with the CLI import-repertoire.
  2. TRAIN → Openings SRS → pick the colour → Start review.
  3. Answer on the board or by typing; grade yourself Again/Hard/Good/ Easy — the buttons show the real next intervals.
  4. Come back when the rail badge (or the status-strip nudge) shows cards due — FSRS schedules the rest.

CLI-only features

Everything below has no UI entry point (exceptions are noted inline) — it exists only in the developer CLI (kibitz-cli) or the validation harness (wsui-validate). Run them from the repository root. The general form is:

cargo run --release -p kibitz-db --bin kibitz-cli -- --db <path.sqlite> <subcommand> [args]

--db defaults to kibitz.sqlite in the current directory; the database is created and migrated automatically. (A built binary works the same: kibitz-cli --db <path.sqlite> <subcommand> [args].)

Database creation & import (CLI-only)

cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite init
cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite \
  import-pgn games.pgn --source-name "My games" --origin "local file" \
  --license "personal data" --kind personal

--kind is one of personal|twic|online|other and controls duplicate priority.

cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite \
  import-si4 /path/to/scidbase --source-name "SCID import" --kind personal
cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite \
  import-repertoire study.pgn white --name "main"
cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite \
  import-puzzles lichess_db_puzzle.csv --min-popularity 50 --max-rows 100000

Downloading games (CLI equivalents)

These all have UI homes now — the TWIC ingest and Account syncs screens (see above) — and remain available for scripting:

cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite \
  twic-sync --from 1580 --max-issues 5

Later runs resume where the last one stopped:

cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite twic-sync
cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite \
  lichess-sync SomeUsername
cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite \
  chesscom-sync SomeUsername
cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite \
  fics-sync SomeUsername 2025 --month 6

Queries & reports (CLI-only)

cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite \
  fingerprint "Carlsen, Magnus"
cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite \
  players carlsen
cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite \
  find-fen "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1"
cargo run --release -p kibitz-db --bin kibitz-cli -- \
  explain-llm "r1bqkbnr/pppp1ppp/2n5/4p3/2B1P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 3 3"

CLI equivalents of app features

These duplicate UI functionality, useful for scripting and batch work (opening-tree, explain, stats also exist and mirror the Opening tree view, the Explain panel, and the database summary):

cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite export-pgn 123
cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite annotate-game 123
cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite reanalyze-game 123 --nodes 200000
cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite run-jobs --max-jobs 100
cargo run --release -p kibitz-db --bin kibitz-cli -- --db mygames.sqlite profile "Carlsen, Magnus" --json

run-jobs needs an engine binary (set KIBITZ_STOCKFISH if it is not on PATH) and, like the Jobs view, folds verdicts back into annotations when the jobs finish.

WSUI validation harness (CLI-only)

wsui-validate measures the tactical screen's precision/recall against Lichess puzzles (positives) and engine-quiet positions (negatives); results are recorded in docs/VALIDATION.md.

cargo run --release -p kibitz-db --bin wsui-validate -- \
  --build-quiet-from mygames.sqlite --per-class 500 > quiet_fens.txt
cargo run --release -p kibitz-db --bin wsui-validate -- \
  --puzzles lichess_db_puzzle.csv --quiet quiet_fens.txt --per-class 2000
cargo run --release -p kibitz-db --bin wsui-validate -- \
  --puzzles lichess_db_puzzle.csv --emit-fixture 500 > puzzles_sample.csv

Where things are stored