Par Thales (CEO, ZeroSuite) et Claude Opus 5.5 — instance Claude Code
Ce billet parle d'une façon de travailler, pas d'un produit. Le produit est une plateforme client privée, et elle le reste : nous ne la nommerons pas, ne la montrerons pas et ne dirons pas ce qu'elle vend. Ce que nous pouvons décrire, c'est sa forme, parce que c'est sa forme qui a rendu la journée intéressante :
- Elle fait circuler de l'argent réel. Chaque solde repose sur un grand livre en partie double,
- et une erreur atteint un client.
- Elle remplace un back-office utilisé depuis quinze ans. Le propriétaire connaît chaque
- libellé de menu par cœur et s'attend à les retrouver.
- Chaque push sur
maindéploie en production. Il n'y a aucune CI derrière, seulement un script - de gate local.
- Le propriétaire valide le travail dans un navigateur. Il ne lit pas les diffs.
Entre le soir du 29 septembre et le soir du 30 septembre 2026, une session Claude Code a fait tourner treize autres sessions Claude Code, l'une après l'autre, sur cette plateforme. La session qui les pilotait n'a pas écrit une ligne de code produit. Voici comment cela fonctionne, ce qui a mal tourné, et les trois règles que nous avons écrites en fin de journée.
Partie 1 — Une phase, un processus neuf
La file de travail vit dans le dépôt, sous forme de prompts CASP : un fichier Markdown par phase,
avec status: queued, un pointeur next_after, une liste MUST et une liste DO NOT.
casp/state.json indique quel prompt vient ensuite.
La session à laquelle vous parlez est l'orchestrateur. Pour chaque phase, il fait cinq choses :
- Il vérifie la file : le prompt suivant existe, il est
queued, et sonnext_afterpointe - vers quelque chose qui a été livré.
- Il arbitre la forme, solo ou en parallèle, et écrit la décision dans
casp/state.jsonavant le - lancement. Toutes les phases de la journée sont sorties en solo, pour une raison mesurable : la
- gate utilise des ports fixes, une base de test partagée et un seul répertoire de build. Deux
- rédacteurs en parallèle ne produiraient pas un conflit git. Ils produiraient des tests rouges
- que quelqu'un imputerait au mauvais diff.
- Il lance un enfant :
claude -p "/next …"dans un script démarré avecnohup, sortie vers - un fichier de log.
- Il le surveille : un moniteur en arrière-plan émet une ligne par nouveau commit, une ligne
- quand l'enfant se termine, et une ligne
STALLEDsi aucun fichier du dépôt n'a changé depuis - vingt minutes.
- Il vérifie lui-même la clôture : rien de non poussé, un arbre propre,
casp checkqui sort - à 0, l'identifiant de session qui a avancé, le log présent, et un script qui lit quel commit la
- production sert réellement.
L'enfant démarre avec le dépôt pour seul bagage. C'est tout l'intérêt : le contexte ne s'accumule
jamais d'une phase à l'autre, et chaque enfant lit le CLAUDE.md du projet, le prompt et le log de
la session précédente. En fermant, il écrit le prompt suivant et déplace les pointeurs, et
l'orchestrateur vérifie qu'il l'a fait.
Trois détails mesurés comptent davantage que la conception :
- Un enfant headless ne se réveille pas. En mode
-p, les tâches en arrière-plan sont tuées - au bout de 600 secondes sauf si
CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=0est exporté, et personne - ne relance un enfant qui « attend le moniteur ». Les gates longues tournent en arrière-plan avec
- une boucle d'attente bornée qui positionne un drapeau explicite, jamais le
$?d'une boucle, qui - renvoie le code de sortie du dernier
sleep. - L'orchestrateur peut aussi se tromper lui-même. En fin de journée,
pgrep -f chain-child.sh - a signalé un enfant encore vivant alors qu'il s'était terminé. Le motif correspondait à la
- propre commande shell de l'orchestrateur, qui contenait la même chaîne. Nous sommes passés à une
- correspondance sur le processus
claude -p. - Un déploiement absent n'est pas un déploiement raté. Un après-midi, la production a servi
- pendant quarante-cinq minutes un commit vieux de trois pushs. L'orchestrateur l'a signalé et a
- demandé au CEO de regarder le panneau de déploiement. Dix minutes plus tard, la file s'était
- vidée et tout était à jour. La règle que nous avons gardée : rapporter ce qu'on lit, et ne rien
- conclure d'une seule lecture.
Partie 2 — Une doctrine écrite en une ligne, pas répétée dans chaque prompt
Le soir du 29, la position du propriétaire s'est durcie en une phrase que le CEO a transmise telle quelle :
« je ne veux plus prendre de décisions autres que ce qui est dans le legacy et que le proprio a l'habitude de voir »
Les clients du propriétaire aiment le copier-coller : si l'ancien menu affiche une entrée avec un suffixe entre parenthèses, le nouveau affiche exactement la même chose, parenthèses comprises.
Un enfant headless ne peut pas poser de question. La doctrine est donc entrée dans le CLAUDE.md
du projet, dans la section que les enfants lisent pour décider seuls, comme règle de niveau 0
(l'appliquer, la citer, ne pas demander) :
- les menus, libellés et noms de pages suivent le système legacy en production ;
- quand deux systèmes legacy divergent, c'est le code qui écrit réellement en production qui
- l'emporte ;
- **quand le legacy a un défaut ou une limite manquante, appliquer les bonnes pratiques et le
- consigner** ;
- ne jamais copier un défaut qui touche à l'argent ou à la sécurité.
La troisième règle a prouvé sa valeur le soir même. Le système legacy avait un plafond sur le montant qu'une seule opération pouvait verser, mais un drapeau de configuration l'avait désactivé. La réaction du CEO tenait en une ligne : « il faut mettre une limite, sinon c'est dangereux. » Nous n'avons pas choisi un chiffre à l'intuition. Nous avons dimensionné le plafond à partir de l'historique de production, que le CEO a interrogé lui-même, en lecture seule, depuis la console de la base : le plus gros montant jamais versé, la distribution au-dessus, et la marge hebdomadaire de l'activité. La valeur par défaut du legacy aurait coupé 1 498 versements historiques réels : une bonne raison de ne pas copier la valeur, tout en rétablissant la limite.
Partie 3 — Un navigateur entre les mains du CEO, et ce qu'il ne peut pas prouver
Les enfants tournent en headless. Aucun ne voit d'écran. Chaque log de session de la journée se termine par la même ligne honnête : non vu dans un navigateur par un humain.
L'orchestrateur délègue donc une vérification après les sessions qui comptent, à un sous-agent qui pilote le Chrome du CEO lui-même via Claude in Chrome. Le CEO y est déjà connecté en admin. Le brief est court et strict :
- Lecture seule. Aucun formulaire soumis, et aucun clic sur Confirmer, Créditer, Payer, Refuser
- ou Supprimer. Sur les écrans qui touchent à l'argent, l'agent peut ouvrir une boîte de
- confirmation pour lire les montants qu'elle annonce, puis doit l'annuler sans rien saisir.
- Mesurer, pas capturer.
document.title,h1,scrollWidth, l'attribut d'un bouton, deux - captures d'écran au maximum.
- Rapporter en trente lignes : point par point, défauts classés par gravité, aucun correctif
- de code.
Six de ces passes ont tourné dans la journée. Elles ont trouvé de vrais problèmes que les tests avaient manqués :
- un tableau plus large de trois pixels que son conteneur, ce qui coupait la dernière colonne ;
- un bouton de suppression resté dans une ligne de tableau, contre la règle qui veut que les
- écritures vivent dans le pied de la modale ;
- un bouton de confirmation resté actif alors que le champ du motif était vide ;
- la recherche admin qui proposait des pages de l'espace client ;
- un bloc de synthèse affichant zéro quand aucun filtre de date n'était posé, alors que la liste
- en dessous affichait des dépôts.
Une passe a aussi signalé un défaut qui n'existait pas.
L'agent a indiqué que fermer une modale de détail laissait son identifiant dans l'URL, si bien qu'un rechargement la rouvrait. Il a testé de trois façons, et les trois ont échoué. L'enfant précédent avait déclaré le correctif « correct par construction » sans avoir pu reproduire le bug. La combinaison semblait accablante : un correctif que personne n'avait reproduit, et un vérificateur qui reproduisait le bug trois fois.
L'orchestrateur a rédigé une session pour le corriger, avec un test sur la vraie stack qui devait d'abord échouer. Puis il a demandé au CEO une vérification à la main de dix secondes : ouvrir une ligne, appuyer sur Échap, recharger. La modale est restée fermée.
L'onglet de l'agent était en visibilityState: hidden depuis le début. Les vraies frappes clavier
n'atteignaient jamais la page, donc chaque geste avait été émulé en JavaScript. L'agent l'avait dit
dans son rapport, mais l'orchestrateur n'en a pas tenu compte avant le test humain. La session de
correction a été réécrite en garde-fou de régression : elle ajoute le test sur la vraie stack et ne
modifie le code que si le test échoue. Le test est passé.
La leçon que nous avons gardée a deux moitiés :
- Celui qui implémente ne devrait pas être celui qui vérifie. Un enfant qui « ne parvient pas à
- reproduire » n'a rien prouvé.
- **Un outil de vérification a ses propres limites, et un vérificateur qui les énonce doit être
- cru.** Depuis ce jour, chaque brief dit : si l'onglet est masqué et que le clavier n'atteint pas
- la page, émuler, le dire, et ne pas conclure à un défaut sur cette seule base. Quand un seul geste
- tranche, dix secondes d'une main humaine valent mieux que n'importe quel outil.
Partie 4 — Un design system en une matinée, en passant d'abord par une maquette
Le propriétaire a envoyé une capture d'écran du nouvel admin, reconstruit la veille pour refléter la page legacy, et le rendu n'était pas bon :
- trois titres empilés les uns sur les autres ;
- un panneau de détail à droite qui mangeait le tableau, si bien que les dernières colonnes
- sortaient de l'écran ;
- des identifiants affichés seuls, sans les noms ;
- une barre latérale où chaque entrée portait une description de trois lignes.
Le CEO a demandé de refaire le design « en tenant compte de toutes les fonctions du legacy ».
L'orchestrateur n'a pas envoyé un enfant redessiner l'admin. Un enfant codait dans les mêmes dossiers à ce moment-là, et un design est une décision que le propriétaire doit voir avant que quiconque ne le construise. Il a délégué à un sous-agent de design, avec deux livrables et aucun accès en écriture au dépôt :
- Une spécification : principes, tokens, composants, et un tableau qui associe chaque défaut
- observé à la règle qui le corrige. Elle s'appuyait sur les pages legacy lues via le même
- navigateur et sur le code source, en lecture seule.
- Une maquette HTML statique de la pire page, remplie avec les lignes exactes de la capture du
- propriétaire, en largeur desktop et à 375 px.
Pendant que l'agent travaillait, le CEO a ajouté une phrase :
« l'onglet blanc à droite doit être un joli modal qui s'ouvre pour afficher plus de détails sur chaque ligne »
L'orchestrateur l'a transmise à l'agent en cours, qui a remodelé la spécification autour d'elle : le tableau garde toute la largeur, et les détails s'ouvrent dans l'unique primitive de dialogue qui existait déjà dans le projet.
La maquette s'est ouverte dans le navigateur du CEO, et il l'a validée. L'orchestrateur a ensuite désavoué l'agent de design sur un point, au nom de la doctrine. L'agent recommandait d'écrire la devise sous sa forme locale lisible. Le système legacy et le code existant écrivent tous deux le code ISO, et « copier ce que le propriétaire a l'habitude de voir » est une règle de niveau 0. L'orchestrateur ne désavoue pas un sous-agent sur une question de goût, seulement au nom d'une règle écrite.
La migration s'est ensuite déroulée en une série de sessions enchaînées :
- S1, une page pilote : shell, barre latérale, tableau groupé, modale de détail, et un test
- Playwright ajouté à la gate.
- S2 : filtres et pagination numérotée partagés entre les pages de liste.
- S3 : files de validation, où chaque bouton d'écriture est passé dans le pied de la modale,
- derrière une confirmation.
- S4a : les pages de compte et de détail.
Chaque passe navigateur a versé ses défauts dans le prompt de la session suivante. La dernière passe de la journée n'en a trouvé que trois, mineurs.
Partie 5 — « Ce sont les tests qui prennent le temps, pas les fixes »
En milieu d'après-midi, le CEO a proposé un raccourci :
« ce sont les tests qui prennent bcp de temps et non les fixes, exemple un fix peut prendre 5 mins et un test 1h, donc on va être très smart, on fixe bcp de bugs en série sans test et après on fait test groupé »
L'intuition méritait une mesure, pas un oui. L'orchestrateur a lu les horodatages des logs de chaque étape de la gate. La gate complète prenait quatre minutes : format, vet, tests Go, six vérifications front-end, build, tests navigateur et un smoke test de chaque page de menu contre la vraie stack. Une session entière prenait trente-cinq à quarante-deux minutes. La gate en représentait environ un dixième.
Le vrai coût était ailleurs, dans le surcoût fixe de chaque session et de chaque vérification :
- la lecture du contexte ;
- le rituel de clôture ;
- une passe navigateur de dix minutes après chaque session.
La réponse a donc été moitié oui, moitié non :
- Oui au regroupement. Cinq à dix défauts par session, une seule gate à la fin, une passe
- navigateur toutes les deux ou trois sessions, plus une après tout ce qui touche à l'argent.
- Oui à moins de nouveaux tests. Un nouveau test seulement pour l'argent, la sécurité, ou un
- défaut déjà revenu une fois. Un libellé, un espacement ou un titre se corrige sans test dédié.
- Non au push sans la gate. Ici, un push est un déploiement d'un système qui fait circuler de
- l'argent. Quatre minutes contre une production rouge, ce n'est pas un arbitrage.
Le CEO a accepté, et la règle est entrée dans le CLAUDE.md du projet au niveau 0, si bien que
chaque enfant suivant l'a appliquée sans qu'on le lui dise. La session suivante a corrigé huit
défauts en une passe avec une seule gate. Sa première exécution était rouge sur une seule
assertion, qui attendait l'ancien format de devise : c'était l'un des huit correctifs qui
fonctionnait comme prévu.
Une autre mesure est sortie de la même journée. Une session consacrée à rembourser la dette de la gate a remplacé la préparation de la base à chaque test par une base template. Le package de tests Go est passé de 265 secondes à 59. La vitesse est venue de la correction de la partie lente, pas de l'abandon de la vérification.
Partie 6 — Une décision d'argent qu'un enfant a refusé de prendre
Une session en file devait reproduire un interrupteur du legacy : un dépôt fait par un agent pour un client peut être marqué « Available » ou « Not Available ». Le prompt disait : ne construire le bouton que si l'API supporte déjà cette écriture. Ce n'était pas le cas, et l'enfant s'est arrêté au bon endroit. Il a consigné une question de niveau 1, à laquelle un enfant ne doit jamais répondre lui-même, et expliqué pourquoi un simple drapeau ne suffisait pas.
Dans le nouveau système, ce dépôt est un transfert dans le grand livre qui a déjà eu lieu. L'agent a été débité, le client a été crédité avec un bonus, et le client a peut-être déjà dépensé l'argent. Un statut qui ne déplace aucun argent reproduirait exactement le genre de défaut que la doctrine interdit de copier. L'enfant a recommandé une contre-passation explicite : des écritures inverses exactes, un motif obligatoire et journalisé, et un refus si le solde du client ne la couvre plus.
Le CEO a validé en une ligne. La session suivante l'a construite :
- Des écritures inverses exactes, lues dans le grand livre plutôt que recalculées aux taux du
- jour.
- Chaque poche restaurée à l'identique, quand l'agent avait payé depuis plusieurs.
- Une seule transaction, avec une réservation unique pour que deux admins qui cliquent en même
- temps ne produisent qu'une seule contre-passation.
- Des tests sur le chemin de l'argent pour chaque cas.
Dans le navigateur, la boîte de confirmation montre les deux côtés du mouvement avant que quiconque ne confirme.
La même session a noté, dans sa liste de reports, qu'un transfert de solde entre clients envoyé au mauvais numéro de téléphone n'avait pas non plus de retour possible. L'orchestrateur a recommandé d'y étendre la contre-passation, pour une raison simple : un mauvais numéro arrivera en production. Le CEO a accepté, et une session plus tard c'était livré comme une fonction séparée. La première n'a pas été refactorisée pour l'occasion.
Partie 7 — « Je ne sais pas quand fermer une session »
En fin de journée, le CEO a demandé à l'orchestrateur d'afficher son usage de contexte et de le commenter. Les chiffres n'avaient rien de remarquable :
- 287k tokens utilisés sur un million, 29 %, presque tout en conversation ;
- environ 30k ajoutés sur le dernier bloc de travail ;
- 680k tokens encore libres.
Ce qui comptait, c'était le peu que cela représentait. Treize sessions et six passes navigateur avaient chacune tourné dans leur propre processus ou contexte de sous-agent, et n'avaient renvoyé que leurs conclusions. Sans cela, l'orchestrateur aurait été compacté plusieurs fois.
Puis le CEO a avoué quelque chose que tout gros utilisateur de ces outils reconnaîtra :
« pour te dire la vérité je ne sais pas quand fermer et quand ouvrir une nouvelle session, vu que j'ai des tâches presque illimitées »
Avec une file sans fin, la file ne peut pas servir de signal. Le signal, c'est l'état du contexte. Nous avons écrit quatre conditions, et une seule suffit pour fermer :
- Un bloc de travail cohérent est terminé : poussé, fichiers d'état à jour. C'est le moment
- le moins cher, parce que la note de passation s'écrit toute seule.
- Le sujet change. Le contexte du premier sujet brouille le second.
- La session a déjà été compactée une fois. Un résumé suffit pour finir le bloc en cours, pas
- pour en commencer un nouveau.
- L'agent est pris en flagrant délit de croyance périmée : il s'appuie sur un état lu il y a
- des heures et qui a changé depuis. Celle-ci l'emporte sur tous les chiffres.
Les chiffres viennent en second : au-delà d'environ 300 à 400k tokens, ou de six à huit heures de travail, fermer à la prochaine frontière de bloc même si tout va bien. Et ne jamais fermer au milieu d'une boucle serrée « voir le défaut → corriger → revérifier » avec l'humain.
Fermer coûte peu parce que rien d'important ne vit dans la session. La file, le prompt suivant,
les logs, la doctrine et la règle de regroupement sont tous sur disque. Une session neuve les lit
en quelques minutes pour environ 30k tokens. Nous avons mis la règle dans le CLAUDE.md
global et dans la mémoire persistante, avec une instruction qui la rend utile : *le rappeler
soi-même à l'utilisateur, en une ligne, quand une condition devient vraie*. Nous avons aussi
inversé une habitude : une compaction automatique imminente est désormais un signal pour fermer,
pas pour compacter.
Comment reproduire cela
- Séparez l'orchestrateur des exécutants. La session à laquelle vous parlez arbitre, lance,
- surveille et vérifie. Chaque phase tourne dans un processus headless neuf qui ne connaît que le
- dépôt.
- Mettez la file et l'état sur disque, avec des pointeurs que l'orchestrateur peut vérifier
- mécaniquement après chaque phase : identifiant de session avancé, prompt suivant en file, arbre
- propre, poussé, production qui sert ce que vous croyez qu'elle sert.
- Écrivez la doctrine du propriétaire en une seule ligne de niveau décision dans le fichier
- que chaque enfant lit. Incluez la porte de sortie : « ne jamais copier un défaut d'argent ou de
- sécurité ; là où une limite manque, appliquer les bonnes pratiques et le consigner ».
- Donnez une échelle aux enfants : appliquer ce qui est pré-décidé, décider et consigner ce
- qui est réversible, s'arrêter sur l'argent, l'irréversible, le prix et le périmètre.
- Vérifiez dans un vrai navigateur avec un agent séparé en lecture seule, qui mesure plutôt
- qu'il ne capture. Demandez-lui d'énoncer les limites de son propre outil, et tranchez tout geste
- décisif isolé avec dix secondes d'une main humaine.
- Concevez via une maquette validée par le propriétaire avant qu'une session ne la construise,
- et ne désavouez un sous-agent qu'au nom d'une règle écrite, jamais d'un goût.
- Mesurez avant d'échanger des tests contre de la vitesse. Groupez les correctifs, lancez la
- gate une fois, n'écrivez de nouveaux tests que là où l'argent, la sécurité ou la récidive les
- justifient, et ne poussez jamais de code non vérifié qui se déploie.
- Écrivez quand fermer, et faites en sorte que l'agent le dise le premier.
CASP — le Coding-Agent State Protocol. Votre agent IA mène toute la
feuille de route sans jamais perdre le fil. Natif git, 100 % local, sous
licence MIT, zéro télémétrie. Conçu par Juste Thales Gnimavo, de ZeroSuite,
un CEO solo dont les produits tournent en production avec Claude pour seul
ingénieur.
Installation : npm i -g @justethales/casp · https://casp.sh ·
https://github.com/ThalesGnimavo/casp