Skip to content

Go CLI frameworks: Cobra, urfave/cli and where Rungrad fits

By Vincent Schmalbach · Updated

The Asana CLI example is another open source project by Rungrad's maintainer.

When you build a command-line tool in Go, a CLI framework helps you define commands, flags, arguments, and help output. Cobra and urfave/cli organize commands, flags, arguments, and help output in different ways. Rungrad adds conventions for CLI behavior to Cobra, along with tools to generate a CLI and check whether it follows those conventions.

Choose Cobra when you want a hierarchical command structure and generated help. Choose urfave/cli when its declarative approach to commands and flags fits your design. Consider Rungrad when you want a Cobra-based Go CLI to follow consistent behavior rules, or when you want to check a CLI in any language against Rungrad’s language-neutral specification.

How Cobra and urfave/cli structure commands

Cobra organizes a CLI as a tree of commands. A root command can contain subcommands, which can contain further subcommands. For example, tool widget list and tool widget delete can share a widget parent command. Cobra creates help text for the command tree, handles flags, and provides command checks. Its cobra-cli tool can also create the initial files for a CLI. See the Cobra package overview and Cobra scaffolding example.

urfave/cli also lets you define commands, flags, and actions. It emphasizes declarative configuration, where you describe those parts, and lets you combine them. Its official project documentation describes shell completion, which lets shells suggest commands and flags, for Bash, Zsh, Fish, and PowerShell. It also supports combined short flags, where -abc groups several one-letter flags. The documentation says it has no dependencies beyond Go’s standard library.

Choose When it fits
Cobra You want a nested command tree, generated help, and Cobra’s surrounding tooling.
urfave/cli You prefer its declarative command and flag structure and its composition model.
Cobra with Rungrad You want Cobra’s command structure plus conventions and checks for CLI behavior.

Neither framework determines every user-facing behavior. You still decide how commands format output, handle destructive actions, report errors, or preview changes.

Where Rungrad fits

Rungrad is a Go framework, CLI scaffolder, and conformance scorer. A conformance scorer runs a CLI and checks what it does and outputs against a set of rules. Rungrad builds on Cobra, so it adds conventions to a Cobra-based CLI rather than replacing Cobra or offering a separate command framework.

The conventions give people readable text output and programs --json output. They send error messages to standard error (the CLI’s separate error-output stream) and define predictable exit codes and help examples. For mutations, they provide --dry-run previews; destructive actions get confirmations. The generated CLI also includes a hidden machine manifest. Optional skill files in the repository describe the generated tool.

Rungrad also defines rungrad-spec/1, a behavior specification that CLIs written in any language can follow. The Go framework is specific to Go, but the specification and scorer are separate: rungrad score runs a configured executable and checks its behavior. If a command case is not configured, the scorer reports it as not applicable. That result does not count as a pass, so read the applicable-rule count alongside any passing-rule count.

The scorer does not provide a security certification. Rungrad also does not supply an MCP server or an agent runtime. Its scope is CLI behavior, scaffolding, and conformance checks.

Try the Rungrad starter

Use a Go version compatible with Rungrad. Install the CLI tool, generate a starter, and exercise its commands:

go install github.com/vincentsch/rungrad/cmd/[email protected]

rungrad new hello
cd hello
go mod tidy
go test ./...
go build -o hello .
./hello widget list --json
./hello widget delete alpha --dry-run
rungrad score ./hello --read "widget list" --mutate "widget create demo" --destructive "widget delete alpha" --update

The generated starter uses in-memory widget fixtures. Its delete preview prints DRY RUN: would DELETE /widgets/alpha, then reports that no changes were made. The path in that message looks like an HTTP API path, but it is only a preview. The starter does not contact an external API.

To add Rungrad’s Go framework to an existing module, use go get github.com/vincentsch/[email protected]. Cobra projects can adopt Rungrad features incrementally; see the Cobra migration documentation. Rungrad also documents getting started, building a CLI, and scoring conformance.

A public adopter, Asana CLI, demonstrates Rungrad in a real Go CLI. The project’s source repository is available for inspection.

Choosing a fit

Start with Cobra if your CLI needs nested commands and you want its established command-generation approach. Start with urfave/cli if its command and flag model better matches how you want to compose the CLI. Before choosing one, compare how each framework handles a small command, its help, and its error output.

Add Rungrad when you want more than a command tree: its behavior rules give you a way to standardize output, previews, confirmations, and exit behavior, while its scorer checks configured cases. If your CLI is written in another language, use the specification and scorer independently of the Go framework. For a Cobra CLI, try Rungrad on one command first and review which cases the scorer marks as applicable before expanding adoption.