Kong, The Beautiful CLI Framework
There is a unique elegance to a CLI, and the joy of using one is surpassed only by the satisfaction of creating it. Today I'm going to talk about my favourite Go CLI library Kong by Alec Thomas.
I will preface this by saying that while Kong is my favourite CLI framework it hasn't always been my go-to.
I built many of my first CLIs using Cobra, inspired by Ricardo Gerardi’s book, Powerful Command-Line Applications in Go. An excellent read I still recommend.
For smaller-scale CLIs, I typically reach for urfave/cli or Peter Bourgon’s Flags First package.
Why Kong Wins
Declarative approach
Kong's use of Go structs and tags make translating a CLI from concept to code a fluid process.
I'll use the xair-cli package for my examples. Take the CLI struct which defines the root of the CLI. Embedded in it is a Config struct:
type CLI struct {
Config `embed:"" prefix:"" help:"The configuration for the CLI."`
}
That Config struct then uses tags to define:
- default values
- environment variables
- long and short versions of the flag
- help output
This is clean, declarative and easy to read.
Highly extensible
Being a well designed library it supports all kinds of plugins, here are two of my favourites:
- mango-kong for generating man pages.
- kong-completion for generating shell completion scripts.
Both integrate seamlessly with the library allowing a developer to extend their CLI by defining fields on the CLI struct:
type CLI struct {
Man mangokong.ManFlag `help:"Print man page."`
Completion kongcompletion.Completion `help:"Generate completions."`
}
Quick, simple and effective!
Supports all the goodies
Kong offers many features allowing developers to create powerful and intuitive interfaces to fit a variety of domains. These include:
- Custom validators
- Branching off positional arguments
- Define arguments with slices, maps and pointers
- Help customisation at a granular level
For example, the xair-cli package represents an 18 channel digital rack mixer composed of 18 input strips, 6 aux buses and a tonne of different control types (EQ, effects, gain sliders etc). When we look at the OSC spec we see addresses such as:
/ch/01/mix/01/level
/bus/1/eq/1/f
The pattern here is:
- select the channel type and index into it
- select the parameter type and index into it
- select the item you wish to control.
So ideally we want to represent these commands like so:
xair-cli strip <index> send <send-index> [<level>]
xair-cli bus <index> eq <band> freq [<freq>]
Since Kong allows us to branch off positional arguments we can achieve this by embedding structs tagged with arg into command structs:
type BusCmdGroup struct {
Index struct {
Index int `arg:""`
} `arg:"" help:"Control a specific bus by index."`
}
type BusEqCmdGroup struct {
Band struct {
Band *int `arg:""`
} `arg:"" help:"Control a specific EQ band of the bus."`
}
The final result is an interface that closely resembles the format expected in audio CLIs.
Conclusion
Kong is a beautiful, powerful and highly flexible library perfect for writing all kinds of CLIs. It's my personal favourite but I encourage you to explore the different libraries available, they all offer their own unique take.
Further notes:
- Historically, Kong has lacked robust shell completion support, but the recently released kong-completion plugin is compatible with the latest version. While this plugin works for bash, zsh, and fish, it does not currently extend to PowerShell.
Subscribe to this blog's RSS feed