CLI tool
python-cmd2/cmd2 avatar
python-cmd2/cmd2

cmd2: A Python Framework for Interactive CLIs That Grow Into Scriptable Tools

cmd2 - quickly build feature-rich and user-friendly interactive command line applications in Python

686 stars131 forksPythonMIT

At a glance

What is it?
cmd2 builds on the standard library's cmd.Cmd to add argument parsing, tab completion, history, scripting and output styling. It suits teams that want a REPL-style interface without assembling those pieces themselves, at the cost of adopting its command lifecycle.
Who is it for?
Adopt cmd2 if you are building an interactive shell or REPL in Python and want argument parsing, completion, history and scripting handled by the framework rather than by hand. Do not adopt it if you only need a one-shot argument parser, since argparse alone is smaller and has no command loop to learn.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The boilerplate cmd2 removes from a Python REPL

The standard library's cmd.Cmd gives you a command loop and methods named do_something. It does not give you argument parsing, generated help, tab completion, command history, output styling or scripting. Teams that start with cmd.Cmd typically end up writing those features themselves, and the result is a home-grown framework that only the original author understands. cmd2 targets that gap. The README describes it as a way to build command-line applications and REPLs by starting from a subclass of cmd.Cmd and adding commands while the framework handles "argument parsing, generated help, tab completion, command history, scripting, output styling, and much more." The intended audience is Python developers building internal tools, admin shells, or interactive interfaces that may need to grow into something scriptable. The README frames the growth path explicitly: a small internal tool can become an extensible, scriptable interface "without replacing the framework or writing the usual CLI boilerplate." That is a specific promise about scope, and it is the main reason to consider the project over assembling libraries yourself.

How a command method becomes a parsed, completable command

The mechanism is a class that inherits from cmd2.Cmd, with each command written as a method. In the README's quick-start example, the method is do_greet, decorated with @cmd2.with_annotated, and its parameters carry type annotations wrapped in Argument and Option objects imported from cmd2.annotated. The README states that this is Typer-style syntax: the decorator turns name into a positional argument and count into an option. That single annotation set drives validation, help text and tab completion for the options. The README also states that a single argparse parser definition drives validation, help and completion, and that commands can use argparse parsers for arguments and subcommands. So there are two visible paths into the same machinery: an argparse parser you define, or annotated parameters the decorator converts. The help output in the README shows the result, with a Usage line listing [-h] [--count COUNT] name. Larger applications are organized into CommandSets, which the README describes as independently testable and dynamically loadable, and the command lifecycle can be customized with hooks. Output is handled through helpers for normal output, errors, warnings and paging, and Rich tables and other styled objects can be rendered.

Installing cmd2 and running the quick-start application

Installation is a single pip command: pip install cmd2. The README's quick-start file is app.py, containing a class App(cmd2.Cmd) with one do_greet method, and the entry point is App().cmdloop() under a __main__ guard. Run it with python app.py. The example imports Annotated from typing and Argument and Option from cmd2.annotated, then uses @cmd2.with_annotated on the method. The method body calls self.poutput to print. Two documented interactions follow. Typing help greet produces a usage line of the form Usage: greet [-h] [--count COUNT] name. Typing greet --count 2 Ada prints the greeting twice. The README says the generated application also includes discoverable help, command history, aliases, macros, scripting, shell integration and other built-in commands, without listing their exact names beyond the shell command and its ! shortcut. That is the extent of what the supplied material confirms about the runtime surface. Anything beyond it, including the exact set of built-in commands and their flags, is documented on the Read the Docs site rather than in the README excerpt.

What the framework assumes about your application's shape

cmd2 is not a general argument parser. It is a command loop with a parser attached, and that shapes what it is good for. The README's own framing is interactive first: commands are methods, the loop is cmdloop, and the value comes from completion, history and help being present from day one. If your program is invoked once, parses argv and exits, the command loop is dead weight, and argparse by itself covers the parsing without the class hierarchy, the CommandSet model or the annotation decorator. The second assumption is that commands live in Python. The shell command and ! shortcut let users run OS commands, and Python scripts can run inside the application, but the command definitions themselves are methods on classes. A team whose interface is defined in a configuration file or generated at runtime will be working against the framework rather than with it. The third assumption is a willingness to adopt the command lifecycle and hooks. That is what makes CommandSets loadable and testable, and it is also what makes cmd2 a framework rather than a library you call from your own design.

Scripting, shell integration and where the boundary sits

The README separates two scripting paths. Shell scripting means passing the same commands users type interactively as command arguments or on standard input, so a cmd2 application can be automated from shell scripts. Python scripting means running Python scripts inside the application for loops, branching and complex control flow, with access to the application's commands and data. The README also documents redirecting command output to files or the clipboard, or piping it through one or more shell commands, and executing OS commands through the built-in shell command or its ! shortcut. This is the part of the design that justifies the framework's weight. A hand-rolled REPL usually has no answer for piping or redirection, and adding one after the fact means retrofitting every command. The trade-off is that these features are part of the command execution path, so commands that bypass that path, for example by writing directly to stdout instead of using the output helpers, will not participate in redirection or paging. The README points developers at helpers for normal output, errors, warnings and paging, which is a hint that using them is expected rather than optional.

The alternative: plain argparse plus prompt-toolkit

The obvious alternative is to assemble the pieces yourself: argparse for parsing, prompt-toolkit for the line editor and completion, and your own code for history and help. The difference in approach is ownership. With argparse you define parsers and call them; with cmd2 the parser is attached to a command method and the framework drives it, which is why one definition can feed validation, help and completion at once. If you already have a prompt-toolkit integration you like, or you need a command loop whose semantics differ from cmd2's, building on the lower-level libraries gives you control that cmd2's lifecycle does not. The cost is that you reimplement completion wiring, help generation from parsers, history persistence and scripting, which is precisely the list cmd2 advertises as handled. The README notes that cmd2 depends on prompt-toolkit for Emacs-style bindings, so the underlying editor is the same in both cases. The choice is whether you want the framework's opinions about commands, or you want to write the glue.

Licence, release cadence and upgrade cost

cmd2 is MIT-licensed, which permits commercial and closed-source use, modification and redistribution provided the licence notice is retained. That is a permissive arrangement, but it is not legal advice; check the LICENSE file in the repository and your own obligations before shipping. On maintenance, the repository is not archived and the last push is dated 2026-09-10. The release list shows 4.2.4 on 2026-09-08, 4.2.3 on 2026-09-02 and 4.2.2 on 2026-08-25, so patch releases arrive roughly weekly in this window. The README describes the package as pure Python with a small dependency footprint and support for Windows, macOS and Linux, which keeps installation and platform testing simple. The upgrade cost is not visible from the supplied material. The README does not state a deprecation policy, and the excerpt does not include a changelog or migration notes, so a team pinning to a 4.2.x release should read the release notes for each bump before moving. What can be said is that the cadence is fast enough that pinning is reasonable and that the Annotated command syntax shown in the quick start should be checked against the version you install.

Who should adopt cmd2 and what to check first

Adopt cmd2 if you are building an interactive shell, admin console or REPL in Python and you want argument parsing, generated help, tab completion, history and scripting without writing them. The quick-start example is short enough to evaluate in an afternoon, and the ability to grow the same application from an internal tool into a scriptable interface is the reason to accept the framework's command model. Do not adopt it if your program is a single-shot CLI, if your command surface is generated from configuration rather than defined as methods, or if you already have a completion and history layer you are happy with. Verify three things before committing: that the Annotated and with_annotated syntax in the README matches your installed version, since the README is written against the current documentation; how CommandSet loading and hooks fit your plugin requirements, because that is the extension point the README names; and how output redirection interacts with any command that writes to stdout directly, since the README's helpers for normal output, errors, warnings and paging are the documented path. The repository's tests workflow and documentation site are the places to confirm behaviour the README only summarizes.

Editorial conclusion

Adopt cmd2 if you are building an interactive shell or REPL in Python and want argument parsing, completion, history and scripting handled by the framework rather than by hand. Do not adopt it if you only need a one-shot argument parser, since argparse alone is smaller and has no command loop to learn. Before committing, verify that the Annotated command syntax shown in the README matches the version you install, and check how the CommandSet loading model fits your plugin story.

Official sources

  1. License: MIT
  2. Project website
  3. python-cmd2/cmd2 on GitHub
  4. README
  5. Releases
Community notes

Community notes