cli
cli is a small helper package for building command-line interfaces in Go.
It wraps the standard flag package with a consistent model for:
- registering flags and positional arguments
- reading values from environment variables
- generating structured, wrapped usage text
- documenting env-only inputs
The API is intentionally small and dependency-free so it can be embedded in
libraries or applications without heavy setup.
Install
go get zuern.dev/cli
Quick start
package main
import (
"flag"
"fmt"
"log"
"os"
"zuern.dev/cli"
)
type Config struct {
Port int
Env string
Path string
}
func main() {
var cfg Config
flagSet := flag.NewFlagSet("example", flag.ExitOnError)
c := cli.New(
"example",
"Example program that shows flags, env vars, and args.",
"example [options] <path>",
"v1.0.0",
[]cli.Opt{
{Name: "port", Env: "EXAMPLE_PORT", Desc: "Port to listen on", Ptr: &cfg.Port},
{Name: "env", Env: "EXAMPLE_ENV", Desc: "Runtime environment", Ptr: &cfg.Env},
},
[]cli.Arg{
{Name: "path", Desc: "Path to process", Ptr: &cfg.Path},
},
cli.UseFlagSet(flagSet),
)
if err := c.ReadEnv(); err != nil {
log.Fatal(err)
}
if err := c.ParseArgs(os.Args[1:]); err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", cfg)
}
Usage output
CLI.Usage() returns a fully formatted usage string that includes your
description, usage line, args, options, and environment variables. The output
is line-wrapped at 80 columns for readability in standard terminals.
To use the default flag package behavior, rely on Create / Parse or set
flag.Usage = cli.Usage() yourself. When you use UseFlagSet, the usage
function is set on that FlagSet.
Options
Options are modeled with cli.Opt:
Name registers a flag (empty name means env-only)
Env specifies the environment variable to read
Ptr points to the destination value
Desc and TypeName control usage text
Supported pointer targets are *string, *bool, *int, *time.Duration, or
anything that implements flag.Value.
DocumentationOnly can be used to include an env var in usage without parsing
it (useful for external libraries).
Arguments
Positional arguments are modeled with cli.Arg and are read in order after
flag parsing. Missing args return cli.ErrMissingArgs from ParseArgs.
Environment variables and .env
Call ReadEnv to load values from environment variables into the same pointers
as your flags.
To optionally load a local .env file before parsing, call:
if err := cli.ApplyEnvFileIfExists(); err != nil {
log.Fatal(err)
}
The .env parser ignores blank lines, # or // comments, and lines without
key=value format.
Error handling
There are two common flows:
Create / New + Parse uses the global flag package and exits the
program on parse or missing-args errors.
New + UseFlagSet + ParseArgs returns errors for your application to
handle and avoids os.Exit.
Use CreateCLI for the short path that does NewCLI, ReadEnv, and Parse
in one call (note this still exits on missing args because it calls Parse).
Example
See the runnable example in example/:
cd example
go run . -h