Documentation
¶
Overview ¶
Package flagkit provides reusable, embeddable flag structs that standardize common CLI flag declarations for use with structcli.
Each type encapsulates a single flag with an opinionated name, type, default, and description matching industry conventions. This gives CLIs a consistent declaration surface. Agents and scripts can rely on --follow, --output, --timeout, etc. having predictable names and types across tools.
flagkit standardizes flag declarations, not behavioral semantics. How a command interprets --quiet or --dry-run is up to the consumer. The value is in the shared vocabulary: consistent names, types, and defaults that AI agents can recognize across CLIs built with structcli.
Design Principles ¶
- One struct per concern for maximum composability
- Sensible, agent-friendly defaults (e.g., no auto-tailing, finite timeouts)
- Standard flag names matching industry conventions
- Works with all structcli features: env vars, config files, JSON Schema, shell completion, and doc generation
Taxonomy ¶
Type Flag Default Status ───────────── ──────────── ─────── ──────── Follow --follow/-f false available LogLevel --log-level info available ZapLogLevel --log-level info available SlogLogLevel --log-level info available Output --output/-o text available Verbose --verbose/-v 0 available DryRun --dry-run false available Timeout --timeout 30s available Quiet --quiet/-q false available
Composition ¶
Embed one or more flagkit types in your options struct:
type LogOptions struct {
flagkit.Follow
flagkit.LogLevel
flagkit.Output
flagkit.Quiet
Service string `flag:"service" flagdescr:"Service name"`
}
func (o *LogOptions) Attach(c *cobra.Command) error {
if err := structcli.Define(c, o); err != nil {
return err
}
flagkit.AnnotateCommand(c)
return nil
}
Naming Convention ¶
Each type uses the flag name as the struct name: Follow for --follow, Output for --output, Timeout for --timeout, and so on. Inner fields use descriptive names (Enabled, Format, Duration, Level) so that embedded access reads naturally (e.g. opts.Output.Format, not opts.Output.Output).
Index ¶
Constants ¶
const FlagEnumAnnotation = "leodido/structcli/flag-enum"
FlagEnumAnnotation mirrors flagEnumAnnotation (unexported, in viper.go) from the root structcli package. Duplicated here to avoid an import cycle (flagkit → structcli → flagkit).
const FlagKitAnnotation = "leodido/structcli/flag-kit"
FlagKitAnnotation is the pflag annotation key set on flags defined by flagkit types. The generate package uses this to detect flagkit usage and emit development guidance in generated docs.
Variables ¶
This section is empty.
Functions ¶
func AnnotateCommand ¶
AnnotateCommand marks all flagkit-owned flags on the command with the FlagKitAnnotation. Call this after structcli.Define when embedding flagkit types in a parent struct.
When using a flagkit type standalone via its Attach method, the annotation is set automatically and this call is not needed. For embedded usage, structcli.Define traverses into the embedded struct but does not call its Attach method, so AnnotateCommand must be called explicitly to set the annotation.
Matching is by flag name, not by type. If the command defines a non-flagkit flag whose name collides with a flagkit flag name (e.g. a custom --follow), it will be incorrectly annotated. Only call this on commands that embed flagkit types.
func RegisterOutputFormats ¶
func RegisterOutputFormats(formats ...OutputFormat)
RegisterOutputFormats registers the given output formats for use with structcli's enum flag handling. Each format's string value is used as both the canonical name and the only accepted alias.
This is a process-global, one-time registration (like database/sql.Register). Register the superset of all formats your CLI supports. For per-command format subsets, use Output.ValidFormat in your command's RunE.
Call this in init() before any structcli.Define calls:
func init() {
flagkit.RegisterOutputFormats(flagkit.OutputJSON, flagkit.OutputText, flagkit.OutputYAML)
}
For custom aliases, use structcli.RegisterEnum directly instead.
Types ¶
type DryRun ¶
type DryRun struct {
Enabled bool `flag:"dry-run" flagdescr:"Preview without making changes" default:"false" flagenv:"true"`
}
DryRun provides a --dry-run flag for safe previewing of operations.
The default is false. When true, commands should describe what they would do without making changes. This is agent-friendly: AI agents can preview destructive operations before committing.
Usage:
type Options struct {
flagkit.DryRun
}
// In RunE:
if opts.DryRun.Enabled {
fmt.Println("would delete", target)
return nil
}
type Follow ¶
type Follow struct {
Enabled bool `flag:"follow" flagshort:"f" flagdescr:"Stream output continuously" default:"false"`
}
Follow provides a --follow/-f boolean flag for opt-in streaming.
When false (the default), commands should print current output and exit. When true, commands should stream output continuously. This default is agent-friendly: AI agents and scripts won't hang on indefinite tailing.
Usage:
type LogOptions struct {
flagkit.Follow
Service string `flag:"service" flagdescr:"Service name"`
}
func (o *LogOptions) Attach(c *cobra.Command) error {
if err := structcli.Define(c, o); err != nil {
return err
}
flagkit.AnnotateCommand(c)
return nil
}
// In RunE:
if opts.Follow.Enabled {
streamLogs(ctx)
} else {
printCurrentLogs()
}
type LogLevel ¶
type LogLevel = ZapLogLevel
LogLevel is the recommended log level type. It is an alias for ZapLogLevel.
Embed this in your options struct for the standard --log-level flag backed by zapcore.Level. Use SlogLogLevel if you prefer the stdlib slog package.
type Output ¶
type Output struct {
Format OutputFormat `flag:"output" flagshort:"o" flagdescr:"Output format" default:"text"`
// contains filtered or unexported fields
}
Output provides a --output/-o flag for selecting output format.
The default is text. You must register the supported formats before use via RegisterOutputFormats or structcli.RegisterEnum.
For CLIs where different commands support different format subsets, register the superset globally, then call Output.RestrictFormats after Attach. RestrictFormats is the single source of truth: it narrows help, JSON Schema, and runtime validation in one call:
func init() {
flagkit.RegisterOutputFormats(flagkit.OutputJSON, flagkit.OutputText, flagkit.OutputYAML)
}
opts.Attach(cmd)
opts.Output.RestrictFormats(cmd, flagkit.OutputJSON, flagkit.OutputYAML)
// In RunE (no args needed, uses the set from RestrictFormats):
if err := opts.Output.ValidFormat(); err != nil {
return err
}
func (*Output) Attach ¶
Attach implements structcli.Options.
Returns an error if the --output flag was not created, which typically means RegisterOutputFormats (or structcli.RegisterEnum) was not called before Attach.
func (*Output) RestrictFormats ¶
func (o *Output) RestrictFormats(c *cobra.Command, allowed ...OutputFormat)
RestrictFormats narrows the --output flag's help text, enum annotation, and runtime validation to only the given formats. Call this after [Attach] or structcli.Define.
This is the single source of truth for per-command format subsets. After calling RestrictFormats, [ValidFormat] with no arguments enforces the same set, eliminating the need to repeat the allowed list.
Shell completion may still show the globally registered superset because cobra does not support overriding completion functions after registration.
opts.Attach(cmd) opts.Output.RestrictFormats(cmd, flagkit.OutputJSON, flagkit.OutputText)
func (*Output) ValidFormat ¶
func (o *Output) ValidFormat(allowed ...OutputFormat) error
ValidFormat returns nil if the current output format is allowed, or an error describing the mismatch.
When called with no arguments, it validates against the set stored by [RestrictFormats]. When called with explicit arguments, it validates against those instead (and ignores any stored restriction).
If neither RestrictFormats was called nor explicit arguments are provided, ValidFormat returns nil (all formats accepted).
type OutputFormat ¶
type OutputFormat string
OutputFormat is a string enum for output format selection.
flagkit provides common constants but does NOT auto-register them. Call RegisterOutputFormats or structcli.RegisterEnum in your init() to declare the CLI-wide format vocabulary.
const ( OutputJSON OutputFormat = "json" OutputJSONL OutputFormat = "jsonl" OutputText OutputFormat = "text" OutputYAML OutputFormat = "yaml" )
type Quiet ¶
type Quiet struct {
Enabled bool `flag:"quiet" flagshort:"q" flagdescr:"Suppress non-essential output" default:"false"`
}
Quiet provides a --quiet/-q flag for suppressing non-essential output.
The default is false. When true, commands should only emit machine-readable output (e.g., IDs, status codes) and suppress progress messages, banners, and decorative formatting.
Usage:
type Options struct {
flagkit.Quiet
}
// In RunE:
if !opts.Quiet.Enabled {
fmt.Println("Deploying to production...")
}
type SlogLogLevel ¶
type SlogLogLevel struct {
LogLevel slog.Level `flag:"log-level" flagdescr:"Set log level" default:"info" flagenv:"true" flaggroup:"Logging"`
}
SlogLogLevel provides a --log-level flag backed by slog.Level (stdlib).
The default is info. slog.Level is handled by structcli's built-in hooks, so no additional registration is needed.
Usage:
type Options struct {
flagkit.SlogLogLevel
}
func (*SlogLogLevel) Attach ¶
func (o *SlogLogLevel) Attach(c *cobra.Command) error
Attach implements structcli.Options.
type Timeout ¶
type Timeout struct {
Duration time.Duration `flag:"timeout" flagdescr:"Operation timeout" default:"30s" flagenv:"true"`
}
Timeout provides a --timeout flag for operation deadlines.
The default is 30s. Accepts any value parseable by time.ParseDuration. This is agent-friendly: operations won't hang indefinitely.
Usage:
type Options struct {
flagkit.Timeout
}
// In RunE:
ctx, cancel := context.WithTimeout(ctx, opts.Timeout.Duration)
defer cancel()
type Verbose ¶
type Verbose struct {
Level int `flag:"verbose" flagshort:"v" flagtype:"count" flagdescr:"Increase verbosity (-v, -vv, -vvv)" default:"0"`
}
Verbose provides a --verbose/-v count flag for verbosity levels.
The default is 0 (quiet). Each -v increments the count: -v is 1, -vv is 2, -vvv is 3. This is the standard Unix convention for verbosity.
Usage:
type Options struct {
flagkit.Verbose
}
// In RunE:
if opts.Verbose.Level > 1 {
// extra debug output
}
type ZapLogLevel ¶
type ZapLogLevel struct {
LogLevel zapcore.Level `flag:"log-level" flagdescr:"Set log level" default:"info" flagenv:"true" flaggroup:"Logging"`
}
ZapLogLevel provides a --log-level flag backed by zapcore.Level.
The default is info. zapcore.Level is registered as an integer enum by structcli's built-in init(), so no additional registration is needed.
Usage:
type Options struct {
flagkit.ZapLogLevel
Host string `flag:"host" flagdescr:"Server host"`
}
func (*ZapLogLevel) Attach ¶
func (o *ZapLogLevel) Attach(c *cobra.Command) error
Attach implements structcli.Options.