Skip to content
HN On Hacker News ↗

Command Line Interface Guidelines

▲ 171 points • 53 comments • by subset • 4mo ago • HN discussion ↗

Pangram verdict · v3.3

We believe that this document is fully human-written

0 %

AI likelihood · overall

Human
100% human-written 0% AI-generated
SEGMENTS · HUMAN 5 of 5
SEGMENTS · AI 0 of 5
WORD COUNT 1,932
PEAK AI % 0% · §1
Analyzed
Jul 15
backend: pangram/v3.3
Segments scanned
5 windows
avg 386 words each
Distribution
100 / 0%
human / AI fraction
Verdict
Human
Pangram v3.3

Article text · 1,932 words · 5 segments analyzed

Human AI-generated
§1 Human · 0%

An open-source guide to help you write better command-line programs, taking traditional UNIX principles and updating them for the modern day. Aanand Prasad Engineer at Squarespace, co-creator of Docker Compose. @aanandprasad Ben Firshman Co-founder of Replicate, co-creator of Docker Compose. @bfirsh Carl Tashian Offroad Engineer at Smallstep, first engineer at Zipcar, co-founder Trove. tashian.com @tashian Eva Parish Technical Writer at Squarespace, O’Reilly contributor. evaparish.com @evpari Design by Mark Hurrell. Thanks to Andreas Jansson for early contributions, and Andrew Reitz, Ashley Williams, Brendan Falk, Chester Ramey, Dj Walker-Morgan, Jacob Maine, James Coglan, Michael Dwan, and Steve Klabnik for reviewing drafts. Join us on Discord if you want to discuss the guide or CLI design. Foreword In the 1980s, if you wanted a personal computer to do something for you, you needed to know what to type when confronted with C:\> or ~$. Help came in the form of thick, spiral-bound manuals. Error messages were opaque. There was no Stack Overflow to save you. But if you were lucky enough to have internet access, you could get help from Usenet—an early internet community filled with other people who were just as frustrated as you were. They could either help you solve your problem, or at least provide some moral support and camaraderie. Forty years later, computers have become so much more accessible to everyone, often at the expense of low-level end user control. On many devices, there is no command-line access at all, in part because it goes against the corporate interests of walled gardens and app stores. Most people today don’t know what the command line is, much less why they would want to bother with it. As computing pioneer Alan Kay said in a 2017 interview, “Because people don’t understand what computing is about, they think they have it in the iPhone, and that illusion is as bad as the illusion that ‘Guitar Hero’ is the same as a real guitar.” Kay’s “real guitar” isn’t the CLI—not exactly. He was talking about ways of programming computers that offer the power of the CLI and that transcend writing software in text files.

§2 Human · 0%

There is a belief among Kay’s disciples that we need to break out of a text-based local maximum that we’ve been living in for decades. It’s exciting to imagine a future where we program computers very differently. Even today, spreadsheets are by far the most popular programming language, and the no-code movement is taking off quickly as it attempts to replace some of the intense demand for talented programmers. Yet with its creaky, decades-old constraints and inexplicable quirks, the command line is still the most versatile corner of the computer. It lets you pull back the curtain, see what’s really going on, and creatively interact with the machine at a level of sophistication and depth that GUIs cannot afford. It’s available on almost any laptop, for anyone who wants to learn it. It can be used interactively, or it can be automated. And, it doesn’t change as fast as other parts of the system. There is creative value in its stability. So, while we still have it, we should try to maximize its utility and accessibility. A lot has changed about how we program computers since those early days. The command line of the past was machine-first: little more than a REPL on top of a scripting platform. But as general-purpose interpreted languages have flourished, the role of the shell script has shrunk. Today’s command line is human-first: a text-based UI that affords access to all kinds of tools, systems and platforms. In the past, the editor was inside the terminal—today, the terminal is just as often a feature of the editor. And there’s been a proliferation of git-like multi-tool commands. Commands within commands, and high-level commands that perform entire workflows rather than atomic functions. Inspired by traditional UNIX philosophy, driven by an interest in encouraging a more delightful and accessible CLI environment, and guided by our experiences as programmers, we decided it was time to revisit the best practices and design principles for building command-line programs. Long live the command line! Introduction This document covers both high-level design philosophy, and concrete guidelines. It’s heavier on the guidelines because our philosophy as practitioners is not to philosophize too much. We believe in learning by example, so we’ve provided plenty of those. This guide doesn’t cover full-screen terminal programs like emacs and vim. Full-screen programs are niche projects—very few of us will ever be in the position to design one.

§3 Human · 0%

This guide is also agnostic about programming languages and tooling in general. Who is this guide for? If you are creating a CLI program and you are looking for principles and concrete best practices for its UI design, this guide is for you. If you are a professional “CLI UI designer,” that’s amazing—we’d love to learn from you. If you’d like to avoid obvious missteps of the variety that go against 40 years of CLI design conventions, this guide is for you. If you want to delight people with your program’s good design and helpful help, this guide is definitely for you. If you are creating a GUI program, this guide is not for you—though you may learn some GUI anti-patterns if you decide to read it anyway. If you are designing an immersive, full-screen CLI port of Minecraft, this guide isn’t for you. (But we can’t wait to see it!) Philosophy These are what we consider to be the fundamental principles of good CLI design. Human-first design Traditionally, UNIX commands were written under the assumption they were going to be used primarily by other programs. They had more in common with functions in a programming language than with graphical applications. Today, even though many CLI programs are used primarily (or even exclusively) by humans, a lot of their interaction design still carries the baggage of the past. It’s time to shed some of this baggage: if a command is going to be used primarily by humans, it should be designed for humans first. Simple parts that work together A core tenet of the original UNIX philosophy is the idea that small, simple programs with clean interfaces can be combined to build larger systems. Rather than stuff more and more features into those programs, you make programs that are modular enough to be recombined as needed. In the old days, pipes and shell scripts played a crucial role in the process of composing programs together. Their role might have diminished with the rise of general-purpose interpreted languages, but they certainly haven’t gone away. What’s more, large-scale automation—in the form of CI/CD, orchestration and configuration management—has flourished. Making programs composable is just as important as ever. Fortunately, the long-established conventions of the UNIX environment, designed for this exact purpose, still help us today. Standard in/out/err, signals, exit codes and other mechanisms ensure that different programs click together nicely.

§4 Human · 0%

Plain, line-based text is easy to pipe between commands. JSON, a much more recent invention, affords us more structure when we need it, and lets us more easily integrate command-line tools with the web. Whatever software you’re building, you can be absolutely certain that people will use it in ways you didn’t anticipate. Your software will become a part in a larger system—your only choice is over whether it will be a well-behaved part. Most importantly, designing for composability does not need to be at odds with designing for humans first. Much of the advice in this document is about how to achieve both. Consistency across programs The terminal’s conventions are hardwired into our fingers. We had to pay an upfront cost by learning about command line syntax, flags, environment variables and so on, but it pays off in long-term efficiency… as long as programs are consistent. Where possible, a CLI should follow patterns that already exist. That’s what makes CLIs intuitive and guessable; that’s what makes users efficient. That being said, sometimes consistency conflicts with ease of use. For example, many long-established UNIX commands don’t output much information by default, which can cause confusion or worry for people less familiar with the command line. When following convention would compromise a program’s usability, it might be time to break with it—but such a decision should be made with care. Saying (just) enough The terminal is a world of pure information. You could make an argument that information is the interface—and that, just like with any interface, there’s often too much or too little of it. A command is saying too little when it hangs for several minutes and the user starts to wonder if it’s broken. A command is saying too much when it dumps pages and pages of debugging output, drowning what’s truly important in an ocean of loose detritus. The end result is the same: a lack of clarity, leaving the user confused and irritated. It can be very difficult to get this balance right, but it’s absolutely crucial if software is to empower and serve its users. Ease of discovery When it comes to making functionality discoverable, GUIs have the upper hand. Everything you can do is laid out in front of you on the screen, so you can find what you need without having to learn anything, and perhaps even discover things you didn’t know were possible.

§5 Human · 0%

It is assumed that command-line interfaces are the opposite of this—that you have to remember how to do everything. The original Macintosh Human Interface Guidelines, published in 1987, recommend “See-and-point (instead of remember-and-type),” as if you could only choose one or the other. These things needn’t be mutually exclusive. The efficiency of using the command-line comes from remembering commands, but there’s no reason the commands can’t help you learn and remember. Discoverable CLIs have comprehensive help texts, provide lots of examples, suggest what command to run next, suggest what to do when there is an error. There are lots of ideas that can be stolen from GUIs to make CLIs easier to learn and use, even for power users. Citation: The Design of Everyday Things (Don Norman), Macintosh Human Interface Guidelines Conversation as the norm GUI design, particularly in its early days, made heavy use of metaphor: desktops, files, folders, recycle bins. It made a lot of sense, because computers were still trying to bootstrap themselves into legitimacy. The ease of implementation of metaphors was one of the huge advantages GUIs wielded over CLIs. Ironically, though, the CLI has embodied an accidental metaphor all along: it’s a conversation. Beyond the most utterly simple commands, running a program usually involves more than one invocation. Usually, this is because it’s hard to get it right the first time: the user types a command, gets an error, changes the command, gets a different error, and so on, until it works. This mode of learning through repeated failure is like a conversation the user is having with the program. Trial-and-error isn’t the only type of conversational interaction, though. There are others: Running one command to set up a tool and then learning what commands to run to actually start using it. Running several commands to set up an operation, and then a final command to run it (e.g. multiple git adds, followed by a git commit). Exploring a system—for example, doing a lot of cd and ls to get a sense of a directory structure, or git log and git show to explore the history of a file. Doing a dry-run of a complex operation before running it for real. Acknowledging the conversational nature of command-line interaction means you can bring relevant techniques to bear on its design.