🎯 OBJECTIF
Comprendre comment :
AGENTS.md en table des matières, init.sh, feature_list.json, progress.md, grille d'évaluateur, checklist d'état propre, linters qui parlent à l'agentharness-creator et le pack avancé d'OpenAI🔖 Version de l'outil
Claude Code 2.1 (Java 25, Spring Boot 4.1, ArchUnit 1.5).
🧠 MODÈLE MENTAL
Un cheval de course n'arrive pas premier grâce à ses muscles seuls. Il lui faut un harnais, une piste balisée, un jockey qui connaît le parcours et un chronomètre indépendant. Le modèle de langage, c'est le cheval : une puissance brute qui, lâchée seule dans un dépôt de code, galope dans toutes les directions, oublie où elle en était d'une session à l'autre et franchit la ligne d'arrivée en annonçant fièrement une victoire que personne n'a chronométrée.
Le harness engineering part d'un constat contre-intuitif : le même modèle, placé dans deux environnements différents, produit des résultats qui varient d'un ordre de grandeur. Ce n'est donc pas l'intelligence qui manque, c'est le système autour. Mitchell Hashimoto a formulé la discipline en une phrase début 2026 : chaque fois qu'un agent se trompe, on n'ajoute pas une consigne dans le prompt, on modifie l'environnement pour que cette erreur devienne structurellement impossible. LangChain l'a résumé en équation : Agent = Modèle + Harness. Le modèle contient l'intelligence, le harness la rend utile. Et comme on ne contrôle pas les poids du modèle, le harness est le seul levier qui nous appartient.
Pour ne pas rester abstrait, cette note suit une seule tâche du début à la fin : une équipe demande à un agent d'ajouter la réservation de stock à un service d'inventaire. On la regarde échouer, on diagnostique, puis on construit le harness étape par étape, dans l'ordre où un agent le traverse : avant la première session, pendant une session, à la fin d'une session, puis quand on le laisse tourner seul. Les sections suivent cet ordre.
Voici le point de départ. Une équipe demande à son agent, en une phrase : « ajoute la réservation de stock à l'API d'inventaire ». Le modèle est l'un des meilleurs du marché. Résultat de la première session :
Le cours walkinglabs classe ce qui vient de se passer en cinq modes d'échec. Aucun n'est une question d'intelligence : ce sont des trous dans l'environnement que le modèle comble en devinant.
| Mode d'échec | Ce qu'on a vu sur la réservation de stock | Trou dans l'environnement |
|---|---|---|
| Exigences vagues | « Ajoute la réservation » : expiration ? stock négatif ? L'agent invente | Personne n'a écrit ce que « fini » veut dire |
| Conventions implicites | Syntaxe d'ORM obsolète, pattern d'erreur ignoré | La règle n'est écrite nulle part dans le dépôt |
| Environnement incomplet | 40 % du contexte brûlé à comprendre comment lancer le projet | Pas de script de démarrage, versions non épinglées |
| Aucune vérification | « Les tests passent » sans commande de test | Aucune commande de vérification fournie |
| Perte d'état entre sessions | La session suivante redécouvre tout depuis zéro | Rien ne survit à la fin de la conversation |
Le premier réflexe est d'allonger la demande. C'est l'ère du prompt engineering : bien formuler, donner des exemples, imposer un format. Mais un prompt ne mémorise rien et ne voit pas le projet. Deuxième réflexe : montrer plus de choses au modèle. C'est le context engineering : fichiers d'instructions, RAG, mémoire, compaction. Le modèle voit alors tout… et déclare toujours « fini » sans preuve, parce que voir n'est pas vérifier. Le harness engineering est la couche externe : il ne se demande pas quoi dire ni quoi montrer, mais comment concevoir le système pour que le résultat soit vérifié et que la session suivante reparte proprement.
Le point de bascule a été documenté publiquement en quelques semaines : Mitchell Hashimoto nomme la pratique le 5 février 2026, OpenAI publie le 11 février son retour d'expérience sur un produit d'un million de lignes écrit sans une ligne manuelle, LangChain formalise en mars l'équation Agent = Modèle + Harness.
Le réflexe à combattre : « il faut un meilleur modèle »
Avant de changer de modèle, diagnostiquer lequel des cinq modes d'échec du tableau ci-dessus est en cause : chacun correspond à un sous-système du harness (section suivante), pas à une limite du modèle. Thoughtworks observe que ni les contrôles déterministes ni les contrôles par IA n'attrapent de façon fiable les échecs les plus coûteux (mauvais diagnostic, sur-ingénierie, exigence mal comprise). Ce sont des problèmes de harness, pas de poids.
🔑 Conclusion clé
Le prompt dit quoi faire, le contexte dit ce qu'on sait, le harness garantit que le résultat est vérifié et que la session suivante repart proprement. Un bon prompt dans un mauvais harness produit un travail convaincant et faux.
Avant de réparer, il faut savoir de quoi un harness est fait. Le cours walkinglabs le découpe en cinq briques, et chacune répond à une question simple :
D'autres sources décrivent le même découpage avec d'autres mots. LangChain parle de prompt système, outils, filesystem, sandbox et mémoire ; un survey académique parle de boucle d'exécution, registre d'outils, gestionnaire de contexte, store d'état, hooks et interface d'évaluation. Peu importe le vocabulaire : ce sont les mêmes cinq briques. C'est cette grille qu'on va suivre dans tout le reste de la note, et le schéma ci-dessous les place autour du modèle.
| Sous-système | Ce qu'il fournit au modèle | Artefacts typiques | Mode d'échec qu'il répare |
|---|---|---|---|
| Instructions | Où regarder, quelles règles ne jamais violer | AGENTS.md, docs/, definition of done |
Exigences vagues, conventions implicites |
| Outils | Capacité d'agir sur le monde | bash, fichiers, navigateur, MCP (voir mcp-model-context-protocol) | Décrit au lieu de faire |
| Environnement | Un monde reproductible et auto-descriptif | init.sh, lockfiles, versions, sandbox |
Environnement incomplet |
| État | Une mémoire qui survit à la session | feature_list.json, progress.md, git |
Perte d'état entre sessions |
| Feedback | La vérité sur ce qui marche | tests, linters, évaluateur, logs | Aucune vérification |
Comment savoir si un sous-système sert à quelque chose, ou si on empile des fichiers par superstition ? Le cours donne un instrument, emprunté à la recherche : l'ablation. Modèle fixé, tâche fixée, on retire un composant à la fois et on mesure la baisse. La plus forte baisse indique la contribution marginale la plus élevée pour cette tâche. Une baisse nulle ne veut pas dire « inutile » : le composant peut être redondant, mal conçu, ou simplement jamais sollicité par cette tâche. Le diagnostic doit croiser l'ablation avec les journaux d'échec. Le projet final du cours (projet 06) est exactement cela : assembler le harness complet, le benchmarker contre une version affaiblie, puis retirer les composants un par un.
Le cours cite une progression illustrative (pas une mesure publiée) sur une application TypeScript/React d'environ 20 000 lignes, modèle identique :
| Étape | Ajout | Taux de réussite |
|---|---|---|
| 1 | README seul | ~20 % |
| 2 | AGENTS.md avec specs |
~60 % |
| 3 | Commandes de vérification | ~80 % |
| 4 | Templates de fichier de progression | 80-100 % |
Le feedback d'abord
Si on ne devait construire qu'un sous-système, ce serait le feedback : lister explicitement les commandes de vérification (tests, typecheck, lint, « tout vérifier ») est l'investissement le moins cher et le plus rentable. Un agent qui peut se faire dire qu'il a tort corrige ; un agent qui ne peut pas déclare victoire.
🔑 Conclusion clé
Les cinq sous-systèmes sont la grille de diagnostic ; l'ablation est l'instrument de mesure. Le reste de la note construit chaque sous-système à l'étape du cycle de vie où il intervient : avant la première session, pendant une session, en fin de session, puis en boucle autonome.
Reprenons la réservation de stock. Avant de redemander quoi que ce soit à l'agent, on consacre une session entière à préparer le dépôt. Anthropic appelle cela l'agent initialisateur : son rôle n'est pas d'écrire une feature mais de laisser une base stable. Le playbook du cours fixe cinq artefacts obligatoires à la sortie de cette session :
AGENTS.md ou CLAUDE.md) ;feature_list.json) ;progress.md) ;init.sh) ;Et un critère de réussite, le test de session fraîche : un agent neuf, sans aucun contexte de conversation, avec le seul dépôt, doit pouvoir répondre à cinq questions. Que fait ce dépôt ? Comment le lancer ? Comment le vérifier ? Qu'est-ce qui reste inachevé ? Quelle est la meilleure prochaine étape ? Chaque « je ne sais pas » est un endroit où il devinera.
Un agent ne lit que quatre choses : le prompt système, la tâche, les fichiers du dépôt et la sortie de ses outils. Il ne consulte ni le chat d'équipe, ni le wiki, ni la tête d'un collègue. D'où le principe d'OpenAI : ce que l'agent ne peut pas atteindre en contexte n'existe pas. Tout ce qui compte doit être versionné : décisions d'architecture, plans d'exécution, specs produit, dette technique. C'est pour ça que notre agent utilisait une syntaxe d'ORM dépassée : la bonne convention n'existait pas, pour lui.
Le réflexe suivant est connu : l'agent se trompe, on ajoute une règle, le fichier passe de 300 à 450 puis 600 lignes. Quatre mécanismes le rendent contre-productif :
La règle de calibration du cours tient en deux listes. Reste dans le fichier racine : objectif et périmètre du dépôt, chemin de démarrage, chemin de vérification, contraintes non négociables, artefacts d'état attendus, règles de fin de session. Sort du fichier racine : cas particuliers historiques, détails d'implémentation d'un seul sujet, notes d'architecture locales (qui vont à côté du code), exemples qui ne concernent qu'un sous-système.
OpenAI a gardé AGENTS.md à environ 100 lignes, comme table des matières vers un répertoire docs/ structuré. Voici ce que l'initialisateur laisse pour notre service d'inventaire :
# AGENTS.md — service d'inventaire
## Vue d'ensemble
API REST Java 25 / Spring Boot 4.1, PostgreSQL 18. Gère les stocks par entrepôt.
## Démarrage
- Setup : ./init.sh # ✓ installe, vérifie, lance
- Tests : ./mvnw verify # ✓ obligatoire avant toute PR
- Lint architecture : ./mvnw -Parch # ✓ ArchUnit, bloque en CI
## Contraintes dures (non négociables)
- Les contrôleurs n'appellent jamais un repository directement (couche service obligatoire).
- Toute écriture en base passe par une transaction explicite.
- Aucun appel réseau sortant dans les tests unitaires.
## Definition of done
Une feature est terminée quand sa commande `verification` dans feature_list.json
passe ET que la preuve est consignée dans progress.md.
## Documentation (à lire selon la tâche)
- docs/architecture.md — couches et sens des dépendances. Lire avant tout nouveau module.
- docs/api-conventions.md — pagination, erreurs, versioning. Lire avant tout endpoint.
- docs/testing.md — Testcontainers, fixtures. Lire avant d'écrire un test.
- docs/exec-plans/ — plans en cours ; un fichier par chantier.
Les documents thématiques font 50 à 150 lignes chacun et ne sont chargés que si la tâche le justifie : c'est la progressive disclosure, exactement le mécanisme des skills décrit dans outiller-developpement-ia-skills-agents-instructions.
Le deuxième trou de notre première session était le temps perdu à comprendre comment lancer le projet. Le script d'initialisation le bouche, et il a une règle : si la vérification de base échoue, l'agent répare la base avant toute autre chose.
#!/usr/bin/env bash
# init.sh — reproducible startup for every agent session
set -euo pipefail
INSTALL_CMD="./mvnw -q dependency:resolve"
VERIFY_CMD="./mvnw -q verify"
START_CMD="./mvnw spring-boot:run"
echo "▶ working dir: $(pwd)"
docker compose up -d postgres # ✓ environment is self-describing
$INSTALL_CMD
$VERIFY_CMD # ✓ baseline must be green before any change
echo "▶ start with: $START_CMD"bashNuance : la doc n'est pas gratuite
Une étude de l'ETH Zurich a trouvé que les fichiers de contexte de dépôt n'améliorent pas systématiquement le taux de réussite et augmentent le coût d'inférence de plus de 20 %. Ce qui marche, c'est un fichier court, écrit à la main, dont chaque ligne vient d'un comportement fautif observé (la méthode Hashimoto), et une doc collocalisée avec le code concerné. Une doc périmée est pire qu'aucune doc : elle a l'air autoritaire et elle trompe.
🔑 Conclusion clé
La session d'initialisation ne produit pas de feature, elle produit un dépôt qui passe le test de session fraîche. Le fichier d'instructions est une carte, pas une encyclopédie : sa qualité se mesure à ce qu'il permet de trouver, pas à ce qu'il contient.
Le dépôt est prêt. L'agent revient pour la réservation de stock, cette fois avec un contexte vide mais un dépôt qui parle. Le cours fixe une routine de démarrage immuable, dans cet ordre, parce que chaque étape protège la suivante :
pwd : confirmer la racine du dépôt (éviter de travailler au mauvais endroit).progress.md : restaurer l'état durable avant tout changement.feature_list.json : savoir ce qui est fait, en cours, bloqué.git log --oneline -5 : voir ce qui a bougé en dernier../init.sh : démarrer de façon standard, pas de mémoire.sequenceDiagram
participant H as Humain
participant I as Agent initialisateur
participant R as Dépôt (état)
participant C as Agent de code (session N)
participant V as Vérification (tests, navigateur)
H->>I: prompt haut niveau
I->>R: init.sh + feature_list.json (toutes à not_started)
I->>R: progress.md + premier commit
Note over R: L'état vit dans le dépôt, pas dans la conversation
loop Chaque nouvelle session (contexte vide)
C->>R: lit progress.md + git log + feature_list.json
C->>V: lance init.sh, vérifie l'état de base
C->>C: choisit UNE feature not_started (WIP = 1)
C->>C: implémente la feature
C->>V: exécute la commande de vérification de la feature
V-->>C: preuve (sortie de test, capture)
C->>R: passes = true + evidence, commit, progress.md mis à jour
Note over C,R: État propre : build OK, tests OK, pas d'artefact de debug
endmermaidLe troisième trou de la première session, c'était six chantiers ouverts et aucun fini. Avec une capacité de contexte C répartie sur k tâches, chaque tâche reçoit C/k ; sous un seuil, rien n'aboutit. L'exemple du cours sur une API à huit features : sans contrainte, cinq features ouvertes, 800 lignes sur 12 fichiers, 20 % de tests verts ; avec WIP = 1, 200 lignes par feature, 100 % de tests verts par session.
feature_list.json : le primitif, pas le documentLa différence entre un document et un primitif : un document est lu par des humains et peut être ignoré ; un primitif est exécuté par le harness. Le planificateur y choisit la prochaine feature, le vérificateur y autorise les transitions d'état, le rapport de fin de session en est généré. Chaque entrée porte un triplet : comportement attendu, commande de vérification, état.
{
"features": [
{
"id": "F03",
"priority": 3,
"area": "stock",
"title": "Réserver une quantité sur un entrepôt",
"user_visible_behavior": "POST /warehouses/{id}/reservations avec {sku, quantity} retourne 201 et décrémente le stock disponible",
"verification": "./mvnw test -Dtest=ReservationControllerIT && curl -sf -X POST localhost:8080/warehouses/w1/reservations -d '{\"sku\":\"A-100\",\"quantity\":2}' -H 'Content-Type: application/json'",
"status": "passing",
"evidence": "commit 4f2a9c1 — ReservationControllerIT 6/6 vert, curl 201",
"notes": "Le stock négatif renvoie 409, cf. docs/api-conventions.md"
},
{
"id": "F04",
"priority": 4,
"area": "stock",
"title": "Libérer une réservation expirée",
"user_visible_behavior": "Un job planifié remet en stock les réservations de plus de 15 min",
"verification": "./mvnw test -Dtest=ReservationExpiryJobTest",
"status": "in_progress",
"evidence": null,
"notes": null
}
]
}jsonRègles de la machine à états : quatre états (not_started, in_progress, blocked, passing), une seule feature in_progress à la fois, et seul le succès de la commande verification autorise le passage à passing. Dans l'expérience d'Anthropic, l'agent n'avait le droit de modifier que le champ de réussite, jamais de supprimer une feature : c'est ce qui empêche la victoire prématurée par effacement du périmètre.
Le sur-périmètre tue la finition
Demandez « ajoute la réservation de stock » sans contrainte et l'agent crée le modèle, l'endpoint, le job d'expiration, refactore la gestion d'erreurs et réorganise les dossiers : six changements à moitié faits. Faire moins mais finir bat systématiquement faire large. La liste de features n'est pas une to-do, c'est le périmètre que l'agent n'a pas le droit d'élargir ni de rétrécir.
🔑 Conclusion clé
Une session de travail, c'est une routine de démarrage fixe, une seule feature choisie dans un primitif que le harness exécute, et une transition d'état que seule une commande verte autorise. L'agent ne décide ni de l'ordre, ni du périmètre, ni du moment où c'est fini.
Notre agent a implémenté F03 et annonce que c'est terminé. Le quatrième trou de la première session, c'était cette phrase sans preuve. Ici, le harness la refuse structurellement.
Les réseaux de neurones modernes sont systématiquement sur-confiants : la confiance rapportée dépasse la précision réelle. L'agent juge « localement » (le code a l'air juste, les tests unitaires passent) alors que l'échec est « global » (migration absente, config manquante, deux composants mockés chacun de leur côté qui ne s'emboîtent pas). Exemple canonique du cours : une réinitialisation de mot de passe où schéma, endpoint et template sont écrits, les tests unitaires verts, et rien ne fonctionne bout en bout.
Trois couches de validation, sans raccourci entre elles :
Anthropic a constaté que donner à l'agent des outils d'automatisation de navigateur et lui demander de tester « comme un humain le ferait » a changé le résultat : il a trouvé des bugs invisibles à la lecture du code. OpenAI a intégré le protocole DevTools de Chrome dans le runtime de l'agent : lancer une instance isolée, capturer le DOM, comparer visuellement, interroger les logs et métriques, et boucler parfois six heures sans intervention.
Un modèle qui note son propre travail le loue avec assurance, même quand la qualité est visiblement médiocre pour un humain. Anthropic a documenté ce biais et l'a corrigé en séparant Planner, Generator et Evaluator, l'évaluateur testant l'application qui tourne via Playwright et notant selon des critères mesurables. Avant de coder, générateur et évaluateur négocient un contrat de sprint : des critères d'acceptation testables. L'évaluateur a attrapé un outil de remplissage qui ne posait que les extrémités, des routes renvoyant 422, un enregistrement audio resté un stub.
Le projet 05 du cours rend ce choix mesurable : on implémente la même feature trois fois, en ajoutant un rôle à chaque fois (agent seul qui se note, puis générateur + évaluateur, puis planificateur + générateur + évaluateur), et on compare les grilles. La grille d'évaluateur fournie note six dimensions de 0 à 2 (correction, vérification, discipline de périmètre, fiabilité, maintenabilité, prêt pour le handoff) et rend un verdict : Accept, Revise ou Block. Elle se calibre : on compare ses scores au jugement humain, on resserre les critères là où ils divergent, et on recommence trois à cinq cycles jusqu'à alignement.
flowchart LR
S[("État externe<br/>progress.md · feature_list.json · issues")] --> P["Planifier<br/>lire l'état, choisir UNE tâche"]
P --> A["Agir<br/>générateur, worktree isolé"]
A --> V{"Vérifier<br/>évaluateur indépendant<br/>tests + navigateur"}
V -- échec, message actionnable --> A
V -- preuve --> C["Committer<br/>seul le validé rejoint main"]
C --> H["Passer la main<br/>mettre à jour l'état externe"]
H --> S
STOP{{"Condition d'arrêt<br/>machine-vérifiable"}} -.-> PmermaidLe deuxième trou de la première session, la convention implicite, se bouche ici aussi, mais mécaniquement. L'idée la plus réutilisable du retour d'OpenAI : les règles d'architecture sont appliquées par des linters personnalisés, des tests structurels et des jobs CI qui bloquent la PR. Et le message d'erreur n'est plus écrit pour un humain : il injecte la correction dans le contexte de l'agent, avec un lien vers la doc concernée.
// ArchUnit test — the failure message is written FOR the agent, not for a human reviewer
@ArchTest
static final ArchRule controllers_must_not_touch_repositories =
noClasses().that().resideInAPackage("..controller..")
.should().dependOnClassesThat().resideInAPackage("..repository..")
.because("""
Controllers must call a @Service, never a repository. // ⚠️ hard constraint
Fix: move the data access into an existing service in src/main/java/.../service,
or create one. Rationale and examples: docs/architecture.md#layers.
Do NOT add an exception to this rule.""");javaThoughtworks classe ces contrôles en deux familles : feedforward (guides qui anticipent : doc, types, scripts de bootstrap) et feedback (capteurs qui observent : linters, tests, revue par IA), et en deux natures : computationnels (déterministes, millisecondes) et inférentiels (sémantiques, lents, non déterministes). Règle de placement : les contrôles bon marché en pré-commit, les contrôles coûteux dans le pipeline.
🔑 Conclusion clé
Le jugement de complétion appartient au harness, pas à l'agent. Trois ingrédients : une definition of done exécutable, une vérification bout en bout avec les vrais outils, un évaluateur qui n'est pas l'auteur. Et chaque signal d'échec doit dire à l'agent comment corriger, pas seulement que c'est faux.
F03 est vérifiée, commitée. Reste le cinquième trou : que la session suivante ne redécouvre pas tout. Le cours impose une routine de fin de session symétrique de celle du démarrage : consigner le progrès, mettre à jour le statut des features, écrire une note de handoff si nécessaire, committer le travail sûr, laisser un chemin de redémarrage propre.
Cinq conditions, simultanées : build vert, tous les tests verts (y compris les anciens), progrès consigné, aucun artefact de debug, chemin de démarrage fonctionnel. En manquer une, la session n'est pas « finie ». La checklist d'état propre du cours ajoute une vérification de cohérence : la liste de features doit refléter la réalité, aucune entrée passing qui ne le soit pas.
Le fichier de progression est la source de vérité de l'état courant : racine du dépôt, commande de démarrage, commande de vérification, feature prioritaire non terminée, bloqueurs, puis un journal par session (objectif prévu, réalisé, vérifications lancées, commits, risque introduit, prochaine action). Pour les sessions longues ou les projets à plusieurs chantiers, une note de handoff compacte s'y ajoute : ce qui est vérifié, ce qui a changé, ce qui est encore cassé ou non vérifié, la meilleure prochaine action et ce qu'il ne faut pas toucher, les commandes clés de démarrage, vérification et debug.
Sans visibilité sur ce qui s'exécute, les retries sont aveugles (l'agent tape au hasard), l'évaluation devient subjective et le progrès est invisible. Le cours chiffre l'écart : implémenter un mode sombre prend 45 minutes en trois ou quatre itérations à l'aveugle, 15 minutes en une itération avec logs et traces accessibles. Deux niveaux à prévoir :
L'agent ne peut pas s'instrumenter lui-même : il ne sait pas ce qu'il ne sait pas. Le harness doit imposer des formats constants et une collecte automatique. OpenAI a donné à ses agents un accès direct aux logs et métriques via LogQL et PromQL, et le cours recommande les conventions sémantiques OpenTelemetry pour l'IA générative. Pour la consommation de tokens côté outillage, voir codeburn-stats-de-tokens-et-couts-pour-claude-code-agents-ia.
Lehman l'avait observé pour tout logiciel : un système en changement continu se complexifie sauf effort actif. Avec des agents qui produisent plus vite que les humains ne relisent, l'entropie explose. Le cours illustre une dégradation sur douze semaines : build vert de 100 à 68 %, tests de 100 à 61 %, démarrage de 5 à plus de 60 minutes. Deux parades au-delà de l'état propre par session :
Le harness a lui-même une dette
Chaque composant du harness encode une hypothèse sur une faiblesse du modèle. Anthropic a supprimé la décomposition en sprints et les resets de contexte quand un modèle plus récent n'avait plus « d'anxiété de contexte ». Cursor a retiré ses premiers garde-fous et son contexte statique au profit d'un contexte dynamique que l'agent va chercher. Auditer régulièrement : quelle règle, quel garde-fou n'a plus de raison d'être ? La complexité du harness ne baisse pas forcément, elle se déplace vers des tâches jusque-là impossibles.
🔑 Conclusion clé
Une session se termine quand la suivante peut démarrer sans aide humaine : état propre vérifié, handoff écrit, logs accessibles. Et le harness lui-même se nettoie, par ramasse-miettes planifié et par ablation périodique de ce qui ne sert plus.
Le harness tient sur une session. L'étape suivante est de ne plus être là. La progression observée dans toute l'industrie : prompts un par un, puis longs prompts multi-étapes, puis auto-réflexion de l'agent, puis jugement d'arrêt indépendant. Le pont est le modèle du « but » : on fournit un objectif, une méthode de vérification et une condition d'arrêt, et l'agent boucle jusqu'à satisfaction.
Le projet 07 du cours fait construire trois boucles sur le harness de la section précédente, chacune confiant un peu plus à la machine :
| Boucle | Ce qu'on écrit | Condition d'arrêt | Quand l'utiliser |
|---|---|---|---|
| Boucle à objectif | Un goal.md : objectif, méthode de vérification, contraintes |
Objectif atteint, ou nombre de tours / temps / budget maximum | Une tâche moyenne à critère clair (80 % de couverture, validation sur tous les endpoints) |
| Boucle minutée | Un prompt de surveillance : quoi vérifier, quoi faire, quand appeler un humain | Pas de fin ; cadence de 10 à 30 min | Une vérification récurrente qu'on faisait à la main (tests horaires, audit de TODO, dépendances) |
| Maker / checker | Trois prompts : maker, checker, contrôle de boucle, plus un loop-state.md |
N passes consécutives du checker, ou tours maximum | Une feature où la relecture compte autant que l'écriture |
Six primitives rendent ces boucles viables : automatisations (cron, webhooks), worktrees isolés, skills, connecteurs, sous-agents maker/checker, et état externe hors conversation. L'exemple de référence est la boucle de recherche de Karpathy : un program.md en langage naturel décrit la méthodologie, et un cliquet à neuf étapes ne garde sur main que les commits qui améliorent la métrique. Résultat : environ 11 % de temps d'entraînement gagné par accumulation de micro-optimisations, sans humain dans la boucle.
Quatre coûts silencieux des boucles longues : dette de vérification (on saute la confirmation machine), pourriture de compréhension (plus personne ne comprend le code généré), abandon cognitif (on accepte sans relire), explosion de tokens (le contexte croît de façon quadratique avec les itérations). La phrase à retenir du cours : les boucles rendent la génération presque gratuite et font du jugement la ressource rare.
Dès qu'un agent a besoin de spécialisation, de parallélisme, d'état partagé, de vérification et de reprise, ce n'est plus une boucle, c'est un graphe : des nœuds (code déterministe, appel de modèle, outil ou agent complet), des arêtes (handoffs avec parallélisme, conditions, retry, rollback), un état partagé et des règles de routage. Le projet 08 montre que le graphe n'est pas un choix de design mais ce qu'une boucle devient quand on l'écrit noir sur blanc : en dessinant la boucle maker/checker, on trouve toujours au moins une arête implicite, une décision qui vivait cachée dans le contexte de l'agent. Trois ajouts caractéristiques :
Trois échecs des boucles monolithiques y trouvent une réponse : la loi de Goodhart (le bot support qui ferme les tickets au lieu de les résoudre), la cécité vers le haut (une boucle ne questionne jamais son objectif) et le conflit entre boucles indépendantes. Cinq critères, dont au moins trois doivent tenir avant de dessiner un graphe : la tâche se décompose en unités indépendantes ; des branches ou rollbacks méritent d'être explicites ; l'état intermédiaire vaut d'être sauvegardé pour reprise ; la definition of done est vérifiable automatiquement ; le bénéfice de coordination dépasse son coût.
🔑 Conclusion clé
Déléguer, c'est écrire la condition d'arrêt avant la tâche. Une boucle est un harness qui se relance seul ; un graphe est une boucle dont on a rendu les décisions cachées explicites. Dans les deux cas, la bande passante de relecture humaine reste le goulot : le parallélisme accélère la génération, jamais le jugement.
On a construit un harness à la main. Les outils du marché en embarquent un, et les lire avec la grille des cinq sous-systèmes montre qu'ils répondent aux mêmes problèmes par des choix différents. Le même modèle peut scorer très différemment selon le harness : LangChain est passé du top 30 au top 5 de Terminal Bench 2.0 en ne touchant que le harness, modèle inchangé.
| Sous-système | Claude Code | Codex | Pi | DeepSeek Harness |
|---|---|---|---|---|
| Instructions | CLAUDE.md en quatre portées (organisation, utilisateur, projet, local), sous-dossiers chargés à la demande, mémoire auto plafonnée |
AGENTS.md ≤ 100 lignes comme annuaire, invariants seulement, détails dans docs/ |
AGENTS.md hiérarchique + SYSTEM.md, prompt système minimal, règles en skills |
Tout est plugin, aucune convention de fichier imposée |
| Contexte / état | Compaction en cinq niveaux (sans perte d'abord, résumé LLM en dernier), historique append-only avec resume et fork | Write / select / compress / isolate ; seuls les champs d'environnement modifiés sont renvoyés à chaque tour | Compaction programmable (garde ~20 k tokens récents), arbre de sessions avec retour à tout nœud | Journal de session append-only, invariant « visible par le modèle = journalisé » |
| Outils | Skills, MCP, hooks, sous-agents, chacun à sa place | Worktree git par tâche, spawn_agent natif |
Extensions TypeScript sur tout le cycle de vie | Capability seams : définition, fournisseur, consommateur ; FS local, E2B ou distant interchangeables |
| Feedback | Classifieur de permissions, hooks PostToolUse et Stop qui forcent une vérification quand l'agent dit « fini » |
Commandes de vérification dans AGENTS.md, politiques d'approbation, plan mode |
Aucun garde-fou natif : extensions communautaires (PROGRESS.md, LESSONS.md) |
Hooks d'événements tools/pre-execute, permission / guard / policy |
| Philosophie | Par addition : mémoire, permissions, sous-agents dans le cœur | Par soustraction : cœur mince, conventions de dépôt | Rien n'est décidé : tout est point d'extension | Le harness comme OS agnostique du modèle, l'agent comme application |
Deux lectures transversales. D'abord, chacun a inventé sa propre réponse à la victoire prématurée : le hook Stop de Claude Code, la commande de vérification obligatoire de Codex, l'extension session-summary de Pi, l'événement agent/turn-stopping de DeepSeek. Ensuite, tous convergent vers un journal append-only et rejouable comme fondation de l'état : le handoff est garanti par la couche de stockage, pas par la mémoire du modèle.
Cursor va plus loin et traite son harness comme un produit : évals hors ligne, A/B tests en ligne (latence, tokens, nombre d'appels d'outils, taux de cache), un « keep rate » qui mesure la part de code généré qui survit, une taxonomie des erreurs d'outils où toute erreur inconnue est un bug du harness, et un harness ajusté par modèle (format d'édition, prompts). En un sprint, les erreurs d'appel d'outil inattendues ont baissé d'un ordre de grandeur sans changer de modèle.
Deux retours d'expérience donnent l'échelle de ce qu'un harness mûr permet :
| Source | Dispositif | Résultat |
|---|---|---|
| OpenAI (août 2025 → janvier 2026) | 3 puis 7 ingénieurs, zéro ligne manuelle, agents Codex | ~1 M de lignes, ~1 500 PR fusionnées, ~3,5 PR/jour/personne |
| Anthropic (harness v1 → v2) | Planner + Generator + Evaluator, puis simplification | Même type d'application : de 6 h et 200 $ à 3 h 50 et 125 $ |
🔑 Conclusion clé
Les harness du marché ne diffèrent pas par leur boucle (toujours la même : raisonner, appeler un outil, observer) mais par ce qu'ils mettent autour, et surtout par ce qu'ils décident à votre place. Choisir un outil, c'est choisir combien du harness on veut écrire soi-même.
Tout ce qui précède existe sous forme prête à copier. Trois niveaux, du plus léger au plus structuré.
| Template | Rôle | Étape du cycle |
|---|---|---|
AGENTS.md / CLAUDE.md |
Règles de travail, chemin de démarrage et de vérification, definition of done | Initialisation |
init.sh |
Trois variables à remplir (INSTALL_CMD, VERIFY_CMD, START_CMD) |
Initialisation |
feature_list.json |
Liste de features avec statut, vérification, preuve | Initialisation, puis chaque session |
claude-progress.md |
État vérifié courant + journal par session | Chaque session |
session-handoff.md |
Note compacte : vérifié, changé, cassé, prochaine action, à ne pas toucher | Fin de session |
clean-state-checklist.md |
Les cinq conditions d'état propre + cohérence de la liste de features | Fin de session |
evaluator-rubric.md |
Six dimensions notées 0-2, verdict Accept / Revise / Block, à calibrer | Vérification |
quality-document.md |
Santé du projet notée A-D par domaine et couche, support de la simplification | Périodique |
harness-creatorLe cours livre aussi un skill (voir outiller-developpement-ia-skills-agents-instructions pour la notion) qui automatise la création et l'audit d'un harness :
npx skills add walkinglabs/learn-harness-engineering --skill harness-creatorbashSon workflow : inspecter ce qui existe (fichiers d'instructions, d'état, commandes de vérification), ne demander que ce qui ne s'infère pas (agent cible, nom de fichier, droit d'écraser), démarrer minimal. Il note cinq sous-systèmes (instructions, état, vérification, périmètre, cycle de vie), traite le score le plus bas comme candidat goulot à confirmer par les logs et les échecs réels, et recommande les deux ou trois premiers changements. Quatre scripts Node : create-harness.mjs (échafaudage), validate-harness.mjs (audit), render-assessment-html.mjs (rapport partageable), run-benchmark.mjs (benchmark structurel). Sept fiches de patterns l'accompagnent : persistance mémoire, runtime de skills, context engineering, registre d'outils, coordination multi-agents, cycle de vie et bootstrap, et une liste de quinze pièges non évidents.
Un benchmark structurel n'est pas une mesure d'efficacité
Le benchmark du skill vérifie que les fichiers existent et sont cohérents. Il ne dit pas si l'agent travaille mieux : cela exige des sessions avant / après sur des tâches représentatives, autrement dit l'ablation de la section 3.
Quand le dépôt a dépassé le harness minimal, le cours propose une structure opinionée dérivée du retour d'OpenAI : AGENTS.md et ARCHITECTURE.md à la racine, un docs/ avec design docs et croyances fondatrices, plans d'exécution actifs et terminés plus un suivi de dette, specs produit, artefacts générés (schéma de base), références au format llms.txt pour les outils externes, et des fichiers de politique explicites : design, frontend, plans, sens produit, score de qualité, fiabilité, sécurité. Une bibliothèque de procédures (SOP) transforme les schémas de l'article en étapes : mise en place de l'architecture par couches, encodage d'une nouvelle connaissance dans le dépôt, stack d'observabilité locale, boucle de validation UI via Chrome DevTools. La règle d'adoption : commencer par le pack minimal, copier le pack avancé quand on en a besoin, et mettre à jour qualité, fiabilité et plans dans le flux normal de travail, pas lors d'une journée de nettoyage.
Le cours fournit une carte de méthode qui résume la discipline en une règle : ajouter le plus petit artefact qui répare l'échec observé, jamais un paragraphe de plus dans le fichier d'instructions global.
| Symptôme observé | Artefact à ajouter | Sous-système | Étape du cycle | Effort |
|---|---|---|---|---|
| Chaque session redécouvre le projet | progress.md + dépôt comme source de vérité |
État | Initialisation | Faible |
| L'agent devine les conventions | AGENTS.md ≤ 100 lignes + docs/ thématiques |
Instructions | Initialisation | Faible |
| Le setup mange le contexte | init.sh idempotent, lockfiles, versions épinglées |
Environnement | Initialisation | Faible |
| « Fini » sans preuve | Commandes de vérification + definition of done + checklist d'état propre | Feedback | Session, fin | Faible, meilleur ROI |
| Six features à moitié faites | feature_list.json, WIP = 1 |
État + Instructions | Session | Faible |
| La session suivante ne sait pas quoi faire | session-handoff.md |
État | Fin | Faible |
| Revue subjective, à l'humeur | evaluator-rubric.md calibré, évaluateur séparé |
Feedback | Vérification | Élevé |
| Violations d'architecture récurrentes | Linter / test structurel avec message pour agent, bloquant en CI | Feedback | Vérification | Moyen |
| Retries aveugles | Logs et traces accessibles à l'agent, formats constants | Observabilité | Fin, boucle | Moyen |
| Dégradation lente | Ramasse-miettes planifié + quality-document.md |
État + Feedback | Périodique | Moyen |
| On ne sait pas ce qui sert | Ablation à modèle fixé | Mesure | Périodique | Moyen |
⚡ TL;DR — chaque concept en une ligne
Harness ✓ Tout ce qui n'est pas le modèle : instructions, outils, environnement, état, feedback ; Agent = Modèle + Harness. ⚠ Un bon prompt dans un mauvais harness produit un travail convaincant et faux.
Cinq modes d'échec ✓ Exigences vagues, conventions implicites, environnement incomplet, aucune vérification, perte d'état : tous réparables sans changer de modèle. ⚠ « Il faut un meilleur modèle » est presque toujours un diagnostic paresseux.
Ablation ✓ Modèle fixé, retirer un composant à la fois et mesurer la baisse : c'est la seule façon de savoir ce qui compte. ⚠ Une baisse nulle ne prouve pas l'inutilité : le composant peut être redondant ou jamais sollicité par cette tâche.
Session d'initialisation ✓ Cinq artefacts (instructions, feature list, progression, init.sh, premier commit) et un critère : le test de session fraîche. ⚠ Une session qui commence par une feature sans ces artefacts rejoue le premier échec.
AGENTS.md en table des matières
✓ ~100 lignes qui disent quoi, comment lancer, comment vérifier, et routent vers docs/.
⚠ Le fichier géant brûle le contexte, noie les priorités et pourrit ; la doc périmée est pire qu'aucune doc.
Routine de démarrage fixe ✓ pwd, progression, feature list, git log, init.sh, smoke test, réparer la base, choisir une feature. ⚠ Sauter le smoke test laisse un point de départ cassé masqué par le nouveau travail.
feature_list.json et WIP = 1
✓ Un primitif exécuté par le harness : comportement + commande de vérification + état, une seule feature active.
⚠ Si l'agent peut supprimer des features ou passer à passing sans commande verte, il déclarera victoire par effacement.
Vérification bout en bout ✓ Trois couches sans raccourci (statique, exécution, système) avec de vrais outils (navigateur, logs). ⚠ Les tests unitaires mockés passent des deux côtés d'une interface qui ne s'emboîte pas.
Générateur / évaluateur séparés ✓ Un évaluateur indépendant, une grille à six dimensions calibrée contre le jugement humain, un contrat de sprint négocié avant le code. ⚠ Un modèle qui note son propre travail le loue avec assurance, même médiocre.
Linters à messages pour agent ✓ Règles d'architecture appliquées mécaniquement, erreur qui injecte la correction et le lien doc dans le contexte. ⚠ Un message d'erreur écrit pour un humain fait tourner l'agent en rond.
État propre et handoff ✓ Cinq conditions simultanées en fin de session, plus une note de handoff qui dit aussi ce qu'il ne faut pas toucher. ⚠ « On nettoiera plus tard » devient permanent ; l'entropie se compose.
Observabilité interne ✓ Logs runtime + artefacts de processus accessibles à l'agent, formats constants, collecte imposée. ⚠ L'agent ne s'instrumente pas seul : il ne sait pas ce qu'il ne sait pas.
Loop et graph engineering ✓ But + vérification + condition d'arrêt, puis nœuds / arêtes / état partagé quand la coordination l'exige. ⚠ La génération devient gratuite ; le jugement humain reste le goulot et le parallélisme ne l'accélère pas.
Harness du marché ✓ Même boucle partout ; ils diffèrent par ce qu'ils décident à votre place (addition, soustraction, extension, plugin). ⚠ Aucun ne fournit la definition of done de votre projet : c'est toujours à vous de l'écrire.
Outillage de démarrage ✓ Huit templates, un skill qui échafaude et audite, un pack avancé quand le dépôt grossit. ⚠ Un benchmark structurel vérifie la présence des fichiers, pas l'efficacité : seule l'ablation la mesure.
🎓 À retenir
feature_list.json n'est utile que si le harness l'exécute (planification, gating, rapport). Un fichier que l'agent peut ignorer ou réécrire librement n'est qu'un mémo.AGENTS.md, init.sh, feature_list.json, claude-progress.md, session-handoff.md, clean-state-checklist.md, evaluator-rubric.md, quality-document.md).AGENTS.md en table des matières, linters à messages pour agent, ramasse-miettes.