Back to sh0
sh0

16 commandes en un jour : l'histoire complète du CLI

Comment nous avons construit 16 commandes CLI, 2 endpoints serveur et un système de streaming WebSocket -- audités à travers 6 sessions indépendantes -- en une seule journée de développement assisté par IA.

Thales & Claude | March 30, 2026 11 min sh0
EN/ FR/ ES
clirustmethodologyauditdeploymentdeveloper-experienceretrospective

Le 27 mars 2026, sh0 est passé d'une plateforme de déploiement avec un CLI basique à une plateforme de déploiement avec une expérience développeur complète. Seize nouvelles commandes. Deux nouveaux endpoints serveur. Un système de streaming WebSocket. De la documentation sur trois surfaces en cinq langues. Six sessions d'audit indépendantes. Zéro bug connu à la fin.

Cet article raconte l'histoire complète -- pas les détails d'implémentation (ceux-ci sont dans les articles précédents) mais la méthodologie, la chronologie, les décisions et les leçons apprises.

Le point de départ

sh0 avait déjà un CLI. Dix commandes construites dès le premier jour du projet, couvrant l'essentiel : serve, setup, status, deploy, logs, env, ssh, check, templates, compose, et d'autres. Ces commandes reproduisaient le tableau de bord et étaient immédiatement utiles pour le développement et les tests.

Mais elles supposaient toutes que l'application existait déjà sur le serveur. Le développeur devait créer les applications via le tableau de bord, configurer les dépôts Git et gérer les déploiements via l'interface web. Le CLI était une télécommande pour le serveur, pas un outil de développement autonome.

Le manque, c'était sh0 push -- la capacité de déployer depuis un répertoire local avec une seule commande.

La chronologie

SessionPhaseCe qui a été faitDécouvertes
1Phase 1 : Buildpush, login, whoami + endpoint serveur--
2Phase 1 : Audit R1Revue de 2 600 lignes3 Critiques, 6 Importants, 5 Mineurs
3Phase 1 : Audit R2Vérification des corrections, revue fraîche2 Importants, 4 Mineurs
4Phase 2 : Buildinit, link, open, config--
5Phase 2 : AuditRevue du code Phase 20 Critique, 1 Important, 2 Mineurs
6Phase 3 : Buildrestart, stop, start, delete, domains--
7Phase 3 : AuditRevue du code Phase 31 Critique, 0 Important, 4 Mineurs
8Phase 4 : Buildwatch + streaming WebSocket--
9Phase 4 : AuditRevue du code Phase 4(inclus dans l'audit global)
10Audit global R1Revue transversale (3 200 lignes)2 Critiques, 5 Importants, 7 Mineurs
11Audit global R2Vérification des corrections globales0 nouvelle découverte
12Phase 5 : DocsMarketing, tableau de bord, 4 pages de docs--
13Phase 5 : Mise à jourSynchronisation des docs avec les commandes Phase 2-4--

Treize sessions. Chaque session opère avec un contexte vierge -- pas de report des sessions précédentes, pas de biais du constructeur.

Ce qui a été construit

Nouvelles commandes CLI (16)

CommandeLignesPhaseObjectif
sh0 push~5801Déploiement en une commande depuis un répertoire local
sh0 login~901Authentification interactive
sh0 whoami~301Afficher l'identité actuelle
sh0 init~1202Détection de stack + génération du .sh0ignore
sh0 link~602Lier un répertoire à une app existante
sh0 open~502Ouvrir l'URL de l'app dans le navigateur
sh0 config~1002Gérer le fichier de configuration
sh0 restart~153Redémarrer l'application
sh0 stop~303Arrêter avec confirmation
sh0 start~153Démarrer une application arrêtée
sh0 delete~403Supprimer avec confirmation par le nom
sh0 domains~1003Sous-commande de gestion des domaines
sh0 watch~1304Auto-push sur changement de fichier

Nouveau code côté serveur

EndpointObjectif
POST /api/v1/apps/:id/uploadRe-upload vers une app existante
GET /api/v1/deployments/:id/streamStreaming des logs de build via WebSocket

Infrastructure de support

ComposantObjectif
Deployment::has_active_by_app_id()Garde contre les déploiements concurrents
ApiError::ConflictVariante de réponse HTTP 409
Struct StreamResultÉtat terminal unifié depuis WS/HTTP
update_phase_from_log()Détection de phase de build partagée
should_ignore_public()Logique d'exclusion partagée pour push/watch

Documentation

SurfacePages/Commandes
Page marketing (sh0.dev/cli)31 commandes, workflow en 5 étapes
Page tableau de bord (/cli)29 commandes, 5 langues
Docs vue d'ensemble4 workflows principaux
Docs installationGuide par plateforme
Docs push & deployRéférence complète de push
Docs commandesRéférence complète des commandes

Le tableau de bord de l'audit

MétriquePhase 1Phase 2Phase 3GlobalTotal
Critique30126
Important810514
Mineur924722
Corrigé1111720
Tests ajoutés10001
Régressions00000

Six découvertes Critiques sur 3 200 lignes de code. Soit un bug Critique pour 533 lignes. Pour contexte, les études industrielles estiment une vulnérabilité de sécurité pour 1 000 à 2 000 lignes de code en production. Le processus d'audit a trouvé et corrigé les problèmes à environ deux fois le taux de détection habituel.

Le compteur de régressions à zéro mérite d'être noté. Vingt corrections appliquées à travers six sessions d'audit, sans qu'aucune correction n'introduise un nouveau bug. Cela suggère que les corrections étaient chirurgicales (modifications ciblées de fonctions spécifiques) plutôt que structurelles (refactorisations pouvant se propager en cascade).

Décisions clés

Décision 1 : auditer après chaque phase, pas après toutes les phases

Nous aurions pu construire les quatre phases et auditer l'ensemble du code une seule fois. Cela aurait été plus rapide (moins de sessions) mais moins efficace. Les bugs trouvés dans l'audit de la Phase 1 ont informé les motifs utilisés dans l'implémentation de la Phase 2. Le motif d'écriture atomique, découvert comme correction de bug en Phase 1, a été appliqué proactivement en Phases 2 et 3.

Décision 2 : audit global après les audits par phase

Les audits par phase examinent le code à l'intérieur d'une frontière. Ils ne peuvent pas détecter les incohérences entre les frontières. L'audit global a trouvé des problèmes transversaux qu'aucun audit par phase n'aurait pu détecter : incohérence du masquage de token, divergence de la logique d'exclusion, limites de pagination.

La leçon : la correction locale n'implique pas la correction globale. Une fonction peut être correcte en isolation et quand même être erronée en contexte.

Décision 3 : réutiliser l'infrastructure existante

Les 16 commandes ont toutes été construites sur du code sh0 existant :

  • Détection de stack : sh0_builder::detector::detect_stack()
  • Vérification de santé : sh0_builder::health::check_health()
  • Pipeline d'upload : sh0-api/src/deploy/pipeline.rs
  • Résolution d'application : Sh0Client::resolve_app()
  • Client WebSocket : tokio-tungstenite (depuis sh0 logs)
  • Serveur WebSocket : axum::extract::ws (depuis le terminal)

Aucune nouvelle dépendance n'a été introduite pour le code côté serveur. Les seules nouvelles dépendances côté client étaient notify (surveillant de fichiers), percent-encoding (encodage d'URL) et des feature flags sur des crates existants.

Décision 4 : WebSocket avec repli HTTP

Le streaming des logs de build aurait pu être exclusivement WebSocket. Nous avons choisi de garder le polling HTTP comme repli car :

  1. Certains proxys inverses suppriment les en-têtes de mise à niveau WebSocket
  2. Le CLI doit fonctionner avec des serveurs sh0 antérieurs au endpoint de stream
  3. Le repli est gratuit -- c'est le code existant de la Phase 1, refactorisé dans une fonction

Le coût du repli est d'environ 50 lignes de code. Le bénéfice est la rétrocompatibilité sans aucune rupture.

Ce que nous avons appris

1. L'écart constructeur-auditeur est réel

Le même modèle qui construit le code ne peut pas l'auditer efficacement dans la même session. Non pas à cause d'une limitation de capacité, mais à cause d'une limitation de contexte. Le constructeur a accumulé des centaines de micro-décisions et d'hypothèses. L'auditeur part sans aucune.

Ce n'est pas propre à l'IA. Les développeurs humains ont les mêmes angles morts pour leur propre code. La solution est la même : une revue indépendante par quelqu'un qui ne l'a pas écrit.

2. Les audits transversaux sont non négociables

Cinq des vingt corrections provenaient de l'audit global. C'étaient des bugs qui existaient dans l'espace entre les commandes, invisibles à toute revue d'une seule commande. Masquage de token, logique d'exclusion, limites de pagination -- toutes des préoccupations transversales qui nécessitent de voir toute la surface en une fois.

3. La dette documentaire s'accumule plus vite que la dette technique

Entre les docs de la Phase 1 et la mise à jour de la Phase 5, dix commandes étaient complètement non documentées. L'écart représentait environ six sessions. Dans une équipe de développement traditionnelle, cela représenterait des semaines ou des mois de dérive. Avec le développement assisté par IA, c'étaient des heures -- mais la dette était la même : des fonctionnalités qui existent mais que personne ne peut découvrir.

La correction consiste à regrouper les mises à jour de documentation après que l'implémentation est terminée, pas à documenter de manière incrémentale pendant l'implémentation. Les docs incrémentales deviennent obsolètes quand les phases suivantes modifient la surface.

4. Les fines couches d'interface sont sous-estimées

Les cinq commandes de la Phase 3 font chacune moins de 50 lignes. Ce sont de fines couches d'interface autour d'appels API avec des invites de confirmation. Il n'y a rien d'ingénieux dedans. Ce sont aussi les ajouts les plus immédiatement utiles du CLI, car elles remplacent des actions courantes du tableau de bord par des commandes uniques.

La leçon : chaque fonctionnalité n'a pas besoin d'être techniquement intéressante. Parfois, le travail à plus haute valeur est le code le plus simple.

Le CLI complet

sh0 est désormais livré avec plus de 30 commandes :

Authentification      push, login, whoami, config
Déploiement           push, init, link, watch, deploy
Cycle de vie          restart, stop, start, delete, open
Domaines              domains list, add, remove
Gestion               status, logs, env, ssh, scale
Infrastructure        templates, compose, cron, yaml
Avancé                hooks, preview, export, users, projects

Chaque action du tableau de bord a un équivalent CLI. Chaque commande CLI a de la documentation. Chaque morceau de code a été audité au moins deux fois. Le CLI n'est pas une interface secondaire -- c'est un citoyen de première classe de la plateforme sh0.

De zéro à là en une journée. Non pas parce qu'une journée c'est rapide, mais parce que la méthodologie -- construire, auditer, auditer, documenter -- rend possible d'avancer vite sans avancer imprudemment.

Le propos plus large

Cette série d'articles ne parle pas d'un CLI. Elle parle d'une méthodologie pour construire du logiciel de production avec l'IA.

La méthodologie a trois propriétés :

  1. Séparation des préoccupations : le constructeur optimise pour les fonctionnalités. L'auditeur optimise pour la correction. Le documenteur optimise pour la clarté. Aucune session unique n'essaie de faire les trois.
  1. Le contexte vierge comme fonctionnalité : chaque session d'audit démarre sans les hypothèses du constructeur. Ce n'est pas une limitation des fenêtres de contexte de l'IA -- c'est un choix de conception délibéré qui produit de meilleures revues.
  1. Convergence par la diversité : construire, auditer, auditer, approuver. Chaque passe voit le code sous un angle différent. Le résultat converge vers quelque chose qu'aucune passe unique ne produirait.

Seize commandes. Six sessions d'audit. Vingt corrections de bugs. Zéro régression. Une journée.

Voilà ce que la méthodologie produit. Pas la perfection -- mais une réduction systématique de l'écart entre « ça fonctionne sur ma machine » et « ça fonctionne en production ».


Cet article fait partie de la série « Comment nous avons ajouté un CLI à sh0 ». Commencez par le début : Une seule commande pour déployer : comment nous avons construit sh0 push.

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles