Define your CLI once.
Usage is a toolkit for building command-line tools. Define your CLI's commands, flags, and args once in a KDL spec — get argument parsing, shell completions, --help, docs, and manpages from that one definition. Experimental reference frameworks for Rust and Go build your CLI from the spec, with Python and JavaScript planned.
Frameworks
Derive your CLI from Rust types — parsing, help, and completions generated from the usage spec. Experimental: APIs may change between releases.
Build Go CLIs on the usage spec, with parsing behavior verified against the same conformance corpus as the Rust implementation. Experimental: APIs may change between releases.
Spec & tooling
Tab completions for bash, zsh, fish, PowerShell, and nushell, generated from the spec.
--help output, markdown docs, and manpages, all generated from the same spec.
Declare a script's interface in a USAGE comment and get arg parsing, validation, and completions.
Define your CLI once in KDL. Completions, docs, and parsers are all generated from it.
The standalone tool for generating completions, docs, and parsing from any spec file.
name "mycli"
flag "-v --verbose" help="Enable verbose output"
arg "<file>" help="File to process"
cmd "deploy" { flag "--env <env>" }Benchmarks
What parsing mise use -g node@20 costs each framework, against a shadow of mise's CLI: 211 commands, 711 flags. Every shadow is generated from the same spec by the same traversal, so what differs is the parser rather than one of them being written more carefully.
wall time, one warmed parse How this is measured In-process and warmed — the fastest of many short rounds, since a fresh process cannot resolve a 200ns parse. Minima and their ratios drift a few percent between runs and machines, hence the ~. Instructions for one cold parse, which do not drift: 4,155 · 6,295 · 5.89M · 21.9M, agreeing across two machines to 0.15%. For scale, starting a process costs ~1ms, so the first two bars are under anything a user feels.
clap and bpaf build a parser before they can use one Where their time goes Most of clap's is constructing and validating its command tree. bpaf's is larger because it assembles a combinator tree per run as well, which reusing the parser across parses only halves. . Heap allocations for a bare parse: zero, against clap's 6,280. argh and bpaf also express less Missing from the argh and bpaf shadows Aliases, hidden commands, global flags, and a positional beside a subcommand — the generator drops them, counts them, and prints the count when it runs. .
wall time, one cold parse How this is measured Whole-process, with the ~0.95ms of Go runtime startup a do-nothing process costs subtracted — approximate, and the reason the Rust card is timed in-process instead.
Instructions for the same parse: ~2.7k vs cobra's 2.0M, urfave/cli's 5.6M, kong's 57.9M.
Methodology and raw numbers: go/README.md · tasks/perf-shadow.sh · time-sweep.rs