They reify UIs, but discoverability of functionality can be a real problem. Git, of course, is the classic example, because its "UI" is a hacked-together mess compiled over years and years and features were added piecemeal. But even for green-field CLI tools, it's a problem.

The real value of CLI tools is extensibility and scriptability. You don't have to rely on the application developer inserting UI hooks everywhere; you just write a shell script, and in the absolute worst-case scenario use Expect to automate interactive processes. And adding a new subcommand is relatively trivial. The code is typically easy to trace the user input down to the internal machinery. The UI is a very simple function dispatch and argument-passing mechanism. There are no widgets to worry about, no switches or boxes to position.

Therefore CLI tools will always be beloved by power users and feared by everyone else. If you know exactly what you're doing, they can really speed up your workflow and provide and interface for precise, expressive control and automation. Otherwise, all but the best-designed CLI tools are intimidating and difficult to master. Who can remember all those switches? Having a bunch of labeled buttons laid out in a UI leads to a much lower cognitive load.

IMO the real value is in CLI applications that can be embedded in a GUI, but are embedded transparently, in that the GUI can be scripted by simply scripting the underlying CLI. Git (Git GUI, GitHub, Tortoise, Tower, etc), Apt (Aptitude, others), TeX (Tex Live Manager, kinda), and others have good interfaces along these lines, but we're definitely in need of a good CLI interface for Rsync and Tar. Many CLI wrapper GUIs tend to be opaque and don't expose enough underlying functionality.

One standard for history-keeping is the following: If we start with a clean system, and replay all the commands from the history, will we end up with the same system?

This is how Lighttable, Photoshop, and other Adobe CS products work. Also the Vim "undo tree" to some extent. It's an excellent feature.

> IMO the real value is in CLI applications that can be embedded in a GUI, but are embedded transparently, in that the GUI can be scripted by simply scripting the underlying CLI.

This is where your CLI application becomes a de-facto API and the wrapper has to anticipate and handle any output from the command. It's an astonishingly brittle system (have fun using any GUI around CVS) to the point that in many cases the GUI doesn't actually wrap a CLI application, but instead uses a library (e.g. most Git GUIs probably use libgit2 instead of calling the CLI). Libraries tend to have better designed interfaces for other programs, you don't have any problems with shell quoting and you don't try to shoehorn an interface for users into one for programs.

Some tiling window managers work this way without any issues.

Bspwm[0], for instance, uses a client CLI program (bspc) to send commands to the daemon and alter its configuration at runtime.

In fact, it doesn't have a configuration file format at all, since it can be configured via a simple shell script that runs a sequence of bspc commands.

It also doesn't have any key binding functionality and offloads this to a separate program, sxhkd[1], whose only purpose is to interpret key presses and execute shell commands. Since this is bspwm's interface, the two work seamlessly together, even though they're not dependent on each other at all.

This is just brilliant design, and speaks volumes for the "do one thing and do it well" school of thought.

For the record, I've been using both programs without a single issue for the past 3 years at least, and it's been one of the most stable and least problematic systems I've ever used, and use to this day.

So just wanted to offer an opposing personal experience (anecdotal, to be sure) regarding your brittleness concerns with this interface.

[0]: https://github.com/baskerville/bspwm [1]: https://github.com/baskerville/sxhkd