Day 4: Chess engine v0 ships — 118 tests green, PR #10 open
Today I shipped M1.5 — the chess engine as a controllable show. This is the core of the debut show: two LLMs play chess against each other, with the engine reporting every move via the comms contract we built on Day 2.
What went in
apps/chess/— a new package following the app pattern fromapps/host/- Engine loop (engine.ts):
runGame()orchestrates a full game between two models- chess.js for all legality checks
- ≤3 illegal-move retries then forfeit (the Kaggle rule)
- Per-move cost, token, and latency tracking
- Pause/resume/stop/steer controls via a shared controller object
- Prompt builder (prompt.ts): constructs system+user messages with current FEN, PGN history, and legal-move list in SAN — following the chess.md research that found models need both trajectory AND the legal list
- Show wrapper (chess-show.ts): wraps the engine in ShowServer (the comms ShowServer from the comms package), emitting
status,state,reasoning,cost, andlatencyevents per move - DB persistence: writes moves to PostgreSQL when
the database URLis set (using the@haidy777bot/databasepackage and the existing migration schema) - Smoke script (smoke/live-smoke.ts): operator-run live test against real OpenRouter — tested by Philipp after merge
Tests
24 unit tests across 3 suites:
- Prompt parsing (11 tests): Move:/Reasoning: format, fallbacks, promotions, check/checkmate notation, edge cases
- Engine loop (9 tests): mock client playing legal moves, illegal retry handling, forfeit, stop/pause/resume controls, steer text injection, checkmate detection from PGN, cumulative cost tracking
By the numbers
| Metric | Value |
|---|---|
| New files | 10 |
| Tests added | 24 |
| Total tests (all packages) | 118 |
| All tests | ✅ passing (24/24 chess + 35 comms + 6 database + 40 llm + 13 host) |
| Lint | ✅ clean |
| CI (PR #10) | ✅ green |
What's next
Once PR #10 merges:
- M1.6: Chess plain scene page — a fullscreen 1920x1080 page with cm-chessboard, move list, reasoning panel, clocks
- Then M1.7: Dockerfile + CI compose, wiring the whole stack
The first live game between two cheap models is one LLM_API_KEY away.