---
title: 'AI: the method'
date: 2026-07-21
description: 'How I worked with AI to build TrainUs: the method'
draft: false
---

In a [previous article]({{< relref "2026-06-20-ia_pourquoi.en.md" >}}), I explained _why_ I used AI so heavily to build TrainUs. Here, I'll talk about the _how_.

Because yes, following a method helps! So I more or less adopted the usual method, really: a spec, a plan, rules (well, it's more explicit with an AI), tests (vital here), and docs (for me, for it, for contributors, and for users).

## Architecture

I told you I'm the lazy type when it comes to architecture, but let's be honest: the structuring decisions were mine, and made from the start. A 100% local, serverless app that works entirely offline: the data stays on the user's device, in a database embedded directly in the browser. No account, no cloud, no backend to maintain — and a workout that doesn't depend on the gym's Wi-Fi.

Where I delegate is the detailed architecture: how components and composables are split, the data access layer, code organization. The AI proposes within a framework. At the root of the project, a rules file (`AGENTS.md`) that the AI reads every session: KISS, SOLID, DRY, minimal changes rather than big refactors. And above all: a step-by-step plan, validated by me **before** writing a single line of code, and manual validation between each step (well, I need to revisit that — I usually have little to object to, so I'm figuring out how to validate "less"). No "go ahead, build the whole app." One feature at a time. In fact, I often draft the text of my features ahead of my work sessions — offline mode ;-) .

Some rules are non-negotiable and written in black and white. Example: "forbidden to bump the database schema version without asking me first," because otherwise it bumps the version on every DB change, except I've never actually shipped a release, so it's pointless.

Sometimes the AI makes choices just to make things work that are unfortunate. Example: "if OPFS doesn't work, create the database in memory" — okay, that doesn't crash the app, but it shouldn't do that; it should tell the user the app doesn't work in their browser.

## The tech stack

The stack, to be precise, is a team effort — but nothing gets in without my approval, and the decision process varied from one piece to another. SQLite WASM directly in the browser, with data stored on OPFS (Origin Private File System): that one I imposed, it's what makes 100% local possible with real persistence. Vue 3? A joint decision. Vite and i18next? Proposals from the AI that I validated — I wanted multilingual support, it suggested i18next, adopted. And for Hugo on the website side, we did a proper comparative study… even though, I'll admit, I already had it in mind.

Really, you have to decide what's non-negotiable, what's up for discussion, and what's exploratory (or no opinion). And once the stack is set and documented, the AI knows where it's going (and so do I).

## The functional spec

Everything starts from a written specification: what the app does, the two modes (edit and execution), the entities. From there, the AI derived a plan (`plan.md`) broken down into steps, each with its status and verification method. It's the project's steering document: I know what's done, what's waiting for my approval, what's left. And the AI keeps it up to date — that's part of its definition of "done."

## The decision log

Every technical decision is logged: the date, the decision, and above all the _why_ (what was considered and rejected). This is doubly useful with AI. From one session to the next, it remembers nothing: the log gives it context back and keeps it from re-proposing a solution already ruled out. And for me, when I come back three weeks later I can go read why we did that. Here too, the AI writes it up from our exchanges.

## Tests

My number one safety net. End-to-end tests with Playwright, on Firefox **and** Chromium, covering the green paths (the happy flow) and the red paths (bad inputs, edge cases, error states). A step isn't done until the tests pass on both browsers.

That's what lets me get away with barely reviewing the generated code: if the full suite passes, the new feature is tested both ways, and my manual validation is OK, the regression risk is low. Without this test base, working this way would be reckless.

## Diataxis for the docs

User documentation follows the [Diataxis](https://diataxis.fr/) framework: a tutorial (quick start), how-to guides (how to do X), a reference (the user guide, screen by screen), and an explanation (understanding the concepts). All of it in English and French, plus a separate technical doc for developers.

Let's be honest: on my own, with my free time, I would **never** have written all that. With AI, the docs get updated at every step — it's in the definition of "done," same as the tests. Giving it a known framework like Diataxis works really well: it knows exactly what type of content goes where, and the result is far more structured than a plain "write me some docs."

## In short

The method is pretty classic, really: a spec, a plan, rules, tests, docs. Nothing revolutionary — it's what we should be doing on any project. The difference is that AI makes the cost of this rigor nearly zero — and in return, that rigor is exactly what makes the AI reliable. The framework is what turns a code generator into a real teammate. Just watch out, though: it can get lazy too sometimes and forget the docs, the tests, or the decision log, so you still have to keep your eyes open and remind it (reminds me of certain people :-p ).
