A reusable Go library that plugs into existing CLI frameworks to add helpers, shell completions, and more polished help output.
| Package | Description |
|---|---|
ansi |
Terminal-aware ANSI output |
cli/cobra |
Cobra framework adapters |
cli/kong |
Kong framework adapters |
cli/urfave |
urfave/cli framework adapters |
complete |
Shell completion generation (bash, zsh, fish) |
help |
Structured help rendering with themed output |
human |
Human-friendly formatting |
shell |
Shell detection |
terminal |
Terminal detection |
theme |
Configurable theme (via lipgloss) |
go get github.com/gechr/clib
Auto-detect terminal support, or force/disable ANSI output:
w := ansi.Auto() // detect from os.Stdout
w := ansi.Auto(os.Stdout, os.Stderr) // all must be terminals
w := ansi.Force() // always emit ANSI
w := ansi.Never() // plain text only
w := ansi.New(ansi.WithTerminal(true)) // manual configuration
w.Hyperlink("https://example.com", "click here") // OSC 8 hyperlink
// Control how hyperlinks render in non-terminal output:
w = ansi.New(ansi.WithHyperlinkFallback(ansi.HyperlinkFallbackMarkdown))
// HyperlinkFallbackExpanded (default) β "text (url)"
// HyperlinkFallbackMarkdown β "[text](url)"
// HyperlinkFallbackText β "text"
// HyperlinkFallbackURL β "url"if terminal.Is(os.Stdout) {
// stdout is a terminal
}
width := terminal.Width(os.Stdout) // column count, 0 if not a terminalCreate a theme with defaults or customize individual styles:
// Use defaults.
th := theme.Default()
// Or customize with options.
th := theme.Default().With(
theme.WithRed(lipgloss.NewStyle().Foreground(lipgloss.Color("9"))),
theme.WithEntityColors([]lipgloss.Color{"208", "51", "226"}),
)Build structured help output. Content blocks implement the help.Content
interface: FlagGroup, Args, Usage, Text, Examples, CommandGroup,
and nested *Section.
hr := help.NewRenderer(th)
sections := []help.Section{
{Title: "Flags", Content: []help.Content{
help.FlagGroup{
{Short: "q", Long: "query", Placeholder: "text", Desc: "Filter results by query"},
{
Short: "f",
Long: "format",
Placeholder: "format",
Desc: "Output format",
Enum: []string{"table", "json", "yaml"},
EnumDefault: "table",
},
},
}},
{Title: "Examples", Content: []help.Content{
help.Examples{
{Comment: "List items in JSON format", Command: "catalog list --format json"},
},
}},
}
if err := hr.Render(os.Stdout, sections); err != nil {
return err
}Flag fields use bare names - the renderer adds dashes (-/--) and angle
brackets (</>) automatically. Sections can be nested by including a
*help.Section as content.
Each adapter provides the same core capabilities for its framework:
Extend (or struct tags for Kong), FlagMeta, Sections/HelpFunc, NewCompletion,
and CSVFlag.
Annotate your CLI struct with Kong-style tags and a clib:"..." tag for
clib-specific metadata (grouping, descriptions, completions, placeholders):
type CLI struct {
clib.CompletionFlags
Query string `name:"query" short:"q" help:"Filter results by query" clib:"group='Filters',terse='Query',complete='predictor=query',order=keep"`
Fields clib.CSVFlag `name:"fields" help:"Fields to show" clib:"complete='predictor=field,comma'"`
Format string `name:"format" short:"f" help:"Output format" default:"table" enum:"table,json,yaml"`
}
flags := clib.Reflect(&CLI{})
gen := complete.NewGenerator("catalog").FromFlags(flags)
gen.Install("fish", false)Integrate with Kong's help system using HelpPrinter or HelpPrinterFunc:
r := help.NewRenderer(th)
k := konglib.Must(&cli,
konglib.Help(clib.HelpPrinterFunc(r, clib.NodeSectionsFunc())),
)Use Extend to attach clib metadata to pflag flags:
f := root.Flags()
f.StringP("query", "q", "", "Filter results by query")
f.StringP("format", "f", "table", "Output format")
cobraFields := &cobracli.CSVFlag{}
f.Var(cobraFields, "fields", "Fields to show")
cobracli.Extend(f.Lookup("query"), cobracli.FlagExtra{
Group: "Filters", Placeholder: "text", Complete: "predictor=query", Order: complete.OrderKeep,
})
cobracli.Extend(f.Lookup("format"), cobracli.FlagExtra{
Group: "Output", Placeholder: "format", Enum: []string{"table", "json", "yaml"}, EnumDefault: "table",
})
cobracli.Extend(f.Lookup("fields"), cobracli.FlagExtra{
Complete: "predictor=field,comma",
})
// Auto-grouped help using extras.
root.SetHelpFunc(cobracli.HelpFunc(r, cobracli.Sections))
// Completion flags (hidden).
comp := cobracli.NewCompletion(root)
gen := complete.NewGenerator("catalog").FromFlags(cobracli.FlagMeta(root))
handled, err := comp.Handle(gen, nil)Use Extend to attach clib metadata to urfave/cli flags:
queryFlag := &clilib.StringFlag{Name: "query", Aliases: []string{"q"}, Usage: "Filter results by query"}
formatFlag := &clilib.StringFlag{Name: "format", Aliases: []string{"f"}, Usage: "Output format", Value: "table"}
fieldsFlag := &clilib.GenericFlag{Name: "fields", Usage: "Fields to show", Value: &cliurfave.CSVFlag{}}
cliurfave.Extend(queryFlag, cliurfave.FlagExtra{
Group: "Filters", Placeholder: "text", Complete: "predictor=query", Order: complete.OrderKeep,
})
cliurfave.Extend(formatFlag, cliurfave.FlagExtra{
Group: "Output", Placeholder: "format", Enum: []string{"table", "json", "yaml"}, EnumDefault: "table",
})
cliurfave.Extend(fieldsFlag, cliurfave.FlagExtra{
Complete: "predictor=field,comma",
})
// Custom help using clib themed renderer.
clilib.HelpPrinter = cliurfave.HelpPrinter(r, cliurfave.Sections)
// Completion flags (hidden).
comp := cliurfave.NewCompletion(root)
gen := complete.NewGenerator("catalog").FromFlags(cliurfave.FlagMeta(cmd))
handled, err := comp.Handle(gen, nil)The complete package generates shell completion scripts from flag
metadata. The complete tag (Kong) or FlagExtra.Complete field (Cobra/urfave)
controls completion behavior:
predictor=<name>- dynamic completion via<app> --@complete=<name>comma- comma-separated multi-value modevalues=<space-separated>- static completion values
The terse key provides a very short description for completions (falls back to help).
Use order=keep (Kong) or Order: complete.OrderKeep (Cobra/urfave) to preserve fish completion order for a flag by emitting complete -k.
Use order=shell or Order: complete.OrderShell to force the shell's normal ordering for a flag.
Use complete.WithOrder(complete.OrderKeep) to make keep-order the generator default.
styled := th.RenderTimeAgo(someTime, true) // colored based on thresholds
plain := human.FormatTimeAgo(someTime) // "3 hours ago"
compact := human.FormatTimeAgoCompact(someTime) // "3h ago"human.ContractHome("/Users/alice/Documents") // "~/Documents"// Styled enum with shortcut letters: [text, json, yaml]
th.FmtEnum([]theme.EnumValue{
{Name: "text", Bold: "t"},
{Name: "json", Bold: "j"},
{Name: "yaml", Bold: "y"},
})
// With default annotation: [text, json, yaml] (default: text)
th.FmtEnumDefault("text", []theme.EnumValue{
{Name: "text", Bold: "t"},
{Name: "json", Bold: "j"},
{Name: "yaml", Bold: "y"},
})
// Dim default/note annotations for flag descriptions.
th.DimDefault("30") // (default: 30)
th.DimNote("required") // (required)Render short markdown strings for inline display with themed code spans:
th.RenderMarkdown("Use `--verbose` for debug output")shell := shell.Detect() // COMPLETE_SHELL env -> parent process -> SHELL envWorking examples for each framework adapter are in the examples/ directory: