
I've spent countless hours in terminals, and something odd keeps striking me. Despite no central command telling developers how to build CLI tools, they all speak roughly the same language. q quits. Ctrl-C cancels. Colors disappear when you pipe output somewhere else.
This isn't accident. It's evolution.
The consistency comes from POSIX standards, old Unix conventions, and sheer momentum. Once enough tools agree on something, disagreement becomes a user experience problem. Below are the patterns I've noticed, the ones that make the command line feel intuitive even when you're using something completely new.
Strip ANSI colors, prompts, spinners & code fences from copied logs
Sanitize copied terminal logs, AI agent CLI outputs, and shell commands. Strip ANSI color codes, $ prompts, code fences, line numbers, and spinners.
These rules are based on real-world observation, not documentation. Modern efforts like the CLI Guidelines try to formalize what developers already knew intuitively.
If a program is noninteractive, pressing Ctrl-C should kill it immediately via a SIGINT signal. Think ping 127.0.0.1 or curl https://example.com. You hit Ctrl-C, the program dies, you get your prompt back.
Interactive programs handle this differently. Shells, text editors like vim, and similar tools catch the signal and use it for something else. In vim, Ctrl-C cancels whatever you're typing. It doesn't exit because exiting would mean losing unsaved work. That's a deliberate choice, not a bug.
Text-based User Interfaces like less, top, htop, man, and vim all respond to the q key for quitting. Try it. Open less /etc/passwd, type q, you're back at your shell. Same with top. Same with htop.
Why q and not Ctrl-Q? Ancient habit, probably. q sits left-hand home row, it's fast, and it's mnemonically obvious. This convention is so strong that breaking it feels like a personal insult.
Read-Eval-Print Loops behave differently. When you're in Python, Node's REPL, or IRB (Ruby's interactive shell), try pressing Ctrl-D on an empty line. The REPL closes. Why?
Ctrl-D sends an EOF marker, an End of File character. REPLs interpret this as "the user is done giving input" and shut down cleanly. It's graceful termination, not a violent kill like Ctrl-C.
Try it in a real terminal. Type python3, wait for the >>> prompt, press Enter, then Ctrl-D. Gone. That's the convention.
Most well-behaved terminal programs use only 16 colors. Those are the ones every terminal theme supports. True color (24-bit, 16 million colors) and 256-color modes exist, but they can conflict with user color schemes and accessibility settings. When in doubt, stay conservative.
This one bit me once and I've never forgotten it. When stdout is a terminal, print colorful output. When stdout is a pipe or file, strip the color codes. Otherwise, developers run yourcommand | grep something and see garbage like \033[31mError\033[0m in their logs.
Detect this with !isatty(stdout). Every language has an equivalent: Python has sys.stdout.isatty(), Node has process.stdout.isatty(). Use it.
Rule 5: Vaguely Support Readline Keybindings
Users bring expectations from bash. These should mostly work:
Ctrl-E jumps to the end of the lineCtrl-A jumps to the beginningCtrl-W deletes the last wordDo you need full readline compatibility? Probably not. But users will try Ctrl-A in your tool expecting it to work. When it doesn't, they notice.
What's the "last word" anyway? For most programs it's space-delimited. Ctrl-W in bash delete everything back to the last space. That behavior comes from cooked mode in the OS terminal driver, so it's what users expect.
Rule 7: A Hyphen Means Stdin or Stdout
This one surprised me when I first noticed it. Many CLI tools accept a single hyphen as a special argument meaning "read from stdin" or "write to stdout."
Some examples:
cat - reads from stdin
tar cf - /path |-gzip > file.tar.gz streams archive to stdout
diff file1 - compares file1 against stdin
It's a convention, not a requirement. But when you see it, you'll understand what the author meant.
Notice how modern Rust rewrites like bat (for cat), rg (for grep), and fd (for find) strictly obey these exact same unwritten rules? They add syntax highlighting and speed, but they still drop color when piped, still quit on Ctrl-C, and still accept - for stdin. They succeed because they respect the ghosts of POSIX past.
Here's the thing. These patterns aren't rules someone wrote down and enforced. They're emergent. When enough tools do something one way, users learn that way. New tools inherit the same behavior because defying it creates friction.
I remember the first time I used a tool that didn't respond to q for quitting. It was some custom TUI for managing Docker containers. I hit q. Nothing. I hit Ctrl-C. Nothing. I had to kill it with Ctrl-Z and kill -9. It felt broken, even though it probably worked "correctly."
That's the point. In the terminal, convention IS correctness. If your tool fights user expectations, it's wrong, regardless of what your documentation says.
The CLI Guidelines project tries to formalize some of this. It's worth reading. But honestly, the fastest way to learn these conventions isn't reading at all. It's using the terminal daily. The patterns sink in through muscle memory.
Install a new tool? Spend two minutes hitting q, Ctrl-C, Ctrl-D, and scrolling with spacebar. Most of the time, you'll discover the conventions without touching the manual.
Next time you're exploring a new CLI tool, try this. Watch how it handles interrupts. Notice whether colorful output vanishes when you pipe it somewhere. Observe what happens when you press Ctrl-A in an input field.
You'll start seeing the patterns everywhere. Because they're not accidents. They're the accumulated decisions of decades, converging on a shared understanding of how terminals should work.
And that strangeness I mentioned at the start? The "strange harmony" of unrelated commands behaving consistently? It's not strange at all when you realize it comes from the same source as language itself. Convention. Repetition. Time.
Your tools are speaking the same dialect because we all learned it from each other.
A developer is building a new interactive command-line tool that allows users to browse log files. They are debating how to handle program termination. Which of the following approaches best aligns with established terminal conventions for interactive tools and user experience?
Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.

A minimal terminal setup that actually sticks: Starship prompt, zsh-autosuggestions, syntax highlighting, and the hard-learned lesson about the dotfile rabbit hole.
Read more
Step-by-step guide to add directories and folders to PATH permanently in Linux & macOS. Edit .bashrc, .zshrc, export commands, and fix command not found.
Read more
The first time my terminal froze mid-pipeline I spent an hour debugging the wrong thing. Here's what was actually happening and how to fix it in seconds.
Read more