Harness engineering : le cas Codex et une mise en œuvre sûre pour débuter
Comprendre le harness engineering : cas Codex, rôles clairs, accès fichiers limités et tests Node.js exécutables.
Vous demandez à un agent IA de nettoyer un dépôt, et il modifie au passage une configuration hors périmètre. Vous lui demandez de lancer les tests, et il répond « tout est bon » sans laisser de trace exploitable de la commande. Ce sont des problèmes fréquents lorsqu’une équipe commence à déléguer du travail à Claude Code, Codex ou un autre agent de développement.
Le prompt n’est qu’une partie du sujet. Il faut aussi préciser ce que l’agent peut voir, les outils qu’il peut utiliser, les conditions qui doivent l’arrêter et la preuve attendue à la fin. Le harness engineering consiste à concevoir ce cadre d’exécution. On peut voir le harness comme l’échafaudage qui aide l’agent à avancer sans lui confier toutes les décisions.
Ce guide part du retour d’expérience publié par OpenAI sur Codex. Il construit ensuite un petit harness qui limite les accès aux fichiers, refuse les écrasements et fournit des tests exécutables. La dernière section distingue clairement ce qui a été vérifié de ce qui ne l’a pas été.
À retenir
- Un harness n’est pas un simple script d’enrobage. Il réunit connaissance du dépôt, outils, droits, tests, journaux, procédures de reprise et validation humaine.
- Dans son cas d’usage Codex, OpenAI a rendu la structure du dépôt, le comportement de l’application et les règles de qualité lisibles et contrôlables par les agents.
- L’IA peut chercher, préparer des brouillons et répéter des tâches. La suppression, la production, les communications externes et les dépenses restent d’abord sous décision humaine.
- Une vérification lexicale du début d’un chemin ne constitue pas une sandbox complète. Il faut aussi traiter les liens symboliques, l’écrasement, les droits du processus et l’isolation du système.
- « Testé » doit toujours indiquer la commande, le résultat et le périmètre. Le message de réussite d’un modèle ne constitue pas une preuve.
Ce que recouvre vraiment le harness engineering
Un prompt indique l’objectif d’une exécution. Le harness définit l’environnement dans lequel cette instruction sera tentée.
| Couche | Question posée | Exemple minimal |
|---|---|---|
| Contexte | Que peut apprendre l’agent ? | AGENTS.md, un dossier ciblé, une spécification versionnée |
| Outils | Que peut-il faire ? | Lire, tester et créer un brouillon |
| Autorisations | Où doit-il s’arrêter ? | Validation humaine avant suppression ou envoi |
| Vérification | Qu’est-ce qui signifie « terminé » ? | npm test se termine avec le code 0 |
| Observabilité | Comment retracer un échec ? | Commande, diff et sortie d’erreur utile |
| Reprise | Comment annuler une mauvaise exécution ? | Petits commits, mode simulation et procédure de retour arrière |
Le modèle n’est qu’un composant de cette boucle :
Objectif humain et règles de validation
↓
Règles du dépôt → agent IA → outils autorisés
↑ ↓
Spécifications tests, journaux et diffs
└── corriger en cas d'échec, solliciter l'humain si un jugement est requis ──┘
Changer de modèle ne rendra pas visible une décision d’architecture restée dans la tête d’une personne. À l’inverse, le même modèle devient plus fiable lorsque les informations utiles sont faciles à trouver et que les critères d’acceptation peuvent être exécutés.
Pourquoi le sujet a pris de l’ampleur en 2026
Une source importante de l’intérêt actuel est l’article d’OpenAI Harness engineering: leveraging Codex in an agent-first world, publié le 11 février 2026.
OpenAI y décrit une expérience partie d’un dépôt Git vide. Sur environ cinq mois, trois ingénieurs pilotant Codex ont ouvert et fusionné près de 1 500 pull requests. L’article indique qu’à ce stade le dépôt approchait le million de lignes et que le produit en bêta interne comptait des utilisateurs quotidiens ainsi que des testeurs alpha externes. Ces chiffres décrivent ce projet précis ; ils ne garantissent pas le même débit à une autre équipe.
La leçon utile n’est donc pas le nombre de pull requests. L’équipe a repensé l’environnement en partant du principe que les agents réaliseraient l’implémentation, tandis que les humains fixeraient les priorités, traduiraient les retours en critères d’acceptation et valideraient les résultats. Le cas publié présente notamment les choix suivants :
- stocker plans, décisions de conception et règles de qualité dans des artefacts versionnés du dépôt ;
- utiliser un
AGENTS.mdcourt comme carte vers des sources plus détaillées, plutôt qu’un manuel monolithique ; - rendre l’interface, les journaux, les métriques et les traces directement consultables par l’agent ;
- imposer les directions de dépendances et d’autres invariants avec des linters dédiés et des tests structurels ;
- interpréter un échec comme le signe d’un outil, d’une règle ou d’une abstraction manquante, au lieu de demander au modèle de « faire plus d’efforts » ;
- lancer régulièrement des tâches de nettoyage pour détecter la documentation obsolète et la dérive du code.
OpenAI précise également que le niveau d’autonomie obtenu dépend fortement de la structure et des outils propres à ce dépôt. Sans investissement comparable, il ne faut pas supposer que le même comportement se reproduira ailleurs.
Claude Code suit la même logique générale. La documentation officielle des hooks du Claude Agent SDK montre par exemple comment examiner une demande d’outil, la refuser, modifier ses paramètres ou l’inscrire dans un journal d’audit. Les mécanismes diffèrent selon les produits, mais le harness reste responsable de la frontière et de la boucle de retour.
Ce que l’IA peut faire et ce que l’humain doit décider
Ne commencez pas par une autonomie totale. Automatisez d’abord les opérations réversibles et demandez une validation lorsqu’une action touche des clients, de l’argent, des données sensibles ou la production.
| Bon point de départ | Déléguer sous conditions | Garder une décision humaine |
|---|---|---|
| Rechercher des fichiers | Modifier des fichiers existants | Supprimer des données de production |
| Exécuter des tests | Ajouter une dépendance | Envoyer un message à un client |
| Résumer un diff | Déployer en préproduction | Modifier une facturation ou un contrat |
| Créer un brouillon | Pousser une branche | Traiter des données personnelles sensibles |
Posez deux questions : l’action peut-elle être annulée à faible coût ? Peut-elle avoir un effet sur une personne extérieure à l’équipe ? Commencez par la lecture et des sorties temporaires. Une opération ne devient automatique qu’après avoir rendu observables ses réussites comme ses échecs.
Construire un harness minimal
L’exemple ne donne au modèle que deux capacités :
- lire du texte à l’intérieur de
sandbox; - créer un nouveau fichier texte à l’intérieur de
sandbox.
Aucun outil ne permet de supprimer, d’écraser, d’ouvrir un shell ou d’accéder au réseau. L’exemple a été vérifié avec Node.js 22 et la version du SDK est figée à celle utilisée lors de cette vérification.
mkdir harness-demo
cd harness-demo
npm init -y
npm install @anthropic-ai/[email protected]
mkdir sandbox
echo "# meeting notes" > sandbox/note.md
Créez policy.json :
{
"workspace": "./sandbox",
"maxSteps": 6,
"maxToolResultChars": 4000
}
1. Imposer la frontière des fichiers dans le code
Créez safe-files.mjs. Un contrôle tel que candidate.startsWith(root) ne suffit pas à lui seul : un dossier au nom proche peut correspondre, et un lien symbolique situé dans l’espace de travail peut pointer vers l’extérieur. La lecture ci-dessous contrôle donc la cible résolue, tandis que l’écriture est limitée aux nouveaux fichiers.
import { open, readFile, realpath } from "node:fs/promises";
import path from "node:path";
function assertInside(root, candidate) {
if (candidate !== root && !candidate.startsWith(root + path.sep)) {
throw new Error(`outside workspace: ${candidate}`);
}
}
export async function createFileGate(workspace) {
const root = await realpath(path.resolve(workspace));
async function readText(relativePath) {
const requested = path.resolve(root, relativePath);
assertInside(root, requested);
const actual = await realpath(requested);
assertInside(root, actual);
return readFile(actual, "utf8");
}
async function createText(relativePath, content) {
const requested = path.resolve(root, relativePath);
assertInside(root, requested);
const actualParent = await realpath(path.dirname(requested));
assertInside(root, actualParent);
let handle;
try {
handle = await open(requested, "wx", 0o600);
await handle.writeFile(content, "utf8");
} catch (error) {
if (error.code === "EEXIST") {
throw new Error(`refusing to overwrite: ${relativePath}`);
}
throw error;
} finally {
await handle?.close();
}
return "created";
}
return { readText, createText };
}
Ce garde-fou se situe au niveau de l’application ; il ne forme pas une frontière de sécurité complète. Pour une isolation plus forte, ajoutez un conteneur, une machine virtuelle, des droits système ou la sandbox du produit utilisé. Un contrôle applicatif ne neutralise pas les privilèges élevés du processus.
2. N’exposer que deux outils au modèle
Créez agent.mjs. Le nom du modèle passe volontairement par ANTHROPIC_MODEL au lieu d’être figé dans l’article, car les modèles disponibles et les droits d’accès varient selon les comptes.
import Anthropic from "@anthropic-ai/sdk";
import { readFile } from "node:fs/promises";
import { createFileGate } from "./safe-files.mjs";
const model = process.env.ANTHROPIC_MODEL;
if (!model) throw new Error("Set ANTHROPIC_MODEL to a model available to your account.");
const policy = JSON.parse(await readFile("./policy.json", "utf8"));
const gate = await createFileGate(policy.workspace);
const client = new Anthropic();
const tools = [
{
name: "read_file",
description: "Read a UTF-8 text file inside the workspace",
input_schema: {
type: "object",
properties: { path: { type: "string" } },
required: ["path"],
additionalProperties: false
}
},
{
name: "create_file",
description: "Create a new UTF-8 file; existing files cannot be overwritten",
input_schema: {
type: "object",
properties: {
path: { type: "string" },
content: { type: "string" }
},
required: ["path", "content"],
additionalProperties: false
}
}
];
async function runTool(name, input) {
if (name === "read_file") return gate.readText(input.path);
if (name === "create_file") return gate.createText(input.path, input.content);
throw new Error(`unknown tool: ${name}`);
}
const prompt = process.argv.slice(2).join(" ") ||
"Read note.md and create summary.md with a three-line summary.";
const messages = [{ role: "user", content: prompt }];
for (let step = 0; step < policy.maxSteps; step += 1) {
const response = await client.messages.create({
model,
max_tokens: 1200,
system: "Use only the supplied tools. Never claim a file was created unless the tool succeeded.",
tools,
messages
});
messages.push({ role: "assistant", content: response.content });
const calls = response.content.filter((block) => block.type === "tool_use");
if (calls.length === 0) {
console.log(response.content.find((block) => block.type === "text")?.text ?? "done");
process.exit(0);
}
const results = [];
for (const call of calls) {
try {
const value = await runTool(call.name, call.input);
results.push({
type: "tool_result",
tool_use_id: call.id,
content: String(value).slice(0, policy.maxToolResultChars)
});
} catch (error) {
results.push({
type: "tool_result",
tool_use_id: call.id,
is_error: true,
content: error.message
});
}
}
messages.push({ role: "user", content: results });
}
throw new Error(`step limit exceeded: ${policy.maxSteps}`);
3. Tester le garde-fou avant d’appeler un modèle
La frontière critique peut être testée localement, sans dépenser de crédits API. Créez safe-files.test.mjs :
import assert from "node:assert/strict";
import test from "node:test";
import { mkdtemp, mkdir, rm, symlink, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { createFileGate } from "./safe-files.mjs";
test("file gate blocks traversal, overwrite, and outside symlinks", async () => {
const base = await mkdtemp(path.join(tmpdir(), "harness-test-"));
const root = path.join(base, "sandbox");
const outside = path.join(base, "outside.txt");
try {
await mkdir(root);
await writeFile(path.join(root, "note.md"), "hello", "utf8");
await writeFile(outside, "secret", "utf8");
const gate = await createFileGate(root);
assert.equal(await gate.readText("note.md"), "hello");
await assert.rejects(() => gate.readText("../outside.txt"), /outside workspace/);
await assert.rejects(() => gate.createText("note.md", "replace"), /refusing to overwrite/);
try {
await symlink(outside, path.join(root, "outside-link.txt"), "file");
await assert.rejects(() => gate.readText("outside-link.txt"), /outside workspace/);
} catch (error) {
if (error.code !== "EPERM") throw error;
}
assert.equal(await gate.createText("summary.md", "safe"), "created");
} finally {
await rm(base, { recursive: true, force: true });
}
});
Lancez les contrôles hors ligne :
node --test safe-files.test.mjs
node --check agent.mjs
Ensuite seulement, définissez ANTHROPIC_API_KEY et ANTHROPIC_MODEL, puis exécutez node agent.mjs. Ne placez jamais les identifiants dans le code source ni dans policy.json.
Trois cas d’usage concrets
1. Équipe logicielle : réaliser et vérifier une pull request
Donnez à l’agent une issue ciblée, les dossiers utiles et les commandes de test. « Le code est écrit » n’est pas une condition d’acceptation. Exigez une reproduction qui échoue avant la correction, un test réussi après celle-ci et un diff lisible. Le déploiement en production et les migrations restent soumis à validation humaine.
2. Équipe éditoriale : contrôler un article avant publication
Séparez la rédaction des contrôles sur les sujets déjà traités, la profondeur du contenu, la syntaxe du code, les liens et l’affichage mobile. Un contrôle en échec doit bloquer la publication et renvoyer un message de correction précis. Le mot « terminé » est alors remplacé par une liste de critères observables.
3. Service client : classer une demande et préparer une réponse
L’agent peut classer un message et proposer un brouillon accompagné de ses raisons. Un humain valide les changements dans la fiche client et l’envoi réel. Ne fournissez que les données personnelles nécessaires au classement et évitez de conserver le corps complet des messages dans des journaux durables.
Calculer un ROI simple
Mesurez le temps humain économisé et la baisse des reprises, pas le nombre de tokens générés. Prenons une équipe qui consacre 20 minutes à la revue de chacune de ses 15 tâches hebdomadaires : cela représente cinq heures. Si la création du harness demande six heures et que sa maintenance descend ensuite à une heure par semaine, l’investissement initial est récupéré en environ une semaine et demie.
Ce calcul illustre la méthode ; il ne promet aucun résultat. Pendant deux semaines avant et après la mise en place, relevez :
- le nombre de minutes humaines par tâche ;
- le taux de reprise ;
- les défauts détectés avant la production ;
- le nombre de demandes de validation humaine.
Trop de demandes de validation peuvent indiquer qu’une opération éprouvée et peu risquée peut être mieux délimitée puis automatisée. Une hausse des défauts ou des reprises signifie plutôt qu’il faut ajouter un contrôle ou clarifier le contexte, pas élargir l’autonomie.
Pitfalls : erreurs fréquentes et corrections
Confondre un contrôle de dossier avec une sandbox
Un chemin peut sembler rester dans l’espace de travail alors qu’un lien symbolique conduit à l’extérieur. Résolvez la cible réelle, refusez l’écrasement et ajoutez une seconde frontière avec les droits du système d’exploitation.
Écrire seulement « ne fais rien de dangereux » dans le prompt
Le texte oriente le modèle, mais n’impose pas une règle. N’exposez pas l’outil dangereux ou bloquez-le dans un hook exécuté avant l’appel. Le guide des permissions Claude Code fournit une configuration concrète.
Croire le message « les tests sont passés »
Enregistrez la commande, le code de sortie et le périmètre de vérification. Pour une interface, ajoutez une interaction réelle ou une capture d’écran. Le workflow de reçu de vérification explique comment conserver ces preuves.
Charger tous les documents à chaque exécution
Un contexte trop long peut masquer la contrainte essentielle. Fournissez une petite porte d’entrée qui renvoie vers des sources ciblées et versionnées. Suivez leur fraîcheur et leur état de vérification afin que la documentation obsolète soit repérable.
Conclusion
Le harness engineering ne consiste pas à rallonger les prompts. Il rend les connaissances utiles accessibles, limite les outils, bloque les actions sensibles, évalue les résultats avec des commandes et transforme les échecs en règles et tests plus solides.
Pour commencer, choisissez un seul processus et notez quatre lignes : entrée, actions autorisées, commande d’acceptation et actions soumises à validation humaine. Les équipes qui veulent intégrer permissions, vérification et revue à un dépôt réel peuvent adapter ces limites à leur activité grâce à la formation et à l’accompagnement Claude Code.
Résultat de la vérification réelle
Le 21 juillet 2026, les blocs safe-files.mjs et safe-files.test.mjs de cet article ont été extraits dans un répertoire temporaire puis exécutés avec Node.js. Le scénario vérifie une lecture normale, la création d’un nouveau fichier, le rejet d’un chemin ../ sortant du périmètre et le refus d’écraser un fichier existant. Sur les systèmes où le processus de test peut créer un lien symbolique, il vérifie aussi le rejet d’un lien pointant à l’extérieur. agent.mjs a fait l’objet d’un contrôle de syntaxe.
Un appel réel à l’API Anthropic ne fait pas partie du périmètre, car l’accès aux modèles et le coût varient selon le compte. Cette distinction est volontaire : « publié », « syntaxe vérifiée », « testé hors ligne » et « exécuté contre une API externe payante » sont quatre affirmations différentes.
Articles liés
Claude Code ou Codex, finalement lequel ? La vraie réponse : les faire cohabiter sans accident
Codex d'OpenAI et Claude Code : qui est doué pour quoi, à qui confier quoi ?
Claude Agent SDK : intégrer Claude Code dans vos apps
Setup actuel, permissions, MCP, exemples exécutables et pièges de production du Claude Agent SDK.
Prompt engineering avance pour Claude Code et Codex : concevoir des briefs de tâche fiables
Concevez des prompts Claude Code/Codex avec brief, critères d'acceptation, vérification et boucle sûre.
PDF gratuit: cheatsheet Claude Code
Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.
Nous protégeons vos données et n'envoyons pas de spam.
À propos de l'auteur
Masa
Ingénieur spécialisé dans les workflows pratiques avec Claude Code.