- Une référence open source qui rassemble des principes de conception et des recommandations concrètes pour les programmes CLI, en réinterprétant de manière moderne la philosophie UNIX traditionnelle, avec pour public principal les développeurs qui créent des outils en ligne de commande
- La CLI n’est plus une simple plateforme de scripting, mais a évolué en interface texte centrée sur l’humain ; les principes de conception doivent donc être mis à jour en conséquence
- Composabilité et convivialité ne sont pas incompatibles ; en respectant les conventions UNIX comme l’entrée/sortie standard, les pipes et les codes de sortie, on peut atteindre les deux à la fois
- Le document fournit aussi des recommandations précises sur des détails souvent négligés en pratique, comme les textes d’aide, les messages d’erreur, les formats de sortie, l’interactivité ou le système de configuration
- La compatibilité future et la confiance des utilisateurs d’un outil CLI dépendent de la stabilité de l’interface et de la transparence des données analytiques ; ce guide en pose la ligne de base
Philosophie (Philosophy)
Conception centrée sur l’humain
- Les commandes UNIX traditionnelles étaient surtout conçues pour être utilisées par d’autres programmes, mais aujourd’hui les CLI sont majoritairement utilisées directement par des humains ; une conception d’abord pensée pour l’humain est donc nécessaire
- Autrefois, les CLI étaient « machine-first », mais elles ont évolué en interfaces texte « human-first »
Petits composants combinables
- Le cœur de la philosophie UNIX consiste à assembler de petits programmes simples pour construire des systèmes plus grands, et cela reste valable aujourd’hui
- Les
stdin/stdout/stderrstandard, les signaux et les codes de sortie garantissent la connexion entre programmes, tandis que JSON permet des échanges de données plus structurés - Un logiciel devient forcément une pièce d’un système plus vaste ; la qualité de cette intégration se décide dès la phase de conception
Cohérence
- Les utilisateurs du terminal ont déjà intégré les conventions existantes ; il est donc recommandé que les CLI suivent les modèles établis
- Toutefois, si la cohérence nuit à l’utilisabilité, il est possible de rompre avec une convention avec prudence
Juste niveau d’information
- Si une commande reste en attente plusieurs minutes sans rien afficher, c’est « trop peu » d’information ; si elle déverse une masse de logs de debug, c’est « trop » d’information
- L’équilibre de la quantité d’information est absolument essentiel pour qu’un logiciel aide réellement son utilisateur
Facilité de découverte (Ease of Discovery)
- Les GUI affichent toutes les fonctions à l’écran, alors que les CLI sont souvent perçues à tort comme reposant uniquement sur la mémoire
- En reprenant des techniques des GUI, comme un texte d’aide complet, des exemples riches ou des suggestions de commandes suivantes, une CLI peut elle aussi devenir facile à apprendre
La CLI comme conversation
- L’usage d’une CLI suit une structure de dialogue fondée sur des essais et erreurs répétés ; proposer des corrections, afficher les états intermédiaires ou demander confirmation avant une opération risquée sont des techniques de conception qui exploitent cette caractéristique
- La pire interaction est une conversation hostile qui rend l’utilisateur impuissant ; la meilleure est un échange agréable qui lui donne un sentiment d’accomplissement
Robustesse (Robustness)
- Un logiciel doit être robuste dans les faits comme dans le ressenti
- La gestion élégante des entrées imprévues, le maintien de l’idempotence, l’affichage de la progression et l’évitement des stack traces exposées sont des points clés
- Réduire les cas particuliers complexes et rester simple renforce la robustesse
Empathie (Empathy)
- Les outils CLI sont des outils créatifs pour développeurs et doivent donc être agréables à utiliser
- Il faut concevoir en réfléchissant suffisamment au problème pour que l’utilisateur sente que l’outil est de son côté
Chaos
- Le monde du terminal est rempli d’incohérences, mais ce chaos est aussi une source de création libre
- « Si une norme nuit clairement à la productivité ou à la satisfaction utilisateur, abandonnez-la. » — Jef Raskin
Recommandations — Les bases (The Basics)
- Utiliser une bibliothèque de parsing d’arguments : parmi les bibliothèques recommandées selon le langage figurent Go(Cobra, cli), Python(Click, Typer, Argparse), Rust(clap), Node(oclif), etc.
- En cas de succès, renvoyer le code de sortie 0 ; en cas d’échec, un code non nul — c’est ce qui permet à un script de distinguer succès et échec
- Envoyer la sortie normale vers
stdout, et les messages comme les logs et erreurs versstderr
Recommandations — Aide (Help)
- Afficher un texte d’aide détaillé avec les flags
-hou--help, y compris pour les sous-commandes - En cas d’exécution sans argument, afficher une aide concise (description, 1 à 2 exemples, explication des flags, indication sur
--help)jqest cité comme un bon exemple d’implémentation
- Prendre en charge plusieurs formes de demande d’aide comme
--help,-houhelp subcommand - Fournir en haut du texte d’aide un lien vers la documentation web et un canal de feedback
- Montrer les exemples d’abord — il est recommandé de construire une progression narrative allant vers des cas d’usage plus complexes
- Placer les flags et commandes les plus fréquents en haut du texte d’aide (voir l’organisation de
git) - Utiliser une mise en forme, par exemple des titres en gras, pour faciliter le survol visuel, tout en restant indépendant du terminal
- Lorsqu’un utilisateur saisit quelque chose d’incorrect, il est possible d’inférer son intention et de proposer une correction — mais l’exécution automatique doit être décidée avec prudence
- Une mauvaise saisie peut être non pas une simple faute de frappe, mais une erreur logique ; en corrigeant automatiquement, on s’impose aussi de supporter durablement cette syntaxe
Recommandations — Documentation (Documentation)
- Fournir une documentation web — indispensable pour la recherche et le partage de liens
- Fournir une documentation dans le terminal — synchronisée avec la version installée et accessible hors ligne
- Envisager de fournir des pages man — elles peuvent être générées avec des outils comme
ronn, et il est recommandé de les rendre accessibles via une sous-commande commenpm help ls
Recommandations — Sortie (Output)
- Donner la priorité à la lisibilité humaine — on peut déterminer si la sortie est destinée à un humain via l’état TTY
- Le flux texte est l’interface universelle d’UNIX ; il faut donc aussi proposer une sortie lisible par machine
- Si une sortie conviviale pour l’humain nuit à la compatibilité avec les pipes, fournir une sortie texte brute avec le flag
--plain - Prendre en charge une sortie au format JSON quand le flag
--jsonest passé - En cas de succès, garder une sortie concise, voire aucune sortie si elle n’est pas nécessaire — pour les scripts, proposer une option
-qpour la supprimer - Informer l’utilisateur lors d’un changement d’état — la sortie de
git pushsur l’état de la branche distante en est un bon exemple - Concevoir une sortie qui permette, comme
git status, de voir facilement l’état actuel du système et de guider vers l’action suivante - Utiliser la couleur de manière intentionnelle, et impérativement la désactiver dans des conditions comme un pipe,
NO_COLOR,TERM=dumbou--no-color - Dans un environnement non TTY, ne pas afficher d’animations ni de spinners (pour éviter de polluer les logs CI)
- N’utiliser emoji et symboles que lorsqu’ils améliorent la clarté (
yubikey-agentest cité en exemple) - Exclure de la sortie par défaut les informations compréhensibles seulement par les développeurs, et ne les afficher qu’en mode verbose
- Ne pas utiliser
stderrcomme un fichier de log — éviter par défaut les labels de niveau de log commeERRouWARN - En cas de sortie volumineuse, envisager l’usage d’un pager comme
less— à activer uniquement en environnement TTY, avec recommandation des optionsless -FIRX
Recommandations — Erreurs (Errors)
- Réécrire les erreurs prévisibles sous forme de messages compréhensibles par un humain (ex. : « vous devez exécuter
chmod +w file.txt») - Maintenir un bon rapport signal/bruit — regrouper les erreurs de même type sous un seul en-tête
- Placer les informations importantes en fin de sortie — le texte rouge doit être utilisé de manière délibérée et rare
- En cas d’erreur inattendue, inclure des informations de debug et indiquer comment soumettre un bug report
- Concevoir l’URL de bug report pour préremplir automatiquement les informations et faciliter l’envoi
Recommandations — Arguments et flags (Arguments and Flags)
- Les arguments (
args) sont positionnels, les flags sont nommés — il faut préférer les flags aux arguments - Fournir pour tous les flags une version longue complète (par ex. prise en charge simultanée de
-het--help) - Réserver les flags à un seul caractère aux options fréquemment utilisées
- Lorsqu’un standard existe, utiliser les noms de flags standard (
-f/--force,-q/--quiet,-v,--json, etc.) - Définir des valeurs par défaut adaptées à la majorité des utilisateurs
- Si un argument ou un flag n’est pas fourni, demander la saisie via un prompt, mais sans jamais l’imposer en environnement non interactif
- Demander confirmation avant les opérations risquées — selon le niveau de risque, utiliser une confirmation
y/n, proposer un dry-run ou exiger la saisie manuelle d’un texte précis- Les risques sont distingués en mild (suppression de fichier), moderate (suppression de répertoire, modification de ressources distantes) et severe (suppression d’un serveur entier)
- Pour les entrées/sorties de fichiers, prendre en charge
-pour lire depuis stdin et écrire vers stdout (ex. :curl ... | tar xvf -) - Ne pas recevoir directement des secrets via les flags — préférer un flag
--password-fileou l’usage de stdin (risque d’exposition viapsou l’historique shell)
Recommandations — Interactivité (Interactivity)
- N’afficher prompts et éléments interactifs que lorsque stdin est un TTY
- Si
--no-inputest passé, désactiver tous les prompts - Lors de la saisie d’un mot de passe, désactiver l’écho (ne pas afficher ce qui est tapé à l’écran)
- Expliquer clairement comment quitter à tout moment — Ctrl-C doit toujours fonctionner
Recommandations — Sous-commandes (Subcommands)
- Maintenir la cohérence des noms de flags et des formats de sortie entre sous-commandes
- Pour les outils complexes, utiliser une structure à sous-commandes en deux niveaux sous forme
noun verbouverb noun(ex. :docker container create) - Éviter les sous-commandes ambiguës ou aux noms trop proches (par ex. éviter d’utiliser à la fois
updateetupgrade)
Recommandations — Robustesse (Robustness Guidelines)
- Effectuer la validation des entrées tôt, et quitter rapidement avec une erreur claire en cas de données invalides
- La réactivité est plus importante que la vitesse — afficher quelque chose en moins de 100 ms
- Pour les opérations longues, fournir une barre de progression (progress bar) — avec par exemple les bibliothèques Python(tqdm), Go(schollz/progressbar), Node(node-progress)
- En traitement parallèle, veiller à ce que la sortie ne se mélange pas
- Définir des timeouts réseau — avec des valeurs par défaut, pour éviter les attentes infinies
- Après une erreur temporaire, concevoir le système pour qu’un retry reprenne depuis l’état précédent
- Conception crash-only — garantir l’idempotence avec une structure capable de s’arrêter immédiatement sans phase de nettoyage
Recommandations — Compatibilité future (Future-proofing)
- Maintenir les changements sous une forme additive et rétrocompatible
- Avant tout changement cassant, afficher un avertissement préalable dans le programme
- Les changements dans la sortie destinée aux humains sont généralement acceptables — pour les scripts, encourager l’usage de
--plainet--json - Interdire les sous-commandes catch-all — elles empêchent d’ajouter plus tard une sous-commande portant ce nom
- Ne pas autoriser automatiquement les abréviations de sous-commandes — n’accepter que des alias explicites, maintenus de façon stable
- Interdire les “bombes à retardement” — minimiser les dépendances externes pour que le programme puisse encore fonctionner dans 20 ans
Recommandations — Signaux et caractères de contrôle (Signals)
- À la réception de Ctrl-C (signal INT), quitter immédiatement, avec un timeout sur les opérations de nettoyage
- Pendant le nettoyage, indiquer qu’une nouvelle pression sur Ctrl-C peut forcer l’arrêt (voir l’exemple de Docker Compose)
- Concevoir le programme en supposant qu’il peut démarrer alors qu’un nettoyage précédent n’est pas terminé
Recommandations — Configuration (Configuration)
Ordre de priorité d’application de la configuration (du plus élevé au plus faible) :
- Flags → variables d’environnement du shell courant → configuration au niveau du projet (
.env) → configuration au niveau utilisateur → configuration système globale
Recommandations selon le type de configuration :
-
Configuration qui change à chaque appel (niveau de debug, dry-run) : utiliser des flags
-
Configuration qui diffère selon le projet ou la machine (chemins, couleur, proxy HTTP) : combiner flags + variables d’environnement
-
Configuration partagée par tout un projet (type Makefile, package.json) : utiliser des fichiers versionnés
-
Respecter la spécification XDG Base Directory — recommander des chemins de configuration basés sur
~/.config(pris en charge par yarn, fish, neovim, tmux, etc.) -
En cas de modification automatique du fichier de configuration d’un autre programme, obtenir impérativement l’accord de l’utilisateur
Recommandations — Variables d’environnement (Environment Variables)
- Les variables d’environnement conviennent aux comportements qui varient selon le contexte d’exécution
- Le nom doit utiliser uniquement des majuscules, des chiffres et des underscores, sans commencer par un chiffre
- Il est recommandé d’utiliser des valeurs sur une seule ligne — le multiligne pose des problèmes de compatibilité avec la commande
env - Vérifier en priorité les variables d’environnement génériques comme
NO_COLOR,DEBUG,EDITOR,HTTP_PROXY,SHELL,TMPDIR,HOME,PAGER - Il est recommandé de prendre en charge la lecture de fichiers
.envpropres au projet — mais.envne remplace pas un vrai fichier de configuration- Limites de
.env: absent du contrôle de version, sans historique, type unique chaîne de caractères, sensible aux problèmes d’encodage
- Limites de
- Ne pas lire les secrets depuis les variables d’environnement — elles se propagent à tous les processus, peuvent fuiter dans les logs et être exposées via
Docker inspectousystemctl show- Les secrets ne doivent être reçus que via un fichier de credentials, un pipe, une socket
AF_UNIXou un service de gestion des secrets
- Les secrets ne doivent être reçus que via un fichier de credentials, un pipe, une socket
Recommandations — Nommage (Naming)
- Utiliser des mots simples et faciles à retenir — s’ils sont trop génériques, ils risquent d’entrer en conflit avec d’autres commandes
- Utiliser uniquement des minuscules et, si nécessaire, des tirets (
curlest un bon exemple,DownloadURLun mauvais) - Garder des noms courts, mais réserver les noms extrêmement courts comme
cd,ls,psaux utilitaires génériques - Le cas de renommage de Docker Compose, passé de
plumàfigpuis àdocker compose, montre concrètement que la facilité de saisie est un critère important de naming
Recommandations — Distribution (Distribution)
- Distribuer si possible sous forme de binaire unique — avec par exemple PyInstaller
- Si ce n’est pas possible, utiliser un installeur natif à la plateforme
- Indiquer la méthode de désinstallation en bas des instructions d’installation
Recommandations — Données analytiques (Analytics)
- Ne pas envoyer de données d’usage ni de crash sans consentement utilisateur
- En cas de collecte, exposer clairement les données collectées, la raison, la méthode d’anonymisation et la durée de conservation
- Recommander l’opt-in par défaut — en cas d’opt-out, l’indiquer clairement au premier lancement ou sur le site web
- Trois cas sont présentés : Angular.js (opt-in explicite), Homebrew (Google Analytics, FAQ publique), Next.js (statistiques anonymes activées par défaut)
- Comme alternatives à l’analytics, on peut utiliser l’instrumentation de la documentation web, la mesure des téléchargements ou des entretiens directs avec les utilisateurs
1 commentaires
Commentaires Hacker News
stdout.stderrsert au logging, aux informations, etc., etstdoutdoit fournir une sortie utile, qu’il s’agisse ou non d’un tty.AF_UNIX, de services de gestion des secrets ou d’autres mécanismes IPC.