Arrêtez d'ajouter une CLI à votre app en dernière minute. Faites-en le noyau de votre agent.
CLI est le nouveau MCP. Slogan mis à part : CLI, c'est des super-pouvoirs offerts à Claude, Codex, et tous les agents qui codent pour vous. Permettre aux LLM de vérifier leur propre travail de manière programmatique leur donne un avantage déloyal sur les apps fullstack classiques qui n'ont pas livré cette interface.
CLI est le nouveau full stack.
TLDR : Deux apps, même stack moderne, un écart de 1,8x en commits livrés sur 30 jours. L'écart ne vient ni de l'IA, ni du framework, ni du backend, mais d'une couche que les guides "stack 2026" ont oubliée, et que votre dossier scripts/ ne remplacera pas.
Le vendredi soir avant de partir pour la Costa Brava, je voulais livrer un petit truc avant de fermer le laptop (sans que ma femme me crie dessus).
Deux fenêtres Claude Code côte à côte. Même prompt pour chacune. Deux apps différentes, même stack à 95%.
Au moment où j'ai fermé le laptop, une app avait livré une feature en trois itérations autonomes. L'autre m'avait fait cliquer dans l'admin comme un junior qui essaie de débugger la prod depuis son téléphone. Même agent, même moi, un dossier de différence.

Même Stack, Un Dossier de Différence
Première app, fenêtre de gauche. Claude Code écrit la mutation, tape une commande dans son terminal, lit le JSON qui revient, repère qu'un champ est mal casté, corrige, retape. Trois itérations en autonomie totale. Je reviens, je dis "bon weekend". Le commit est prêt, validé à 100%.
Deuxième app, fenêtre de droite. Claude Code écrit la mutation, puis s'arrête. Il me ping. Tu peux ouvrir l'admin et vérifier que ça marche ? Je clique. Je refresh, puis re-clique. Re-ping. Ma femme commence à hausser le ton. Tant pis, on verra lundi. Sinon j'aurais passé toute la soirée à être la souris d'un agent qui était censé coder à ma place.
Même stack, même moi, même Claude Code des deux côtés. La seule différence tient dans un dossier.
Les deux apps sont à moi. L'une est un back-office qui synchronise un catalogue WooCommerce via une API partenaire chaque nuit, plus un flux CSV hebdomadaire d'un distributeur. L'autre est un back-office qui pilote un réseau d'e-shops clients WooCommerce (déploiements, mises à jour de thèmes, sync de plugins, le truc de flotte habituel). Toutes deux construites depuis six mois. Toutes deux tournent sur Next.js, Convex, shadcn, Vercel. Même CLAUDE.md, mêmes conventions.
L'une a un CLI comme couche centrale. L'autre a un dossier scripts/.
C'est tout. C'est tout l'écart.
Par "CLI" j'entends un vrai point d'entrée avec des sous-commandes nommées d'après les actions métier (catalog refresh, partner sync, site init), branchées sur exactement la même couche métier qu'utilise le dashboard. Tu tapes bun run cli partner sync --dry-run, et le même chemin de code qui s'exécute quand un admin clique "Sync" s'exécute, sauf qu'il retourne du JSON sur stdout.
L'autre app n'a rien de tout ça. Juste des fichiers .mjs avec des noms comme fix-thing-2025-08.mjs (avoue, tu as un dossier comme ça aussi). Chacun écrit pour "passer une fois". La plupart n'ont jamais tourné une seconde fois.
C'est toute la différence. Et ça a changé la façon dont l'agent travaillait à tous les niveaux.
30 Jours de Commits Ne Mentent Pas : 1,8x Plus de Features, Moitié Moins de Corrections
Je suis retourné dans l'historique git des deux repos sur la même fenêtre de 30 jours en mai.
L'app-CLI a livré 272 commits. L'app-scripts en a livré 150. C'est un ratio de 1,8x, sur le même moi, même agent, même routine quotidienne.
Dans le repo CLI, chaque sous-commande a été touchée au moins une fois pendant la fenêtre. 100%. Dans le dossier scripts/, seulement 29% des fichiers ont vu de l'activité. Le reste était dormant. 41% de tous les fichiers de script dans l'app-scripts avaient été écrits, exécutés une fois, et jamais rouverts. Le plus ancien que j'ai trouvé qui correspond à ce profil n'avait pas été touché depuis 57 jours. J'avais complètement oublié qu'il existait jusqu'à ce que j'aille chercher.
Il y a un autre chiffre intéressant, mais je veux le signaler comme une hypothèse, pas comme une preuve. En regardant les messages de commit taggés fix: versus feat:, l'app-CLI avait un ratio fix-sur-feat de 0,44. L'app-scripts était à 0,82. Environ deux fois plus de commits de correction par feature du côté sans CLI.
Je ne peux pas prouver que le CLI cause cet écart. Les deux apps ont une maturité de domaine différente, une complexité différente, une couverture différente des cas limites. La moitié de la différence pourrait venir du fait que le back-office pour les sites clients est simplement plus ancien et plus capricieux que celui de l'API partenaire. Mais l'écart est cohérent avec ce que j'observe quotidiennement, et il suit l'écart d'autonomie que j'ai décrit en intro : l'agent livre un travail plus propre quand il a un moyen de se vérifier, donc moins de régressions passent à travers.
Le taux d'orphelins (41% versus 0%) et l'écart de vélocité (1,8x) ne sont pas des hypothèses. Ça, je peux le lire directement dans git log.
Le Vrai Mécanisme : Les Agents Ont Besoin d'une Surface Text-Structurée
La raison pour laquelle l'app-CLI produit des itérations autonomes tandis que l'app-scripts produit des festivals de ping n'a rien à voir avec la qualité du code ou la taille du modèle.
C'est à propos de la surface que l'agent a pour valider son propre travail.
Réfléchis à ce que Claude Code fait réellement dans une boucle de feature. Il écrit du code, puis il a besoin de savoir si le code fait ce qu'il était censé faire. Si le seul moyen de vérifier c'est "ouvre le dashboard, clique partout, regarde l'écran", l'agent ne peut pas le faire. Les navigateurs retournent du DOM. Le DOM sans un œil humain pour interpréter ce qui est rendu est opaque pour un agent. Les couleurs, les états de chargement, la modale qui a poppé, le message de validation en bas, tout ça a du sens pour une personne et c'est du bruit pour un modèle. L'agent n'a pas de vérité terrain, donc il s'arrête et te demande.
Un CLI retourne du texte. JSON, stdout structuré, codes de sortie. Des trucs qu'un agent peut lire, parser, sur lesquels raisonner. L'agent lance la commande, lit la sortie, voit que partnerStatus: "rejected" signifie que la mutation n'est pas passée, corrige le code, relance. Pas d'humain dans la boucle. Le signal de feedback est nativement lisible par le modèle.
C'est tout le principe. Surface text-structurée égale agent autonome. Surface DOM-seulement égale agent qui te ping à chaque itération.
C'est aussi pourquoi les serveurs MCP, les API REST, les endpoints tRPC, GraphQL fonctionnent tous pour les agents qui appellent ton service. Ce sont toutes des surfaces text-structurées. Un CLI est juste l'incarnation la plus simple et la plus locale de ce principe pour l'agent qui code ta propre app. Pas appeler un service distant. Écrire du code dans ton repo et avoir besoin de le tester maintenant.
Tu peux simuler ça avec Playwright pointé sur ton dashboard. Les gens le font. Ça marche, en quelque sorte. Ça coûte aussi un ralentissement 10x, une couche de retry capricieuse, et une étape de comparaison de screenshots qui casse chaque fois que tu livres un changement d'UI. Un CLI retourne la même réponse en millisecondes sans caprice, parce que le texte était toujours ce que l'agent voulait en premier lieu.
La Stack 2026 a Oublié une Couche (Et Tous les Outils de Génération de Code IA L'Ignorent Aussi)

Va lire n'importe quel guide "meilleure stack pour lancer ton outil codé par IA" écrit entre février et avril 2026. KDnuggets, Idlen, Context Studios, MindStudio, tu peux en choisir un au hasard. Ils convergent tous sur les mêmes six ou sept couches. Next.js pour le frontend. shadcn pour le kit UI. Supabase ou Convex pour le backend. Clerk pour l'auth. Stripe pour les paiements. Resend pour l'email transactionnel. Vercel pour l'hébergement. Certains ajoutent Tailwind, OpenAI, Claude, Gemini.
Il y a au moins 50 de ces guides publiés dans les trois derniers mois. Aucun d'eux ne mentionne un CLI pour ton app.
Même angle mort du côté IA. Cursor, v0, Bolt, Lovable, Claude Code lui-même quand il scaffolde un nouveau projet. Tous génèrent un frontend, un backend, une config d'hébergement. Zéro d'entre eux ne génère un CLI comme couche de première classe. Si tu demandes à Claude Code de "mettre en place une app Next.js avec Convex et Stripe", tu auras ces trois trucs et rien d'autre. Le CLI, s'il y en a un, apparaîtra plus tard comme scaffolding (next dev, convex dev) et c'est tout.
Ce n'était pas un problème en 2020. En 2020, tu écrivais ton propre code, et ton IDE était ta boucle de feedback. F5, F12, console.log, console.log, console.log. Le DOM allait bien parce que c'était toi qui le lisais.
En 2026, tu n'es pas celui qui écrit la plupart du code. L'agent l'est. Et l'agent n'a pas d'yeux.
Une stack 2026 sans couche CLI force l'agent à dépendre de toi pour chaque itération. L'agent écrit une mutation, tu cliques dans l'admin, tu dis à l'agent si ça a marché. L'agent écrit un job de sync, tu fais tail -f sur les logs, tu dis à l'agent ce que tu as vu. Chaque boucle de feature t'a comme nœud intermédiaire obligatoire. Tu penses que tu promptes un agent pour livrer à ta place, tu joues en fait l'intermédiaire navigateur pour l'agent.
La quatrième couche découle d'un fait : si tu veux que l'agent livre de manière autonome, tu dois lui donner une surface qu'il peut lire.
L'article d'Idlen argumente que choisir le mauvais backend signifie réécrire tes modèles de données à 2h du matin. Ouais, et c'est pire si tu n'as pas de CLI, parce que tu les réécris à la main au lieu de lancer bun run cli model migrate.
Pourquoi les Scripts Pourrissent et les CLI Vivent
Le taux d'orphelins de 41% ne vient pas de la paresse. Il vient du fait qu'un dossier scripts/ ne te demande rien architecturalement.
Tu écris scripts/migrate-orders-2025-04.mjs parce que tu as une urgence. Tu le lances une fois. Ça marche. Tu le commites (ou pas, selon ton niveau de panique). Trois semaines plus tard, autre urgence. Tu écris scripts/migrate-orders-fix.mjs. Même problème, nom légèrement différent. Tu ne réutilises pas le premier parce que tu ne te souviens pas qu'il existe. Il n'y a pas de scripts/ --help. Il y a juste un ls.
Tout le dossier finit comme le classeur de Karen de la Compta : techniquement organisé, pratiquement inutilisable. Tout est "là", personne ne sait où, même Karen a arrêté de chercher.
Un CLI force une forme différente. Tu ne peux pas ajouter partner sync comme sous-commande sans l'enregistrer dans le point d'entrée, ce qui signifie que tu vois toutes les autres sous-commandes chaque fois que tu en ajoutes une nouvelle. La découvrabilité est intégrée dans l'outil. Les nouvelles sous-commandes héritent des mêmes flags (--dry-run, --limit, --verbose), du même logger, de la même gestion d'erreur. L'idempotence devient facile parce que tu passes déjà par une couche métier partagée que le dashboard utilise aussi.
C'est pourquoi le taux de touché est à 100% du côté CLI. Je ne suis pas plus discipliné quand j'utilise un CLI. Le CLI est juste architecturalement hostile au code jetable d'une façon que scripts/ ne sera jamais.
Et --help fait plus que t'aider. C'est le point d'entrée pour tout agent qui atterrit sur ton repo. Claude Code tape bun run cli --help une fois et maintenant connaît chaque action métier qu'il peut déclencher, avec ses flags et sa description. Pas d'ingénierie de prompt, pas de doc à nourrir. Le CLI se documente lui-même, pour les humains et pour les agents en même temps. C'est ce que scripts/ ne te donnera jamais, peu importe la propreté de tes noms de fichiers.
Caveat que je devrais mettre ici, pendant que je me vante. Mon propre CLI a une vraie faiblesse. Sur 14 sous-commandes, 11 n'ont pas de description dans la sortie --help. C'est 79% de mes commandes qui apparaissent comme des noms nus sans explication. Le CLI a forcé la discipline d'exécution. Il n'a pas forcé la discipline de documentation. Claude Code peut toujours découvrir chaque commande, parser la sortie JSON, et l'utiliser. Un dev junior qui ouvre le repo pour la première fois devrait lire le source. Je corrige lentement, mais la leçon tient : l'architecture résout le problème d'exécution, pas le problème d'enseignement. Tu dois encore écrire les docstrings.
Ton App Est Déjà Agentique par Accident
Le truc que personne ne te dit dans les guides stack-2026 : un CLI qui partage la couche métier avec ton UI rend ton app nativement agent-ready. Pas comme produit séparé. Comme effet de bord gratuit.
Trois façons concrètes d'exposer ton CLI à un agent qui n'est pas assis dans ton IDE.
L'enrober comme serveur MCP. Peut-être 50 lignes de TypeScript. Tu écris un serveur MCP fin qui enregistre chaque sous-commande de ton CLI comme outil MCP. L'input de l'outil mappe aux flags CLI. L'output de l'outil est le JSON que le CLI retourne déjà. Boom, tout client MCP (Claude Desktop, Cursor, tout ce qui parle MCP) peut appeler ton CLI comme outil natif. Tu as enrobé ton CLI existant et appelé ça un serveur MCP.
Cron plus agent. Un scheduler lance bun run cli catalog refresh toutes les six heures. La sortie JSON va dans une table Convex. Un agent en arrière-plan lit la dernière ligne, décide si le refresh a touché une erreur partenaire, et si oui déclenche un suivi bun run cli partner reconnect. Pas de navigateur. Pas d'humain. L'agent prend des décisions basées sur le texte que le CLI émet, puis déclenche plus de commandes CLI. Tu viens de transformer ton back-office en boucle auto-réparante.
Gateway HTTP shell-out. Tu exposes un tiny endpoint Express ou Hono qui prend un nom de commande CLI plus des args, shell-out vers le CLI, retourne le JSON. Authentifié bien sûr. Maintenant tout agent externe qui parle HTTP peut piloter ton app. Pas de SDK à maintenir. Le CLI est le SDK.
Aucune de ces trois ne demande un refactor de ta logique métier. Ce sont des couches d'exposition pures au-dessus du code que tu as déjà écrit. Une stack, deux modes : dashboard pour les humains, CLI pour les agents. Le dashboard ne savait pas qu'il avait un jumeau. Maintenant si.
Les Trois Patterns d'Intégration (Choisis-en Un, Choisis Bien)
Si tu vas cuire un CLI dans ta stack, il y a trois façons de le câbler. Une seule te donne l'écart d'autonomie que j'ai décrit plus tôt.
Pattern 1 : CLI partage la couche métier avec l'UI. Le bouton dashboard "Sync partner" appelle une mutation Convex. La commande CLI partner sync appelle la même mutation, avec le même schéma Drizzle, mêmes types TypeScript bout-en-bout. Mêmes garanties d'idempotence. Même log d'audit. C'est celui que tu veux. Tout ce que j'ai décrit assume ce pattern. (Convex se marie particulièrement bien avec Claude Code pour exactement cette config, parce que l'API typée bout-en-bout fait du CLI un wrapper fin autour des mutations plutôt qu'une implémentation parallèle.)
Pattern 2 : CLI comme client HTTP de ta propre API. Le CLI appelle tes endpoints REST ou tRPC. Plus facile à isoler, agnostique au langage, tu peux livrer le CLI aux clients qui ne font pas tourner ton monorepo. Mais tu perds les bénéfices de typage, tu dois gérer l'auth manuellement, et l'idempotence dépend de qui a écrit l'endpoint. Acceptable comme fallback si ton backend est dans un repo différent de ton consommateur CLI. Pas optimal.
Pattern 3 : CLI DevOps, séparé de l'app. Commandes de déploiement, scripts de backup, outils de monitoring. Utile, mais ce n'est pas un substitut. Si ton app vit, tu as aussi besoin du Pattern 1 ou 2 à côté. Le Pattern 3 seul est ce que la plupart des équipes livrent et ce qui est confondu avec "on a un CLI". C'est juste un script de déploiement.
Verdict : Le Pattern 1 est le seul qui retourne l'écart de vélocité. Le Pattern 2 est la moitié du travail pour une fraction du bénéfice. Le Pattern 3 est de la plomberie d'hébergement déguisée en CLI.
Si tu ne peux construire qu'un pattern, construis le premier.
Outillage : cac vs citty vs le Reste en 2026
Rapide tour d'horizon de ce qui vaut vraiment la peine d'être utilisé pour construire le CLI lui-même, puisque c'est là que la plupart des gens restent coincés un weekend.
cac est mon défaut. Environ 2 KB, zéro dépendance, ESM-first. Si ton CLI a moins de 20 sous-commandes, c'est le bon outil. Assez petit pour que tu n'y penses pas, et Claude Code génère du code cac propre du premier coup.
citty des gens d'UnJS est le choix montant pour 2026. Type-safe, sous-commandes lazy-loading (important quand tu commences à taper dans les 30+), ESM-first, joue bien avec Nitro et le reste du monde UnJS. Migre vers lui quand ton CLI grandit au-delà de là où cac semble à l'étroit.
commander est l'option mature legacy. Stable, bien documenté, fera le job, mais l'API semble plus ancienne et le bundle est plus lourd qu'il ne devrait. Choisis-le seulement si ton équipe le connaît déjà.
clipanion est orienté OOP, utilisé par Yarn. Bien si tu aimes les classes et veux un typage strict. Niche.
oclif est sur-architecturé sauf si ton CLI lui-même est le produit (pense Heroku, Salesforce). Pour un CLI qui supporte une app, oclif c'est amener un chariot élévateur pour déplacer un canapé.
Pour le reste de l'expérience, tu veux clack pour les prompts (TUI magnifique, très récent), picocolors pour les couleurs (plus petit et plus rapide que chalk maintenant), consola pour le logging, listr2 si tu as des tâches multi-étapes avec barres de progression, et bun shell ou zx pour les scripts embarqués.
Commence sur cac. Migre vers citty quand tu dépasses 20 sous-commandes.
Ne sur-réfléchis pas.
Quand le CLI Manquant Fait Mal (Quatre Scénarios)
Quatre moments où l'absence d'un CLI te coûte spécifiquement, au cas où l'argument abstrait n'aurait pas atterri.
Onboarding d'un nouvel e-shop client. Sans CLI, chaque nouveau client c'est deux à trois heures de clics dans l'admin : provisionner le domaine, définir le thème, installer les plugins, seeder le catalogue, configurer le DNS. Multiplie par dix clients dans un mois. Avec un CLI, site init shop.example.com lance toute la séquence en cinq minutes. L'agent peut le lancer tout seul quand un webhook Stripe tire "nouveau client".
Correction de données récurrente. Un partenaire retourne parfois des prix malformés dans leur API. Sans CLI, chaque incident signifie réécrire la mutation de correction à la main, ou fouiller dans scripts/ pour trouver "celui qui a marché la dernière fois". Avec un CLI, tu as bun run cli prices reconcile --dry-run, idempotent, versionné, documenté dans --help. L'agent l'invoque lui-même quand l'alerte tire.
Audit pendant incident. Quelque chose a cassé en prod, tu as besoin de savoir quelles commandes ont été affectées. Sans CLI, tu grep dans scripts/ pour "ce truc d'audit que j'ai écrit en mars". Avec un CLI, cli orders audit --since=2026-04-01 existe, est documenté, et l'agent peut le lancer pendant que tu tapes encore dans Slack.
Refresh de données externes. Cron doit rafraîchir un catalogue partenaire chaque nuit. Sans CLI, le cron pointe vers node scripts/old-thing.mjs et le fichier dérive lentement hors de sync avec le schéma, jusqu'à ce qu'un mardi il échoue silencieusement pendant 48 heures avant que quelqu'un le remarque. Avec un CLI, le cron pointe vers bun run cli partner refresh, qui partage la même couche métier que le dashboard, donc un changement de schéma casse le cron au prochain déploiement au lieu d'au milieu de la nuit.
Mêmes quatre problèmes. Le CLI rend chacun ennuyeux.
Le Test de 30 Secondes Que Ta Stack Doit Passer Aujourd'hui
Ouvre ton terminal. cd dans ton repo. Tape bun run cli --help (ou yarn cli --help, ou npm run cli -- --help, peu importe ton gestionnaire de paquets).
Il y a exactement trois résultats possibles.
Résultat A. Rien ne sort. Ou "command not found". Ou package.json n'a pas de script cli. Tu n'as pas de CLI. Tu as une UI boulonnée sur un backend. L'agent qui code ton app dépend de toi pour chaque itération, et le taux d'orphelins de ton dossier scripts/ grimpe lentement vers 41% que tu le mesures ou non.
Résultat B. Une liste apparaît, mais les sous-commandes sont des trucs devops génériques (build, dev, test, deploy) sans actions métier. Tu as du scaffolding devops. Utile, mais l'agent peut déployer ton code et ne pas valider qu'une feature marche. Tu es au Pattern 3 des trois patterns ci-dessus. La moitié du voyage.
Résultat C. Une liste apparaît avec des sous-commandes nommées d'après les actions métier (site init, partner sync, catalog refresh), chacune avec une description. Tu as une stack 2026-ready. L'agent qui écrit ton code a un moyen de le vérifier. Ton dossier scripts/ est vide ou a moins de cinq fichiers. Tu peux arrêter de lire.
Si tu as eu A ou B, c'est là que tu commences. Choisis une ou deux actions métier que tu fais le plus souvent (celles qui apparaissent dans ton dossier scripts/ sous trois noms différents), et fais-en les deux premières sous-commandes d'un vrai CLI. Câble-les à travers la même couche métier qu'utilise le dashboard. Rends la sortie en forme de JSON. C'est le plus petit Pattern 1 possible, et ça changera la façon dont Claude Code travaille sur ton repo dès demain matin.
J'ai déjà écrit sur les CLI comme interface pour les agents appelant tes outils. Celui-ci est sur les CLI comme interface pour l'agent écrivant ton code de l'intérieur. Problème différent, même couche. Le premier est sur MCP versus CLI comme convention d'appel distant. Celui-ci est sur si l'agent dans ton IDE a un moyen de livrer.
La prochaine fois que tu démarres une app, décide dès le jour un si le CLI est un kernel ou une réflexion après coup. Ce choix décide combien de temps Claude Code passe à coder pour toi, versus combien de temps tu passes à être la souris de Claude Code.
Six mois à construire deux apps en parallèle et je n'ai pas réalisé que je menais une expérience contrôlée sur moi-même. En tant qu'ancien de Linux, je savais déjà que CLI bat la plupart des trucs, intuitivement. Ce que je n'ai pas vu venir c'était la partie qui comptait le plus : pas juste la vitesse et la scriptabilité, mais donner à l'agent une boucle de feedback qu'il pouvait lire tout seul.
Claude et Codex ne suggéreront pas ça par défaut. Alors dis-le leur toi-même : cuis une couche CLI comme kernel, jour un.
J'y vais, la piña colada m'attend 😎
CLI était la couche depuis le début.
Sources
- KDnuggets, Tech Stack for Vibe Coding Modern Applications (Février 2026)
- Idlen, The Best Stack to Launch Your AI-Coded Tool in 2026 (Avril 2026)
- Context Studios, The Perfect Vibe Coding Tech Stack 2026: 10 Tools Every App Needs (Février 2026)
- Audit de première main, deux de mes propres apps, 30 jours d'historique git (Mai 2026)