- Una referencia en forma de documento open source que organiza principios de diseño y lineamientos concretos para programas CLI como una reinterpretación moderna de la filosofía tradicional de UNIX, dirigida principalmente a desarrolladores que crean herramientas de línea de comandos
- La CLI ya no es solo una plataforma simple para scripting, sino que ha evolucionado hacia una UI de texto centrada en humanos, y los principios de diseño también deben actualizarse en consecuencia
- La componibilidad (composability) y la facilidad de uso para humanos no se contradicen; si se respetan las convenciones de UNIX como entrada/salida estándar, pipes y códigos de salida, es posible lograr ambas al mismo tiempo
- Ofrece recomendaciones concretas incluso sobre detalles que suelen pasarse por alto en la práctica, como texto de ayuda, mensajes de error, formato de salida, interactividad y sistemas de configuración
- La compatibilidad futura y la confianza del usuario en las herramientas CLI se definen por la estabilidad de la interfaz y la transparencia de los datos analíticos, y esta guía presenta esa línea base
Filosofía (Philosophy)
Diseño centrado en humanos
- Los comandos tradicionales de UNIX se diseñaron principalmente asumiendo que serían usados por otros programas, pero hoy la mayoría de las CLI son usadas directamente por personas, por lo que se necesita un diseño con prioridad en el ser humano
- Antes la CLI era "machine-first", pero ahora ha evolucionado hacia una UI de texto "human-first"
Pequeñas piezas componibles
- El núcleo de la filosofía UNIX es combinar programas pequeños y simples para construir sistemas más grandes, y eso sigue siendo válido hoy
stdin/stdout/stderrestándar, señales y códigos de salida garantizan la conexión entre programas, y JSON permite un intercambio de datos más estructurado- El software inevitablemente se convierte en parte de un sistema más grande, y si será una pieza que funcione bien o no se decide en la etapa de diseño
Consistencia
- Los usuarios de terminal ya están acostumbrados a las convenciones existentes, por lo que se recomienda que las CLI sigan los patrones ya establecidos
- Aun así, si la consistencia perjudica la usabilidad, es posible romper con la convención de manera cuidadosa
Cantidad adecuada de información
- Si un comando espera durante varios minutos sin mostrar nada, hay "muy poca" información; si arroja grandes cantidades de logs de depuración, hay "demasiada" información
- El equilibrio en la cantidad de información es absolutamente clave para que el software apoye al usuario
Facilidad de descubrimiento (Ease of Discovery)
- Las GUI muestran todas las funciones en pantalla, mientras que a la CLI suele atribuírsele erróneamente una dependencia de la memoria
- Con texto de ayuda completo, ejemplos abundantes y sugerencias del siguiente comando, la CLI también puede hacerse fácil de aprender tomando prestadas técnicas de las GUI
La CLI como conversación
- Usar una CLI tiene una estructura conversacional de prueba y error repetidos; sugerencias para corregir errores, mostrar estados intermedios y pedir confirmación antes de tareas riesgosas son técnicas de diseño que aprovechan esa característica
- La peor interacción es una conversación hostil que deja al usuario impotente; la mejor es un intercambio agradable que genera sensación de logro
Robustez (Robustness)
- El software debe ser robusto tanto en la realidad como en la percepción
- Manejar con elegancia entradas inesperadas, mantener la idempotencia, informar del progreso y evitar exponer stack traces son puntos clave
- Reducir casos especiales complejos y mantener la simplicidad aumenta la robustez
Empatía (Empathy)
- Las herramientas CLI son instrumentos creativos para desarrolladores, por lo que deben ser agradables de usar
- Diseña pensando lo suficiente en el problema para que el usuario sienta que la herramienta está de su lado
Caos (Chaos)
- El mundo de la terminal está lleno de inconsistencias, pero ese caos también es fuente de creación libre
- "Si un estándar es claramente perjudicial para la productividad o la satisfacción del usuario, abandona ese estándar" — Jef Raskin
Lineamientos — Lo básico (The Basics)
- Usa una biblioteca de parseo de argumentos: entre las recomendadas por lenguaje están Go(Cobra, cli), Python(Click, Typer, Argparse), Rust(clap), Node(oclif), entre otras
- En caso de éxito devuelve código de salida 0; en caso de fallo, un código distinto de 0 — este es el criterio que usan los scripts para distinguir éxito y error
- La salida por defecto debe ir a
stdout, y los mensajes como logs o errores astderr
Lineamientos — Ayuda (Help)
- Muestra texto de ayuda detallado con la bandera
-ho--help, y aplica lo mismo a los subcomandos - Si se ejecuta sin argumentos, muestra una ayuda breve (incluyendo descripción, 1 o 2 ejemplos, explicación de banderas y referencia a
--help)- Se menciona a
jqcomo un buen ejemplo de esta implementación
- Se menciona a
- Soporta distintas formas de pedir ayuda como
--help,-hohelp subcommand - Proporciona en la parte superior del texto de ayuda un enlace a la documentación web y una vía para enviar feedback
- Muestra primero los ejemplos — se recomienda construir una narrativa que avance gradualmente hacia casos de uso más complejos
- Coloca las banderas y comandos más usados al inicio del texto de ayuda (tomando como referencia la organización de git)
- Usa formato como títulos en negrita para que sea fácil de escanear, pero de forma independiente del terminal
- Cuando el usuario escriba algo incorrecto, puedes inferir su intención y sugerir una corrección; aun así, decidir ejecutar automáticamente esa corrección requiere cautela
- Una entrada incorrecta puede no ser solo un typo sino un error lógico, y la autocorrección también implica la carga de mantener ese comportamiento de forma permanente
Lineamientos — Documentación (Documentation)
- Proporciona documentación basada en web — es esencial para la capacidad de búsqueda y para compartir enlaces
- Proporciona documentación en terminal — se mantiene sincronizada con la versión instalada y sigue siendo accesible sin conexión
- Considera ofrecer páginas man — pueden generarse con herramientas como
ronn, y se recomienda permitir acceso por subcomando, como ennpm help ls
Lineamientos — Salida (Output)
- La legibilidad humana es la prioridad — usa si es TTY o no para determinar si quien lee es una persona
- Los flujos de texto son la interfaz universal de UNIX, así que también debe haber salida legible por máquina
- Si la salida amigable para humanos perjudica la compatibilidad con pipes, ofrece salida de texto plano con la bandera
--plain - Si se pasa la bandera
--json, soporta salida en formato JSON - En caso de éxito, la salida debe ser concisa; si no hace falta, no imprimas nada — para scripts, ofrece la opción
-qpara suprimir salida - Informa al usuario cuando cambie el estado — que
git pushmuestre el estado de la rama remota es un buen ejemplo - Diseña la salida para que, como en
git status, sea fácil ver el estado actual del sistema y también el siguiente paso a realizar - Usa color de forma intencional, y desactívalo obligatoriamente en condiciones como pipes,
NO_COLOR,TERM=dumbo--no-color - En entornos que no sean TTY, no muestres animaciones ni spinners (para evitar contaminar logs de CI)
- Usa emoji o símbolos solo cuando realmente mejoren la claridad (
yubikey-agentse presenta como ejemplo) - La información que solo entiende el desarrollador debe quedar fuera de la salida por defecto y mostrarse solo en modo verbose
- No uses
stderrcomo si fuera un archivo de logs — en general evita imprimir etiquetas de nivel comoERRoWARN - Si la salida es muy extensa, considera usar un pager como
less— actívalo solo en entornos TTY y se recomiendan opcionesless -FIRX
Lineamientos — Errores (Errors)
- Reescribe los errores previsibles en mensajes comprensibles para humanos (por ejemplo, "necesitas ejecutar
chmod +w file.txt") - Mantén una buena relación señal/ruido — agrupa errores del mismo tipo bajo un solo encabezado
- Coloca la información importante al final de la salida — el texto rojo debe usarse con intención y rara vez
- Si ocurre un error inesperado, incluye información de depuración y cómo enviar un reporte de bug
- Diseña la URL del reporte de bug para que la información se rellene automáticamente y sea fácil de enviar
Lineamientos — Argumentos y banderas (Arguments and Flags)
- Los argumentos (
args) son posicionales y las banderas (flags) tienen nombre — prefiere banderas por encima de argumentos - Proporciona una versión con nombre completo para todas las banderas (por ejemplo, soporte simultáneo de
-hy--help) - Limita las banderas de un solo carácter a las que se usan con frecuencia
- Cuando exista un estándar, usa nombres de banderas estándar (
-f/--force,-q/--quiet,-v,--json, etc.) - Configura valores por defecto que sean adecuados para la mayoría de los usuarios
- Si no se pasan argumentos o banderas, solicita la entrada mediante prompt, pero nunca fuerces prompts en entornos no interactivos
- Antes de operaciones peligrosas, pide confirmación — según el nivel de riesgo, usa confirmación
y/n, ofrece un dry-run o exige escribir texto explícitamente- Se distingue el riesgo como mild (borrar un archivo), moderate (borrar un directorio, modificar recursos remotos) y severe (borrar un servidor completo)
- En entrada/salida de archivos, soporta leer/escribir desde stdin/stdout usando
-(por ejemplo,curl ... | tar xvf -) - No recibas secretos directamente en banderas — se recomienda una bandera como
--password-fileo usarstdin(por el riesgo de exposición en salida depso historial del shell)
Lineamientos — Interactividad (Interactivity)
- Los prompts y elementos interactivos deben mostrarse solo cuando
stdinsea un TTY - Si se pasa
--no-input, desactiva todos los prompts - Al ingresar contraseñas, desactiva el eco (no mostrar en pantalla lo escrito)
- Indica con claridad cómo el usuario puede salir en cualquier momento — Ctrl-C debe seguir funcionando siempre
Lineamientos — Subcomandos (Subcommands)
- Mantén consistencia en nombres de banderas y formatos de salida entre subcomandos
- En herramientas complejas, usa una estructura de subcomandos de dos niveles tipo
noun verboverb noun(por ejemplo,docker container create) - Evita subcomandos con nombres ambiguos o demasiado parecidos (por ejemplo, no usar a la vez update y upgrade)
Lineamientos — Robustez (Robustness Guidelines)
- Realiza la validación de entrada desde el inicio y termina pronto con un error fácil de entender si los datos no son válidos
- La capacidad de respuesta importa más que la velocidad — muestra algo en menos de 100 ms
- En tareas largas, ofrece una barra de progreso (progress bar) — pueden usarse bibliotecas como Python(tqdm), Go(schollz/progressbar), Node(node-progress)
- En procesamiento en paralelo, cuida que la salida no se mezcle
- Configura timeouts de red — incluyendo valores por defecto para evitar esperas infinitas
- Tras errores temporales, diseña el sistema para que pueda reanudar desde el estado anterior al reintentar
- Diseño crash-only — estructura que pueda terminar de inmediato sin tareas de limpieza para asegurar idempotencia
Lineamientos — Compatibilidad futura (Future-proofing)
- Mantén los cambios de forma aditiva y compatible hacia atrás
- Antes de cambios que rompan compatibilidad, muestra una advertencia previa dentro del programa
- En general se permiten cambios en la salida para humanos — para scripts, orienta a usar
--plaino--json - Prohíbe subcomandos catch-all — luego impiden agregar un subcomando real con ese nombre
- No permitas abreviaturas automáticas de subcomandos — solo aliases explícitos y mantenidos de forma estable
- Prohíbe las "bombas de tiempo" — minimiza dependencias externas para que siga funcionando incluso dentro de 20 años
Lineamientos — Señales y caracteres de control (Signals)
- Al recibir Ctrl-C (señal INT), termina de inmediato y pon timeout a las tareas de limpieza
- Si el usuario pulsa Ctrl-C otra vez durante la limpieza, indícale que puede forzar la salida (véase el ejemplo de Docker Compose)
- Diseña el programa asumiendo que puede iniciarse con tareas de limpieza incompletas
Lineamientos — Configuración (Configuration)
Prioridad para aplicar configuración (alta → baja):
- banderas → variables de entorno del shell actual → configuración a nivel proyecto (
.env) → configuración a nivel usuario → configuración a nivel sistema
Recomendaciones por tipo de configuración:
-
Configuración que cambia en cada invocación (nivel de debug, dry-run): usar banderas
-
Configuración que cambia por proyecto o por máquina (rutas, color, proxy HTTP): combinación de banderas + variables de entorno
-
Configuración compartida de todo el proyecto (tipo Makefile, package.json): usar archivos versionados
-
Cumple con la especificación XDG Base Directory — se recomiendan rutas de configuración basadas en
~/.config(compatibles con yarn, fish, neovim, tmux, etc.) -
Si modificas automáticamente archivos de configuración de otros programas, es obligatorio obtener el consentimiento del usuario
Lineamientos — Variables de entorno (Environment Variables)
- Las variables de entorno son apropiadas para comportamientos que cambian según el contexto de ejecución
- En los nombres usa solo mayúsculas, números y guion bajo, y no empieces con un número
- Se recomiendan valores de una sola línea — los valores multilínea causan problemas de compatibilidad con el comando
env - Revisa primero variables de entorno universales como
NO_COLOR,DEBUG,EDITOR,HTTP_PROXY,SHELL,TMPDIR,HOME,PAGER - Se recomienda soportar lectura de archivos
.envpor proyecto — pero.envno reemplaza un archivo de configuración formal- Limitaciones de
.env: no forma parte del control de versiones, no tiene historial, solo admite el tipo string y es vulnerable a problemas de codificación
- Limitaciones de
- No leas secretos desde variables de entorno — se propagan a todos los procesos, pueden filtrarse en logs y quedar expuestos mediante
Docker inspectosystemctl show- Los secretos deben recibirse solo mediante archivos de credenciales, pipes, sockets
AF_UNIXo servicios de gestión de secretos
- Los secretos deben recibirse solo mediante archivos de credenciales, pipes, sockets
Lineamientos — Nombres (Naming)
- Usa palabras simples y fáciles de recordar — si son demasiado genéricas, existe riesgo de conflicto con otros comandos
- Usa solo minúsculas y, si hace falta, guiones (
curles un buen ejemplo;DownloadURLes un mal ejemplo) - Mantén el nombre corto, pero nombres extremadamente breves como
cd,ls,psquedan reservados para utilidades de uso general - El caso de renombrado del antecesor de Docker Compose,
plum→fig→docker compose, muestra en la práctica que la facilidad de escritura es un criterio importante al nombrar
Lineamientos — Distribución (Distribution)
- Siempre que sea posible, distribuye como binario único — usando herramientas como PyInstaller
- Si no es posible un binario único, usa instaladores de paquetes nativos de la plataforma
- Indica cómo desinstalar al final de las instrucciones de instalación
Lineamientos — Analítica (Analytics)
- No envíes datos de uso ni datos de fallos sin consentimiento del usuario
- Si recopilas datos, publica claramente qué se recopila, por qué, cómo se anonimiza y cuánto tiempo se conserva
- Se recomienda opt-in por defecto — si usas opt-out, notifícalo claramente en la primera ejecución o en el sitio web
- Se presentan tres casos: Angular.js (opt-in explícito), Homebrew (Google Analytics, FAQ pública) y Next.js (estadísticas anónimas activadas por defecto)
- Como alternativas a la analítica, pueden usarse medición de documentación web, medición de descargas y entrevistas directas con usuarios
1 comentarios
Comentarios de Hacker News
stderres para logging, información, etc., ystdoutdebe ofrecer una salida útil independientemente de si es tty o no.AF_UNIX, servicios de gestión de secretos u otros mecanismos de IPC.clig.devse puede ver que las opiniones han cambiado bastante con el tiempo.