commander: a Ruby framework for writing command line programs
The complete solution for Ruby command-line executables
At a glance
- What is it?
- Commander is an MIT licensed Ruby library that sits on top of OptionParser and HighLine to give you commands, global and per command options, generated help, a default command, aliases, paging and terminal interaction in a small API. It suits a Ruby developer who keeps writing a first command line tool and would rather not reimplement the option parsing, and it is a poor fit if you want a full argument parser with subcommand routing of your own design.
- Who is it for?
- commander suits a Ruby developer writing a single command line tool, or a small suite of them, who wants options, help output and terminal interaction without hand writing the plumbing, since the library supplies all three in an API you can read in a page.
- 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 last received commits 82 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A framework layered over OptionParser and HighLine
The project describes itself as the complete solution for Ruby command-line executables, and the README explains the position in one sentence: Commander bridges the gap between other terminal related libraries you know and love, OptionParser and HighLine, while providing many new features and an elegant API.
That framing tells you the architecture in one go. OptionParser does the option parsing, HighLine does the terminal interaction, and Commander is the layer that turns those into a program structure with commands, help output and a consistent style.
The feature list is what makes it concrete. It parses options using OptionParser, and it auto-populates a struct with the options, which the README describes as no more of the `|v| options[:recursive] = v` pattern. It auto-generates help documentation via pluggable help formatters, and it ships with two of them, Terminal and TerminalCompact. It supports a default command when none is present, and it separates global options from command level options. It handles multi-word command names, so `drupal module install MOD` rather than `drupal module_install MOD`, which is the kind of detail that only matters once someone using the tool complains about it. It supports command aliasing, where both switches and arguments can be used, and it has a highly customizable progress bar.
The audience is a Ruby developer who has written a script, turned it into a tool, and found themselves hand rolling the same option parsing, help text and confirmation prompts. The project is MIT licensed, the last push to the repository was on 2026-08-02, and the same day carries the v6.0.0 release tag.
The options struct is populated for you
The auto-population of the options struct is the feature that removes the most code from a typical program, and it is worth looking at how the API uses it.
In the classic style example, a command declares its options and the action block receives an options object.
command :bar do |c|
c.syntax = 'foobar bar [options]'
c.description = 'Display bar with optional prefix and suffix'
c.option '--prefix STRING', String, 'Adds a prefix to bar'
c.option '--suffix STRING', String, 'Adds a suffix to bar'
c.action do |args, options|
options.default :prefix => '(', :suffix => ')'
say "#{options.prefix}bar#{options.suffix}"
end
endThe `c.option` call is the OptionParser declaration, with the type and the description, and the options arrive in the action block already parsed and named.
The `options.default` call is a Commander addition, documented under Option Defaults. The options struct passed to the action provides a default method, allowing you to set defaults in a clean manner for options which have not been set. The README's own example sets a default interval of 2 and a default timeout of 60, with a line continuation in the source that is easy to misread if you have not seen the multi argument form before.
The output of the example shows the effect.
$ foobar bar
# => (bar)
$ foobar bar --suffix '}' --prefix '{'
# => {bar}The defaults apply when the option is absent and the passed values win when they are present, which is the behaviour you want from a command line tool and the reason the defaults live on the options object rather than in the action body.
Three styles for the same program
Commander supports three ways of writing a program, and the README gives an example of each, which is the fastest way to understand the API.
The classic style imports the methods into the global namespace with require 'commander/import', then declares the program and its commands at the top level.
require 'commander/import'
# :name is optional, otherwise uses the basename of this executable
program :name, 'Foo Bar'
program :version, '1.0.0'
program :description, 'Stupid command that prints foo or bar.'The modular style requires 'commander' instead, and puts everything inside a class that includes Commander::Methods, ending with a run! call. The README carries a note about this that is easy to get wrong: make sure to use require 'commander' rather than require 'commander/import', otherwise Commander methods will still be imported into the global namespace. That is the whole reason the two require paths exist, and the difference is a namespace decision rather than a convenience one.
The block style is the smallest of the three, configuring the program inside Commander.configure do ... end with the commands added elsewhere.
require 'commander'
Commander.configure do
program :name, 'Foo Bar'
program :version, '1.0.0'
program :description, 'Stupid command that prints foo or bar.'
endFor a library that other people will load, the modular style is the one that keeps the global namespace clean, and the note in the README is the reason to pay attention to which require you use.
HighLine is imported for you, and adds the interaction you would otherwise write
The HighLine gem is imported into the global scope, and the README says so plainly: as mentioned above, the highline gem is imported into the global scope.
The examples show what that buys. Asking for a password with the characters masked, asking for a password with no echo at all, asking the user to agree to something with a yes or no prompt, asking for a name, asking for a description on a new line, and asking for a value that gets parsed by a class, so a birthday through Date.parse or an age through Integer.
# Ask for password masked with '*' character
ask("Password: ") { |q| q.echo = "*" }
# Ask if the user agrees (yes or no)
agree("Do something?")
# Calls Date#parse to parse the date string passed
ask("Birthday? ", Date)
# Ensures Integer is within the range specified
ask("Age? ", Integer) { |q| q.in = 0..105 }The last one is worth pausing on, because it is the kind of validation that is easy to skip and annoying to get wrong. Passing Integer as the expected type and constraining the acceptable range means the prompt itself will not accept a value outside 0 to 105, so the program never has to check the age afterwards.
The scope of the import is worth being explicit about, because it is a design decision rather than an oversight. A command line tool that asks questions benefits from having ask, agree and choose available everywhere, and the cost is that those names are in your program's top level namespace. For a standalone executable that is a good trade. For a library that loads Commander into someone else's process, it is a real constraint, and the modular style exists partly to address it.
Commander adds paging, progress, editors and speech on top of HighLine
Beyond the HighLine basics, the README lists a set of additions that Commander makes to simplify common tasks, and this is where the library earns its place beyond option parsing.
There is a password helper, and a variant that takes a message and a mask character. There are typed askers, ask_for_array and ask_for_date, for a list of names and for a date. There is a progress bar, Commander::UI::ProgressBar, used by iterating over a list of URIs and passing each to the block.
# Simple progress bar (Commander::UI::ProgressBar)
uris = %w[
http://vision-media.ca
http://google.com
http://yahoo.com
]
progress uris do |uri|
res = open uri
# Do something with response
endThere is a log method that writes an action and a path to stdout, and enable_paging, which turns on paging of output after that point, which the features list describes as sexy paging for long bodies of text.
There is ask_editor, which opens the editor named by the EDITOR environment variable or whichever is available, with TextMate, vim, vi, emacs, nano and pico listed, and it can take initial text or a preferred editor.
There is choose, which selects from an array of elements, and an io method that alters IO for the duration of a block and resets stdin and stdout afterwards, which is the way to capture what a script printed.
And there is a group of macOS specific helpers: speak for text to speech, with an optional voice and rate, applescript to run arbitrary AppleScript, and converse, which talks to a speech recognition server and returns a symbol keyed hash, in the example with cookies, yes, no and maybe cases.
The commander executable scaffolds both styles
There is a generator, and the README points at it in the features list as the use of the commander executable to initialize a commander driven program.
$ gem install commander$ commander init yourfile.rb
$ commander init --modular yourfile.rbThe first form produces the classic style template, and the modular flag produces the modular style template. So the choice between the two styles is made at generation time, and the scaffold lands in a file you name.
The project layout follows the standard Ruby gem shape, with a lib directory for the library, a bin directory for the executables including the commander generator itself, a spec directory with the RSpec configuration in the .rspec file, a commander.gemspec for packaging, a Gemfile, a Rakefile, a .ruby-version file, and RuboCop configuration in .rubocop.yml with a .rubocop_todo.yml alongside it. There is also a History.rdoc changelog.
One entry in the features list deserves a note for anyone who has shipped a command line tool before. Multi-word command name support, such as `drupal module install MOD` rather than `drupal module_install MOD`, and command aliasing where both switches and arguments can be used, are the two features that most change how a tool feels to use. The README calls aliasing very powerful, and the alias_command method is the entry point, with an example that creates a command named install gem as a single aliased name rather than two nested commands.
Editorial conclusion
commander suits a Ruby developer writing a single command line tool, or a small suite of them, who wants options, help output and terminal interaction without hand writing the plumbing, since the library supplies all three in an API you can read in a page. It does not suit a project that needs a different parsing model, since Commander's structure is a command tree with global and per command options and a default command, and it does not suit a team that would rather keep dependencies to a minimum, because HighLine is imported for you and the interaction helpers lean on it. Before you adopt it, confirm your Ruby version is 3.1 or later, since that is the stated floor, and note that the current release is v6.0.0 dated 2026-08-02, which is a major version and therefore a point at which the API can change under you.
Frequently asked questions
What is the commander Ruby library?
Commander is an MIT licensed library described as the complete solution for Ruby command-line executables. It bridges OptionParser and HighLine, and adds commands, global and command level options, auto-generated help, a default command, aliasing, paging and terminal interaction helpers.
How do I install commander and generate a new program?
Run gem install commander, then commander init yourfile.rb for the classic style template, or commander init --modular yourfile.rb for the modular style template. The README requires Ruby 3.1 or later, tested through Ruby 4.0.
What is the difference between require 'commander' and require 'commander/import'?
The modular style uses require 'commander' and includes Commander::Methods in your class, while require 'commander/import' puts the Commander methods into the global namespace. The README warns that using the import version in the modular style would still import those methods globally.
How do I set default values for options in commander?
The options struct passed to the action block provides a default method, which sets defaults for options that have not been given, for example options.default :interval => 2, :timeout => 60. Passed values always win over the defaults.
Does commander support multi-word commands and aliases?
Yes. The features list names multi-word command name support such as drupal module install MOD rather than drupal module_install MOD, and command aliasing where both switches and arguments can be used, created through the alias_command method.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/commander-rb-commander)Was this useful?