Skip to content

Latest commit

 

History

History
146 lines (112 loc) · 12.8 KB

File metadata and controls

146 lines (112 loc) · 12.8 KB
id go-cli-frameworks
title go-cli-frameworks
type research
status accepted
created 2026-05-27
updated 2026-05-27
tags
go
cli
frameworks
comparison

go-cli-frameworks

A decision guide for choosing Go CLI toolkits, optimized for four axes:

  1. Aesthetic / professional UX — styled help, color, layout, interactive prompts.
  2. Human discoverability--help, completions, man pages, intuitive command trees.
  3. AI-discoverability — machine-readable schema, --output json, deterministic errors, runtime introspection that an agent can use without a tutorial.
  4. Schema-driven consistency — a single declarative source of truth (typed Go structs / tags) that enforces semantic (what commands mean), syntactic (flag/arg grammar), and stylistic (help text, formatting) consistency as the surface area grows.

Note on terminology: in Go these split into two layers — command/flag parsers (Cobra, Kong, urfave) and the UX/render layer (the Charm suite). The strongest products combine one of each. Recommendations and the stack section below reflect that.


TL;DR — Recommended stacks

Goal Recommended stack Why
Best all-around, growing product Cobra + Fang + Charm (Huh/Lipgloss) + Viper, plus a schema/--output json convention Largest ecosystem & human discoverability (Cobra), batteries-included aesthetics (Fang), interactive UX (Huh), config layering (Viper). Add JSON output + schema export for AI.
Maximum schema-driven consistency Kong (define the whole CLI as a typed struct) + Charm for rendering One typed struct is the single source of truth → semantic/syntactic/stylistic consistency is enforced by the type system. Easiest to reflect into a JSON schema for agents.
Want Cobra's ecosystem and a struct-first schema structcli (declares structs → emits Cobra under the hood) + Fang Keeps Cobra's completions/docs/ecosystem while getting Kong-style declarative consistency.
Minimal, zero-dependency, simple urfave/cli v3 Tiny dependency surface, context-aware, dynamic completion, good defaults.

If you must pick one framework that maximizes all four axes for a product expected to grow: Cobra + Fang for human/aesthetic/ecosystem, layered with a declarative schema (either structcli on top of Cobra, or migrate the parser to Kong) and a hard convention of --output json + a schema subcommand for AI-discoverability.


Top 10 — Features & functionality

# Framework Model Subcommands Schema-driven Completions Help / docs gen Config / env Notable users
1 Cobra (spf13/cobra) Imperative builder Deep nesting ✗ (code-defined) bash/zsh/fish/PowerShell + __complete protocol Auto help, man pages, markdown/yaml docs via Viper (files, env, flags) kubectl, gh, Hugo, Docker, Helm, GitHub CLI
2 Fang (charmbracelet/fang) Wrapper over Cobra inherits Cobra inherits Cobra completion cmd Styled help + errors, man via mango, auto --version inherits Charm-ecosystem tools
3 Charm suite (Bubble Tea, Lipgloss, Bubbles, Huh, Glamour, Gum) UX/render layer (not a parser) n/a n/a n/a n/a (renders anything) n/a Charm tools, gh extensions, many TUIs
4 Kong (alecthomas/kong) Declarative struct tags Arbitrary nesting (cmd tag) ✓ (struct is the schema) via kongplete Auto from struct tags env tags, defaults, resolvers Many modern Go CLIs; supersedes Kingpin
5 urfave/cli v3 (urfave/cli) Declarative-lite (slices/structs) Yes, aliases + prefix match partial Dynamic, multi-shell Auto help, cli-docs for md/man env + file lookups Drone, many OSS tools
6 structcli Declarative struct → Cobra inherits Cobra ✓ (struct-first) inherits Cobra inherits Cobra struct-driven Newer / smaller adoption
7 goopt (napalu/goopt) Declarative struct tags Hierarchical ✓ shell completion Auto + i18n validation tags Newer / niche
8 go-flags (jessevdk/go-flags) Declarative struct tags Yes basic Auto from tags env vars, defaults Mature, widely embedded
9 go-arg (alexflint/go-arg) Declarative struct tags Yes ✓ (minimal) Auto, minimal env vars, defaults Lightweight tools
10 mitchellh/cli Imperative, interface-based Yes bash Manual-ish needs separate flag lib Terraform, Vault, Consul, Packer, Nomad

Honorable mentions: alecthomas/kingpin (fluent builder; now in maintenance, superseded by Kong) · peterbourgon/ff + ffcli (minimal, stdlib-flag based, great config/env layering) · jawher/mow.cli (spec-string DSL, used by Financial Times) · mkideal/cli (struct-tag) · stdlib flag + spf13/pflag (POSIX baseline).


Top 10 — Pros & cons

Framework Pros Cons
Cobra De-facto standard, huge ecosystem; best human discoverability (completions, man pages, docs gen); battle-tested at scale; the __complete protocol is a de-facto runtime introspection API. Imperative/boilerplate-heavy; not schema-driven (consistency relies on discipline); plain default styling; larger binaries.
Fang Instantly makes Cobra look professional (styled help/errors, themes); auto --version, man pages, completions; minimal adoption cost over Cobra. Explicitly experimental, evolving API; thin layer (no parsing/schema changes); ties you to the Charm look.
Charm suite Best-in-class aesthetics; Huh = polished interactive forms/prompts; Lipgloss = CSS-like styling; Glamour = rich markdown; composable. Not a CLI parser — you still need Cobra/Kong; interactive UX can fight scriptability/AI use unless gated behind a TTY check.
Kong Cleanest schema-driven model — one typed struct enforces semantic/syntactic/stylistic consistency; trivial to reflect into JSON schema for agents; hooks (BeforeApply/AfterApply), enums, resolvers, env. Smaller ecosystem than Cobra; completions need kongplete; styling is plain (pair with Charm); less tutorial content.
urfave/cli v3 Simple, fast, zero deps; context.Context-aware (cancellation/timeouts); dynamic completion; env/file flag lookups; mutually-exclusive flags. Less rigid schema enforcement than Kong; smaller feature surface than Cobra; v2→v3 migration churn.
structcli Kong-style declarative structs with Cobra's ecosystem underneath (completions/docs); removes Cobra boilerplate. Young / low adoption; depends on Cobra's release cadence; smaller community.
goopt Declarative, hierarchical; built-in i18n, validation, completion; user-friendly defaults. Niche adoption; smaller ecosystem and docs; less production track record.
go-flags Mature, stable, struct-tag schema; small binaries; good env/default support. Lower activity; weaker completion/docs story; styling is plain.
go-arg Dead simple struct-based parsing; minimal API; env + defaults. No completions; minimal feature set; not for large command trees.
mitchellh/cli Proven at HashiCorp scale; clean command interface; predictable. Imperative; needs a separate flag library; largest binary in comparisons; effectively maintenance-mode.

Scoring against your four axes

Scores are relative (●●●●● best). Parser-only tools score the UX axis low by design — pair them with the Charm suite.

Framework Aesthetic UX Human discoverability AI-discoverability Schema-driven consistency
Cobra ●●○○○ ●●●●● ●●●●○ ●●○○○
Cobra + Fang ●●●●● ●●●●● ●●●●○ ●●○○○
Kong ●●○○○ ●●●○○ ●●●●● ●●●●●
Kong + Charm ●●●●● ●●●○○ ●●●●● ●●●●●
urfave/cli v3 ●●○○○ ●●●●○ ●●●○○ ●●●○○
structcli + Fang ●●●●● ●●●●● ●●●●○ ●●●●○
goopt ●●○○○ ●●●○○ ●●●○○ ●●●●○
go-flags ●○○○○ ●●○○○ ●●●○○ ●●●●○
go-arg ●○○○○ ●●○○○ ●●○○○ ●●●○○
mitchellh/cli ●○○○○ ●●●○○ ●●○○○ ●●○○○
Charm suite (UX layer) ●●●●● n/a n/a n/a

Why "schema-driven" matters for consistency

A declarative model (Kong, structcli, goopt, go-flags) makes the Go type the single source of truth:

  • Semantic consistency — command meaning/grouping lives in the struct hierarchy, not scattered across AddCommand calls.
  • Syntactic consistency — flag grammar, required/optional, enums, defaults, env binding are uniform tags; you can't accidentally invent a one-off flag style.
  • Stylistic consistency — help text, ordering, and formatting derive from one renderer, so new commands inherit the look for free.

Imperative frameworks (Cobra, mitchellh/cli) can reach the same place, but only via team discipline and linters — there's no compiler forcing it.

// Kong: the struct IS the contract. New subcommands inherit grammar + help style.
type CLI struct {
    Output  string `enum:"text,json" default:"text" help:"Output format."`
    Verbose bool   `short:"v" help:"Enable verbose logging."`

    Deploy struct {
        Env   string `arg:"" enum:"dev,staging,prod" help:"Target environment."`
        Force bool   `help:"Skip confirmation."`
    } `cmd:"" help:"Deploy a release."`
}

Designing for AI-discoverability (framework-agnostic)

The framework choice matters less than these conventions — but declarative parsers make them nearly free:

  1. --output json (and stable schema) — table-stakes for agents. Keep human formatting for TTYs, switch to JSON when piped or --output json is set.
  2. A schema / --describe subcommand — emit the command tree, flags, types, and enums as JSON. With Kong/structcli/go-flags you can reflect the struct directly; with Cobra, walk the command tree.
  3. Deterministic errors + exit codes — machine-parseable error objects, not just colored prose.
  4. Good --help text everywhere — agents read help at runtime; Cobra's hidden __complete protocol already acts as a runtime discovery API.
  5. Gate interactivity behind a TTY check — never block on an interactive Huh prompt when stdin isn't a terminal; fall back to flags/errors so agents (and scripts) don't hang.

This is the crux of the 2026 "CLI as the new API/MCP" discussion: a CLI that is self-describing, JSON-capable, and non-interactive-by-default is usable by agents without a separate MCP server, while staying beautiful for humans.


Sources