AI SDD Β· Episode 1

Let's build a ChessGame
with AI Spec-Driven Development

A hands-on walkthrough of building a real chess application the disciplined way β€” where AI implements and humans stay in control of architecture, specs, and validation.

🧠 Methodology: AI SDDΒ· βš™οΈ TypeScript Β· Rust Β· StockfishΒ· β™ŸοΈ From spec to working board
Part 1 β€” The idea

Introduction to AI SDD

AI SDD stands for Artificial Intelligence Spec-Driven Development β€” a methodology designed to help developers take full advantage of AI while keeping complete control over their projects.

The full AI SDD methodology lives at i-smile.one. All the code for the demo ChessGame project is available on GitHub: https://github.com/denis-papin/chessgame.

Modern large language models are remarkably capable β€” often producing code faster and more effectively than humans. AI SDD is about leveraging that power without becoming dependent on AI-generated code we no longer understand.

The core idea is simple: AI implements, humans decide.

In a nutshell:

The future is not AI replacing developers β€” it's AI amplifying experienced engineering teams.

Part 2 β€” The demo project

What we're building: a ChessGame

From a software perspective, a chess game is an app that lets a human play chess against a computer. Our opponent is Stockfish, one of the strongest chess engines available today.

The three cooperating processes of the ChessGame β€” the chessgame frontend, the fisher-server backend, and the Stockfish engine β€” and how they communicate
Three cooperating processes. The browser front end (chessgame) talks to the fisher-server back end over REST/JSON; the back end drives the Stockfish engine over UCI. Each move flows to the engine; the engine replies β€” repeat until the game ends.

At first glance it seems simple: a chessboard on a web page, the user moves pieces with the mouse, the app sends the position to Stockfish, waits for the reply, and shows the engine's move. But chess is full of rules and edge cases β€” castling, en passant, promotion, check, stalemate, draws β€” and that is exactly what makes the project interesting.

The first lesson. We cannot simply tell an LLM "build me a chess game." Could it generate something? Absolutely. Would it generate the system we actually want? Probably not. So in AI SDD the very first step is to define the architecture β€” a strategic decision that stays in human hands.
Part 3 β€” Architecture

Defining the architecture

At the root of the project we place an _ai folder that holds all the knowledge of the application. In its global subfolder lives the architecture design document.

Here is that document, fetched live from GitHub so it always reflects the current file rather than a screenshot that can drift. Scroll the panel to read it, or open the full file below.

πŸ“„Github : architecture.md

Loading the architecture document from GitHub…

An architecture document doesn't need to be complete or perfect on day one β€” architecture evolves as the project does. What matters is a solid starting point and a clear direction. We identified three components:

The frontend is itself organized in layers, each with a clear boundary:

Human-defined, AI-assisted. The architecture was defined entirely by the developer; the LLM only helped turn those ideas into the polished document. The result establishes the vocabulary, the components, and the responsibilities β€” it sets the stage for everything that follows.
Part 4 β€” The first feature

Feature F0001: start-a-game

We start every feature on its own Git branch:

git checkout -b feat/F0001-start-a-game

The goal of F0001 is to display a responsive chessboard in the browser, complete with standard coordinates along the edges. When a game starts, the board is populated from data the backend returns. In standard mode the pieces appear in their traditional positions; in random mode (for testing) the positions are randomized while the piece count is fixed.

We are not asking for code yet. At this stage the LLM's job is to produce a feature specification document β€” F0001 β€” not an implementation.

The full prompt sequence

The work used the guide-spec-definition-md skill together with the feature name. No code was requested yet β€” only the spec and its tests. Here is the complete sequence of all 10 prompts, exactly as they were issued, each followed by a review session to refine the documents. Click any title bar to expand that prompt.

Claude prompt #1 β€” create the spec
/guide-spec-definition-md F0001-start-a-game The feature is to display a web page showing a chessboard with pieces.
The number of pieces is between 2 and 16 for White, and the same for Black.
In random mode (dev), the pieces are spread randomly across the board.
In a standard chess game, the pieces are placed on their standard starting squares.
The board will be built using regular DOM components. It must be responsive, and it will display the standard A-H and 1-8 coordinates on the edges.
The frontend will use the following API from the feature server:
GET /start-game
This API will return:

* the UUID of the current game
* the position of each piece in FEN format
Claude prompt #2 β€” ask for the tests
/guide-integration-test-rust-md F0001

Give me frontend unit tests that I can run locally to validate the frontend code.
Give me backend integration tests that I can use to test the APIs.
Claude prompt #3 β€” drop FEN, define our own Overview model
/guide-spec-definition-md F0001

I do not want to use FEN notation. Instead, I want to define my own JSON model called **Overview**.

Example:

[
  ["r", "n", "b", "q", "k", "b", "n", "r"], // rank 8
  ["p", "p", "p", "p", "p", "p", "p", "p"], // rank 7
  ...
]

Additional game state information:

{
  "black": "short castle",
  "white": "long castle"
}

I want all algorithms to be based on these representation models rather than FEN notation.
Claude prompt #4 β€” update the tests for the Overview model
/guide-integration-test-rust-md F0001

Adjust the existing unit tests and integration tests to use the new `Overview` representation model instead of FEN notation wherever applicable.
Claude prompt #5 β€” fix the empty-board assumption
you wrote : TC-UT-F0001-005 β€” render produces 64 squares and pieces that match the Overview
Given: a jsdom document with an empty <div id="board">, and buildBoard(STANDARD).

But I think "board" should not be empty when the rendering of the 32 pieces starts. Can you fix the F0001 documents?
Claude prompt #6 β€” name the routines, add a sequence diagram
/guide-spec-definition-md   In the specs, you never name the key routine, especially the one you are going to unit test.
You could draw a sequence diagram to explain the dom events, local routines and the api calls.
Claude prompt #7 β€” ask for an explanation
From the spec F0001, explain to me how the chessboard is created
Claude prompt #8 β€” fold the explanation back into the spec
/guide-spec-definition-md   please, integrate the explanation above into the F0001 spec, especially because it contains routine names.
Check if we can also remove some other sections ?
Claude prompt #9 β€” clarify random mode
/guide-spec-definition-md   For mode=random, is it clear that the number of pieces is not random, only the positions are random?
The number of pieces is set on the web page and passed through to the restful service.
Claude prompt #10 β€” single piece-count parameter
Yes, there is a single number (for instance 4), passed to the back end service in order to fix the number of pieces to 4 black and 4 white (including mandatory kings).
Also update the unit tests definitions.
This is the steering a human provides. Noticing that FEN was inconvenient for the backend algorithm and replacing it with a custom Overview model is precisely the kind of design decision that stays with the developer.
Part 5 β€” The documents

Specs become the source of truth

The result is a set of well-structured documents inside the F0001-start-a-game folder.

Rather than a screenshot, here is F0001.md itself, fetched live from the feat/F0001-start-a-game branch. Scroll the panel to read it β€” its internal sequence diagram is rendered from the document's own Mermaid source. Open the full file below.

πŸ“„Github : F0001.md

Loading the F0001 specification from GitHub…

And the tests, written the same way. First IT-F0001.md β€” the integration-test spec with cases such as TC-IT-F0001-001, run directly against the fisher-server:

πŸ§ͺGithub : IT-F0001.md

Loading the IT-F0001 integration-test spec from GitHub…

And unit_test_F0001.md β€” the frontend unit-test spec for the rendering routines, likewise fetched live from GitHub:

πŸ”¬Github : unit_test_F0001.md

Loading the unit-test spec from GitHub…

Once these documents are complete, they become the source of truth for code generation.

That has a powerful consequence: you cannot, for example, modify a Rust integration test just to make it pass without also updating its specification and the business rules it enforces. The methodology forces the spec, the tests, and the code to stay in agreement.

Part 6 β€” Code generation

Now we generate the code

With the specs and tests locked, a single prompt drives the implementation β€” and the tests are the referee.

Claude prompt β€” implement the feature
/implement-code Implement feature F0001 and all associated tests as specified.

Run the complete test suite and use the tests as the source of truth
for validating the implementation.

Do not modify the test definitions or the business specification. If you
encounter any contradiction, ambiguity, missing requirement, or blocking
issue, stop and report the problem in the chat, explaining the conflict
and the available options.

Once the code was generated, two commands brought the servers up β€” the Vite frontend from the chessgame project and the Rust backend from fisher-server:

# frontend (chessgame)
npm run dev

# backend (fisher-server)
cargo run
Claude Code reasoning while the Rust server logs requests
AI at work: Claude Code reads the spec and implements, while the fisher-server logs start-game requests in real time.

And then β€” the payoff. A fully rendered, responsive chessboard, served by the Vite frontend and driven by the Rust backend, exactly matching the Overview model the spec defined.

The rendered chessboard in standard starting position
Standard mode. The board renders the classic starting position β€” all 32 pieces, file and rank coordinates, served from /start-game.
The rendered chessboard in random mode
Random mode. A fixed number of pieces placed at random β€” the dev layout used to exercise the rendering and the API.
The result. Working software, generated fast β€” but every line traceable back to a spec a human wrote and reviewed. Productivity and control, together.

The generated files, on GitHub

Everything F0001 produced β€” the spec and its tests β€” is Markdown living beside the code in the feat/F0001-start-a-game branch, each generated the AI SDD way and readable in full.

Part 7 β€” A real bug

When the spec catches a bug

Right after the first code generation, every test was green β€” but a real problem was hiding in random mode: the board could start with a forbidden set of pieces.

The problem

The piece count was correct, but the composition wasn't constrained. The random generator drew piece types with replacement, so a starting position could be illegal β€” for example more than one queen, more than two rooks, knights or bishops, or a pair of bishops sitting on the same square colour. None of that can happen in a real chess army.

An illegal random-mode board with several white queens at once
The bug, on the board. A random-mode start that is plainly illegal β€” White has several queens at once (and other duplicated pieces). A legal army allows at most one queen per side.

The AI SDD way to fix it

The fix did not start in the code. It started in the spec. A single prompt added the missing constraints to F0001 and then regenerated the implementation:

Claude prompt β€” add the constraints, then regenerate
/guide-spec-definition-md  F0001

in random mode, we want to enforce some constraints for the piece
choice by side color
  * A single king
  * max 2 bishops, both on a different square color
  * max 2 knights
  * max 2 rooks
  * max 1 queen
  * max 8 pawns

/implement-code F0001

Those constraints became business rules and, crucially, the corresponding tests were written before regenerating the implementation:

Caps per piece type. Each constraint bounds how many pieces of a given nature a side may hold, so a random army stays legal while still reaching a full 16 pieces: 1K + 1Q + 2R + 2B + 2N + 8P = 16. Exactly the kind of detail a human settles when reviewing the spec before code is generated.

The new test cases TC-IT-F0001-011, 012 and 013 in the spec
The new rules become test cases in IT-F0001.md β€” the per-colour material caps (B-10) and the opposite-colour bishop pair (B-11).
The bug wasn't patched in the code β€” a new rule was added to the spec and tests first, then the code was regenerated to obey it.
Why this matters. This is AI SDD working exactly as intended. A human spotted the gap, expressed the fix as rules and tests (the source of truth), and let AI bring the implementation back into compliance β€” keeping the spec, the tests, and the code in permanent agreement.

The bug is fixed

With the new rules in the spec and their tests in place, the implementation was regenerated β€” and the illegal starts are gone. Every random army now respects the per-colour caps and the opposite-coloured bishop pair: at most one king, one queen, two rooks, two knights, two bishops and eight pawns per side.

A legal random-mode board after the fix β€” every side respects the material caps
Fixed. The same random mode, now generating only legal armies β€” no duplicated queens, no illegal composition. TC-IT-F0001-011/012/013 pass, and the board obeys the rules.
Spec first, tests next, code last β€” and the once-broken board is now correct by construction.