J’ai remplacé le « Vibe Coding » par des Prompt Contracts — et Claude Code a cessé de me saboter

2 400 lignes de code supprimées. Pas parce qu’elles étaient mauvaises — parce qu’elles résolvaient le mauvais problème.

J’avais demandé un flux d’authentification Supabase avec Row-Level Security. Claude Code m’a livré un système d’auth impeccable — sur Firebase. Ça compilait. Ça tournait. C’était propre. Et c’était fondamentalement inutilisable dans mon stack.

Ce n’est pas un bug de l’IA. C’est un bug de process. Quand on donne un brief vague à un modèle capable, on obtient une réponse capable… à côté de la plaque. Ce soir-là, j’ai compris que je ne pilotais pas Claude Code — je lui lançais des dés en espérant un résultat.


Le problème du Vibe Coding

Le vibe coding, c’est taper un prompt en langage naturel et espérer que le modèle devine le reste :

> Construis-moi un dashboard pour mon SaaS

Claude Code génère 3 000 lignes sur 14 fichiers. On lance. Ça casse. On dit « corrige ». Il corrige un truc, en casse trois autres. Au bout de 45 minutes, on a quelque chose qui tourne mais qu’on ne comprend pas vraiment.

J’ai livré deux produits SaaS quasi entièrement avec Claude Code. Sur cette période, environ 30% de mon temps a consisté à défaire ce que l’IA avait construit avec assurance dans la mauvaise direction.

Le problème n’a jamais été l’intelligence du modèle. Opus est un dev senior qui a absorbé l’intégralité de Stack Overflow — y compris les mauvaises réponses. Le problème, c’est que mes prompts étaient des intentions, pas des spécifications.

« Rends ça responsive. » « Ajoute de la gestion d’erreur. » « Utilise les bonnes pratiques. »

Ce ne sont pas des instructions. Ce sont des vœux pieux. Claude Code n’est pas un devin — c’est un prestataire. Et aucun prestataire sérieux ne peut livrer correctement à partir d’un post-it marqué « construis maison, fais joli ».


Les Prompt Contracts : structurer l’interaction

Le concept vient d’un ex-ingénieur OpenAI. L’idée : au lieu d’écrire des prompts comme des briefs créatifs, les écrire comme des contrats avec quatre clauses exécutoires.

ClauseRôleQuestion clé
GOALCritère de succès mesurable« Comment je vérifie que c’est terminé en 60 secondes ? »
CONSTRAINTSLimites non négociables« Qu’est-ce que l’IA n’a PAS le droit de toucher ? »
FORMATStructure de sortie attendue« Quels fichiers, quel nommage, quelle architecture ? »
FAILURE CONDITIONSCe qui invalide le résultat« Qu’est-ce qui déclenche un git revert immédiat ? »

J’ai testé cette approche pendant trois semaines sur deux projets SaaS en production. Chaque prompt vibe remplacé par un Prompt Contract structuré.


GOAL — Définir « terminé » avant d’écrire une ligne

La première clause force à définir le critère de succès avant que Claude Code commence à coder.

❌ Vibe :

> Ajoute un système d'abonnement à l'app

✅ Contract :

> GOAL: Implémenter la gestion d'abonnements Stripe.
> 3 tiers (free/pro/team), upgrade/downgrade instantané,
> statut de facturation visible sur /settings/billing.
> 
> Succès = un utilisateur free peut passer Pro,
> voir le débit sur le dashboard Stripe,
> et accéder aux features restreintes en moins de 5 secondes.

La différence n’est pas le niveau de détail — c’est la testabilité. Quand Claude Code a fini, je peux valider l’objectif en moins d’une minute. Pas d’interprétation possible.

Ce seul changement a réduit mes allers-retours d’environ 50%. Quand le modèle sait à quoi ressemble la ligne d’arrivée, il cesse de dériver.


CONSTRAINTS — Verrouiller le stack

Sans contraintes explicites, Claude Code prend des libertés architecturales. Il remplace Convex par Prisma, swape Clerk pour NextAuth parce que « c’est plus courant ». C’est techniquement défendable — et totalement inutilisable dans un projet existant.

La solution : un fichier CLAUDE.md à la racine du projet, lu en début de chaque session.

# CLAUDE.md — Contraintes Projet (toujours actives)

## Stack (non-négociable)
- Frontend: Next.js 14+ App Router, TypeScript strict
- Backend: Convex pour le temps réel, Supabase pour auth + storage
- Auth: Clerk (pas d'auth custom)
- Styling: Tailwind uniquement

## Règles
- Ne jamais installer une dépendance sans demander
- Ne jamais modifier le schéma DB sans montrer le plan de migration
- Tous les appels API passent par les fonctions Convex
- Variables d'environnement dans .env.local, jamais en dur

## Patterns
- Server components par défaut
- Error boundaries sur chaque segment de route
- Validation Zod sur chaque input utilisateur

Le premier message de chaque session :

> Lis CLAUDE.md et confirme que tu comprends les contraintes
> du projet avant de faire quoi que ce soit.

C’est un handshake. Claude Code restitue les contraintes, on valide ensemble la réalité du projet, et le travail commence sur des bases partagées. Sans ça, chaque session repart de zéro — et le modèle improvise.


FORMAT — Imposer la structure de sortie

Sans directive de format, Claude Code optimise pour la vitesse, pas pour la maintenabilité. Le résultat typique : un fichier monolithique de 800 lignes, validation inline, pas de types, tout mélangé.

❌ Vibe :

> Crée un endpoint API pour l'onboarding utilisateur

✅ Contract :

> FORMAT:
> 1. Fonction Convex dans convex/users.ts (mutation, pas action)
> 2. Schéma Zod dans convex/schemas/onboarding.ts
> 3. Types TypeScript exportés depuis convex/types/user.ts
> 4. JSDoc sur la fonction publique
> 5. Retour : { success: boolean, userId: string, error?: string }

Code modulaire, typé, documenté — à chaque génération. Le modèle sait produire du code propre. Il a juste besoin qu’on lui dise que c’est ce qu’on attend.

C’est d’autant plus critique avec les agent teams de Claude Code. Si les sous-agents ne suivent pas le même contrat de format, le merge devient un cauchemar de styles et de conventions incompatibles.


FAILURE CONDITIONS — L’arme secrète

Si le Goal est la cible positive, les Failure Conditions sont la cible négative. Elles définissent ce qui rend une sortie inacceptable — et le modèle les respecte scrupuleusement.

Exemple de Prompt Contract complet :

> Build la page /dashboard.
>
> GOAL: Afficher les projets actifs avec mises à jour temps réel.
> First meaningful paint sous 1 seconde. Création, archivage
> et renommage de projets inline.
>
> CONSTRAINTS: Convex useQuery pour les données, pas de polling,
> pas de SWR. Clerk useUser() pour l'auth. Redirection /sign-in
> si non authentifié. Max 150 lignes par composant.
>
> FORMAT: Page dans app/dashboard/page.tsx (server component wrapper),
> client component dans components/dashboard/ProjectList.tsx,
> query Convex dans convex/projects.ts. Tailwind uniquement.
>
> FAILURE CONDITIONS:
> - useState pour des données qui devraient être dans Convex
> - Composant dépassant 150 lignes
> - Fetch côté client quand le serveur est possible
> - UI library autre que Tailwind
> - Loading states ou error states manquants
> - Types TypeScript absents sur les paramètres

Résultat : un dashboard temps réel propre, du premier coup. Pas de Firebase, pas de Prisma, pas de package npm obscur de 2019 avec 12 étoiles GitHub.

Le mois précédent, le même besoin formulé en vibe avait produit un composant avec Material UI (pas dans mon stack), du useEffect pour le data fetching (Convex gère ça nativement), et zéro loading state.

La différence entre « conduis prudemment » et « ne dépasse pas 130, ne grille pas les feux, évite le périphérique aux heures de pointe ». L’un est un souhait. L’autre est un cadre opérationnel.


Résultats après 3 semaines

Métriques relevées sur deux projets en production :

MétriqueVibe CodingPrompt Contracts
Taux de rollback~1 génération sur 3~1 sur 10
Allers-retours par feature~3 rounds~1,2 rounds
Violations de stackPlusieurs par jourQuasi zéro
Temps prompt → code utilisable45+ minutes~10 minutes

Le combo CLAUDE.md + handshake de session fonctionne comme une checklist pré-vol. C’est un investissement de 60 secondes par prompt qui en économise 45 minutes de debug.

Observation contre-intuitive : les prompts sont devenus plus courts avec le temps. Une fois que CLAUDE.md porte les contraintes permanentes et que la structure à 4 clauses est internalisée, un Prompt Contract pour une feature complexe s’écrit en une minute.


Mise en œuvre immédiate

Deux actions pour démarrer :

1. Créer un CLAUDE.md à la racine du projet avec le stack, les règles et les patterns. C’est la couche de contraintes permanente. Chaque session Claude Code commence par le lire et le confirmer.

2. Sur le prochain prompt, ajouter un GOAL, une CONSTRAINT et une FAILURE CONDITION. Un de chaque. Le delta de qualité est immédiat.

Le framework Prompt Contract ne demande pas d’écrire plus. Il demande de spécifier 60 secondes pour que le modèle n’ait pas à interpréter pendant 60 minutes.

C’est la différence entre piloter un outil et subir ses décisions.

Publications similaires