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:

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:

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:

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:

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."`
}

Repeating this pattern:

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:

Subscribe to this blog's RSS feed