Documentation
¶
Overview ¶
Package yargs provides a flexible, type-safe command-line argument parser with automatic help generation.
The library is designed for building CLIs with subcommands and follows these principles:
- Type-safe flag parsing using Go generics
- Zero boilerplate for common use cases
- Automatic help generation from struct tags
- Flags can appear anywhere in the command line
- Consistent and predictable parsing behavior
Basic Usage (Simple CLI) ¶
For a simple CLI without subcommands, use ParseFlags:
type Flags struct {
Verbose bool `flag:"verbose" short:"v" help:"Enable verbose output"`
Output string `flag:"output" short:"o" help:"Output file"`
}
result, err := yargs.ParseFlags[Flags](os.Args[1:])
if err != nil {
log.Fatal(err)
}
fmt.Printf("Verbose: %v, Output: %s\n", result.Flags.Verbose, result.Flags.Output)
Subcommand CLI ¶
For CLIs with subcommands, use RunSubcommands with ParseAndHandleHelp in handlers:
type GlobalFlags struct {
Verbose bool `flag:"verbose" short:"v" help:"Enable verbose output"`
}
type RunFlags struct {
Detach bool `flag:"detach" short:"d" help:"Run in background"`
}
func handleRun(args []string) error {
result, err := yargs.ParseAndHandleHelp[GlobalFlags, RunFlags](args, helpConfig)
if errors.Is(err, yargs.ErrShown) {
return nil
}
if err != nil {
return err
}
// Use result.GlobalFlags and result.SubCommandFlags
return nil
}
func main() {
handlers := map[string]yargs.SubcommandHandler{
"run": handleRun,
}
if err := yargs.RunSubcommands(os.Args[1:], helpConfig, GlobalFlags{}, handlers); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}
Flag Syntax ¶
Flags support both long and short forms:
- Boolean flags: -v, --verbose
- Flags with values (equals): -o=file.txt, --output=file.txt
- Flags with values (space): -o file.txt, --output file.txt, -n 10, --lines -5
When using ParseWithCommand or ParseFlags with typed structs, the parser automatically consumes the next argument as the flag's value for non-boolean flags (unless the next argument starts with "-"). Boolean flags never consume the next argument
Supported Types ¶
The following types are supported for flag fields:
- string, bool
- int, int8, int16, int32, int64
- uint, uint8, uint16, uint32, uint64
- float32, float64
- time.Duration
- url.URL, *url.URL
- Port (uint16 with optional range validation via `port:"min-max"` tag)
- Pointer types to any of the above (e.g., *int, *bool, *string, *Port)
Pointer types allow distinguishing between "flag not provided" (nil) and "flag provided with value" (non-nil). This is useful for optional settings where you need to preserve existing values if the flag is omitted.
The Port type is a uint16 alias that supports optional range validation. Use the `port:"min-max"` struct tag to specify allowed port ranges:
type Flags struct {
HTTPPort Port `flag:"port" port:"1-65535" help:"HTTP port"`
AdminPort *Port `flag:"admin-port" port:"8000-9000" help:"Admin port"`
}
Command Registry and Introspection ¶
Use Registry to declare command schemas once and resolve commands without hardcoded lists. This is useful for checking positional requirements.
type RunArgs struct {
Service string `pos:"0" help:"Service name"`
Payload string `pos:"1" help:"Payload (file/image)"`
}
type StatusArgs struct {
Service string `pos:"0?" help:"Optional service name"`
}
reg := yargs.Registry{
Command: yargs.CommandInfo{Name: "app"},
SubCommands: map[string]yargs.CommandSpec{
"run": {Info: yargs.SubCommandInfo{Name: "run"}, ArgsSchema: RunArgs{}},
"status": {Info: yargs.SubCommandInfo{Name: "status"}, ArgsSchema: StatusArgs{}},
},
}
res, ok, err := yargs.ResolveCommandWithRegistry(os.Args[1:], reg)
if err != nil {
log.Fatal(err)
}
if ok {
if arg0, ok := res.PArg(0); ok {
fmt.Printf("arg0 name=%s required=%v\n", arg0.Name, arg0.Required)
}
}
Index ¶
- Variables
- func ApplyAliases(args []string, config HelpConfig) []string
- func ConsumeFlagsBySpec(args []string, specs map[string]ConsumeSpec) ([]string, map[string][]string)
- func ExtractGroupAndSubcommand(args []string) (group, subcommand string)
- func ExtractSubcommand(args []string) string
- func GenerateGlobalHelp[G any](config HelpConfig, globalFlagsExample G) string
- func GenerateGlobalHelpLLM[G any](config HelpConfig, globalFlagsExample G) string
- func GenerateGroupHelp[G any](config HelpConfig, groupName string, globalFlagsExample G) string
- func GenerateGroupHelpLLM[G any](config HelpConfig, groupName string, globalFlagsExample G) string
- func GenerateSubCommandHelp[G any, S any, A any](config HelpConfig, subCmdName string, globalFlagsExample G, ...) string
- func GenerateSubCommandHelpFromConfig[G any](config HelpConfig, subCmdName string, globalFlagsExample G) string
- func GenerateSubCommandHelpLLM[G any, S any, A any](config HelpConfig, subCmdName string, globalFlagsExample G, ...) string
- func GenerateSubCommandHelpLLMFromConfig[G any](config HelpConfig, subCmdName string, globalFlagsExample G) string
- func RunSubcommands[G any](ctx context.Context, args []string, config HelpConfig, globalFlagsExample G, ...) error
- func RunSubcommandsWithGroups[G any](ctx context.Context, args []string, config HelpConfig, globalFlagsExample G, ...) error
- type ArgSpec
- type CommandInfo
- type CommandSpec
- type ConsumeSpec
- type FlagValueError
- type Group
- type GroupInfo
- type GroupSpec
- type HelpConfig
- type InvalidArgsError
- type InvalidFlagError
- type KnownFlagsOptions
- type KnownFlagsResult
- type ParseResult
- type Parser
- type Port
- type Registry
- type ResolvedCommand
- type SubCommandInfo
- type SubcommandHandler
- type TypedParseResult
- func ParseAndHandleHelp[G any, S any, A any](args []string, config HelpConfig) (*TypedParseResult[G, S, A], error)
- func ParseWithCommand[G any, S any, A any](args []string) (*TypedParseResult[G, S, A], error)
- func ParseWithCommandAndHelp[G any, S any, A any](args []string, config HelpConfig) (*TypedParseResult[G, S, A], error)
Constants ¶
This section is empty.
Variables ¶
var ( // ErrHelp is returned when global help is requested (--help, -h, or "help" subcommand) ErrHelp = errors.New("help requested") // ErrSubCommandHelp is returned when subcommand-specific help is requested ErrSubCommandHelp = errors.New("subcommand help requested") // ErrHelpLLM is returned when LLM-optimized help is requested (--help-llm) ErrHelpLLM = errors.New("llm help requested") // ErrShown is returned by ParseAndHandleHelp when help or an error message was displayed. // This allows callers to distinguish between "message displayed successfully" and other errors. // Callers should treat this as a signal to exit and return nil to the user. ErrShown = errors.New("help or error displayed") )
Sentinel errors for help handling
Functions ¶
func ApplyAliases ¶
func ApplyAliases(args []string, config HelpConfig) []string
ApplyAliases rewrites args to replace any command aliases with their canonical names. It handles both flat subcommands and grouped commands.
func ConsumeFlagsBySpec ¶
func ConsumeFlagsBySpec(args []string, specs map[string]ConsumeSpec) ([]string, map[string][]string)
ConsumeFlagsBySpec removes known flags from args and returns remaining args plus parsed values. Unknown flags (and their following values) are left intact. The "--" separator stops parsing and is preserved in remaining args.
func ExtractGroupAndSubcommand ¶
ExtractGroupAndSubcommand extracts both group and subcommand from command-line arguments. It returns the first two non-flag arguments (excluding "help"). Returns empty strings if not found. Example: ["docker", "run"] -> ("docker", "run") Example: ["status"] -> ("", "status")
func ExtractSubcommand ¶
ExtractSubcommand extracts the subcommand name from command-line arguments. It returns the first non-flag argument that isn't "help". Returns empty string if no subcommand is found.
func GenerateGlobalHelp ¶
func GenerateGlobalHelp[G any](config HelpConfig, globalFlagsExample G) string
GenerateGlobalHelp generates and prints the global help message.
func GenerateGlobalHelpLLM ¶
func GenerateGlobalHelpLLM[G any](config HelpConfig, globalFlagsExample G) string
GenerateGlobalHelpLLM generates LLM-optimized help for the entire CLI as structured markdown. This format is designed for LLMs to understand the CLI structure, commands, and their usage.
func GenerateGroupHelp ¶
func GenerateGroupHelp[G any](config HelpConfig, groupName string, globalFlagsExample G) string
GenerateGroupHelp generates and prints help for a specific command group.
func GenerateGroupHelpLLM ¶
func GenerateGroupHelpLLM[G any](config HelpConfig, groupName string, globalFlagsExample G) string
GenerateGroupHelpLLM generates LLM-optimized help for a specific command group as structured markdown.
func GenerateSubCommandHelp ¶
func GenerateSubCommandHelp[G any, S any, A any](config HelpConfig, subCmdName string, globalFlagsExample G, subCmdFlagsExample S, argsExample A) string
GenerateSubCommandHelp generates and prints help for a specific subcommand.
func GenerateSubCommandHelpFromConfig ¶
func GenerateSubCommandHelpFromConfig[G any](config HelpConfig, subCmdName string, globalFlagsExample G) string
GenerateSubCommandHelpFromConfig generates subcommand help using only HelpConfig metadata. It omits subcommand-specific flags and arguments when no structured types are available.
func GenerateSubCommandHelpLLM ¶
func GenerateSubCommandHelpLLM[G any, S any, A any](config HelpConfig, subCmdName string, globalFlagsExample G, subCmdFlagsExample S, argsExample A) string
GenerateSubCommandHelpLLM generates LLM-optimized help for a specific subcommand as structured markdown.
func GenerateSubCommandHelpLLMFromConfig ¶
func GenerateSubCommandHelpLLMFromConfig[G any](config HelpConfig, subCmdName string, globalFlagsExample G) string
GenerateSubCommandHelpLLMFromConfig generates LLM-optimized help for a subcommand using only HelpConfig metadata.
func RunSubcommands ¶
func RunSubcommands[G any](ctx context.Context, args []string, config HelpConfig, globalFlagsExample G, handlers map[string]SubcommandHandler) error
RunSubcommands automatically routes to the appropriate subcommand handler. It handles:
- Empty args: shows global help
- Global help flags (--help, -h, help): shows global help
- Unknown subcommands: returns error with helpful message
- Known subcommands: calls the registered handler
This eliminates all the boilerplate of manual help handling and routing.
Example:
handlers := map[string]yargs.SubcommandHandler{
"status": handleStatus,
"run": handleRun,
}
if err := yargs.RunSubcommands(os.Args[1:], helpConfig, GlobalFlags{}, handlers); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
func RunSubcommandsWithGroups ¶
func RunSubcommandsWithGroups[G any](ctx context.Context, args []string, config HelpConfig, globalFlagsExample G, commands map[string]SubcommandHandler, groups map[string]Group) error
RunSubcommandsWithGroups automatically routes to the appropriate subcommand handler, supporting both flat commands and grouped commands (e.g., "docker run"). It handles:
- Empty args: shows global help
- Global help flags (--help, -h, help): shows global help
- Group without subcommand (e.g., "docker"): shows group help
- Group help flags (e.g., "docker --help"): shows group help
- Grouped subcommands (e.g., "docker run"): calls the handler from the group
- Flat subcommands (e.g., "status"): calls the handler from commands map
- Unknown groups/commands: returns error with helpful message
This allows mixing flat commands with grouped commands for better organization.
Example:
commands := map[string]yargs.SubcommandHandler{
"status": handleStatus,
"whoami": handleWhoAmI,
}
groups := map[string]yargs.Group{
"docker": {
Description: "Docker-related commands",
Commands: map[string]yargs.SubcommandHandler{
"run": handleDockerRun,
"ps": handleDockerPs,
},
},
}
if err := yargs.RunSubcommandsWithGroups(ctx, os.Args[1:], config, GlobalFlags{}, commands, groups); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
Types ¶
type ArgSpec ¶
type ArgSpec struct {
Position int
Name string
Type string
GoType reflect.Type
Description string
Required bool
Variadic bool
MinCount int
IsSlice bool
}
ArgSpec describes a positional argument defined by struct tags.
func ExtractArgSpecs ¶
ExtractArgSpecs extracts positional argument metadata from a struct with `pos` tags. It returns an empty slice if schema is nil or not a struct.
type CommandInfo ¶
type CommandInfo struct {
Name string
Description string
Examples []string
LLMInstructions string // Additional instructions for LLMs (only shown in --help-llm)
}
CommandInfo contains metadata about the CLI command for help generation.
type CommandSpec ¶
type CommandSpec struct {
Info SubCommandInfo
ArgsSchema any
}
CommandSpec describes a subcommand with optional positional-argument schema.
type ConsumeSpec ¶
ConsumeSpec describes how to consume a flag and its values from args. Kind is the expected type; bool flags never consume the next argument. SplitComma splits comma-separated values into multiple entries.
type FlagValueError ¶
type FlagValueError struct {
FlagName string // The flag that had an invalid value (e.g., "http-port")
FieldName string // The struct field name (e.g., "HTTPPort")
Value string // The invalid value that was provided
SubCommand string // The subcommand (if any)
UserMsg string // User-friendly error message for display
Err error // Full wrapped error chain for debugging/verbose logging
}
FlagValueError is returned when a flag value cannot be parsed or is invalid. It provides a user-friendly error message while preserving the underlying error for debugging. UserMsg contains the clean user-facing error message, while Err contains the full wrapped error chain.
func (*FlagValueError) Error ¶
func (e *FlagValueError) Error() string
func (*FlagValueError) Unwrap ¶
func (e *FlagValueError) Unwrap() error
type Group ¶
type Group struct {
Description string
Commands map[string]SubcommandHandler // Handlers for commands in this group
}
Group represents a collection of related subcommands with their runtime handlers. A group itself has no handler - it only organizes commands under a common prefix. Groups are used at runtime to route commands like "docker run" where "docker" is the group.
Example:
groups := map[string]yargs.Group{
"docker": {
Description: "Docker container management",
Commands: map[string]yargs.SubcommandHandler{
"run": handleDockerRun,
"ps": handleDockerPs,
},
},
}
type GroupInfo ¶
type GroupInfo struct {
Name string
Description string
Commands map[string]SubCommandInfo // Commands within this group
Hidden bool // Hidden groups don't appear in help but still work
LLMInstructions string // Additional instructions for LLMs (only shown in --help-llm)
}
GroupInfo contains metadata about a command group for help generation. Unlike Group, GroupInfo contains SubCommandInfo structs instead of handlers, and is used purely for generating help text. The GroupInfo should be included in HelpConfig.Groups and must match the structure of the Group.
Example:
Groups: map[string]yargs.GroupInfo{
"docker": {
Name: "docker",
Description: "Docker container management",
Commands: map[string]yargs.SubCommandInfo{
"run": {Name: "run", Description: "Run a container"},
"ps": {Name: "ps", Description: "List containers"},
},
},
}
type GroupSpec ¶
type GroupSpec struct {
Info GroupInfo
Commands map[string]CommandSpec
}
GroupSpec describes a group of commands with optional positional-argument schemas.
type HelpConfig ¶
type HelpConfig struct {
Command CommandInfo
SubCommands map[string]SubCommandInfo // Flat subcommands (status, whoami, etc.)
Groups map[string]GroupInfo // Command groups (docker, etc.)
}
HelpConfig contains all metadata needed for help generation.
type InvalidArgsError ¶
type InvalidArgsError struct {
Expected string // "1", "1-3", "at least 1", "0 or more"
Got int
SubCommand string // The subcommand that had invalid args (if any)
}
InvalidArgsError is returned when the wrong number of positional arguments is provided.
func (*InvalidArgsError) Error ¶
func (e *InvalidArgsError) Error() string
type InvalidFlagError ¶
type InvalidFlagError struct {
Flag string
SubCommand string // The subcommand that had an invalid flag (if any). Empty if the flag appeared before the subcommand was identified.
}
InvalidFlagError is returned when an unknown/undefined flag is encountered.
func (*InvalidFlagError) Error ¶
func (e *InvalidFlagError) Error() string
type KnownFlagsOptions ¶
type KnownFlagsOptions struct {
SplitCommaSlices bool
}
KnownFlagsOptions controls how ParseKnownFlags handles slices.
type KnownFlagsResult ¶
KnownFlagsResult contains parsed flags plus remaining args.
func ParseKnownFlags ¶
func ParseKnownFlags[T any](args []string, opts KnownFlagsOptions) (*KnownFlagsResult[T], error)
ParseKnownFlags parses only the flags defined by T and leaves unknown flags intact. It returns the remaining args with known flags removed.
type ParseResult ¶
ParseResult combines the parsed flags with the Parser for access to other fields.
func ParseFlags ¶
func ParseFlags[T any](args []string) (*ParseResult[T], error)
ParseFlags parses command-line arguments and returns a typed struct with parsed flags. The struct fields should have a `flag:"name"` tag to specify the flag name. Optionally use `short:"x"` tag for short flag aliases. Supported types: string, bool, int, int64, uint, uint64, float64, time.Duration, url.URL, *url.URL Pointer types (*int, *bool, *string, etc.) are also supported for optional flags - they remain nil if not specified
Example:
type Flags struct {
Verbose bool `flag:"verbose" short:"v"`
ControlURL string `flag:"control-url"`
Port int `flag:"port"`
}
result, err := yargs.ParseFlags[Flags](os.Args[1:])
type Parser ¶
type Parser struct {
// SubCommand is the sub-command name (first non-flag argument)
SubCommand string
// Args contains positional arguments to the sub-command
Args []string
// GlobalFlags contains global flags parsed from anywhere in the command line
GlobalFlags map[string]string
// SubCommandFlags contains sub-command specific flags
SubCommandFlags map[string]string
// Flags contains all flags (global and sub-command) for backward compatibility
Flags map[string]string
// RemainingArgs contains all arguments after "--" as a slice (preserves argument boundaries)
RemainingArgs []string
}
Parser represents a parsed command line.
type Port ¶
type Port uint16
Port is a uint16 type alias for IP ports with optional range validation. When used in struct fields, you can optionally specify allowed port ranges using the `port:"min-max"` struct tag. If no range is specified, all ports 0-65535 are allowed.
Examples:
type Flags struct {
HTTPPort Port `flag:"port" port:"1-65535" help:"HTTP port (excludes port 0)"`
AdminPort *Port `flag:"admin" port:"8000-9000" help:"Admin port (restricted range)"`
}
Note: Range validation only applies to flag fields, not positional arguments.
type Registry ¶
type Registry struct {
Command CommandInfo
SubCommands map[string]CommandSpec
Groups map[string]GroupSpec
}
Registry provides a schema-aware command registry independent of help config.
func (Registry) CommandSpec ¶
func (r Registry) CommandSpec(path []string) (CommandSpec, bool)
CommandSpec returns the CommandSpec for the given command path.
func (Registry) HelpConfig ¶
func (r Registry) HelpConfig() HelpConfig
HelpConfig returns a HelpConfig derived from the registry.
type ResolvedCommand ¶
type ResolvedCommand struct {
Path []string
Info SubCommandInfo
Args []string
// ArgsSchema is an optional schema (struct with `pos` tags) used for introspection.
ArgsSchema any
}
ResolvedCommand describes a resolved subcommand and the remaining args. Path is ["subcommand"] or ["group", "subcommand"] and Args excludes the command tokens.
func ResolveCommand ¶
func ResolveCommand(args []string, config HelpConfig) (ResolvedCommand, bool, error)
ResolveCommand resolves a subcommand (including grouped commands) using the same alias and parsing rules as the dispatcher. It returns the resolved command path and the remaining args with the command tokens removed.
func ResolveCommandWithRegistry ¶
func ResolveCommandWithRegistry(args []string, reg Registry) (ResolvedCommand, bool, error)
ResolveCommandWithRegistry resolves a command using the registry and attaches the args schema.
type SubCommandInfo ¶
type SubCommandInfo struct {
Name string
Description string
Usage string // e.g., "SERVICE" or "SERVICE [SERVICE...]"
Examples []string
Aliases []string
Hidden bool // Hidden subcommands don't appear in help but still work
LLMInstructions string // Additional instructions for LLMs (only shown in --help-llm)
}
SubCommandInfo contains metadata about a subcommand for help generation.
type SubcommandHandler ¶
SubcommandHandler is a function that handles a subcommand. It receives the original args (including the subcommand name) and returns an error if the command fails.
type TypedParseResult ¶
type TypedParseResult[G any, S any, A any] struct { *Parser GlobalFlags G SubCommandFlags S Args A HelpText string // Contains generated help text if help was requested }
TypedParseResult combines the parsed flags and args with the Parser for access to other fields.
func ParseAndHandleHelp ¶
func ParseAndHandleHelp[G any, S any, A any](args []string, config HelpConfig) (*TypedParseResult[G, S, A], error)
ParseAndHandleHelp parses command-line arguments and automatically handles help output. If help is requested, it prints the help text to stdout and returns (nil, ErrShown). This eliminates the need for manual help checking in command handlers.
When a FlagValueError occurs and the global flags struct has a "Verbose" field set to true, detailed error information is displayed including the flag name, value, subcommand, and full error chain.
Returns:
- (result, nil) on successful parse
- (nil, ErrShown) if help was displayed (caller should treat as success)
- (nil, error) if parsing failed
Usage:
result, err := yargs.ParseAndHandleHelp[GlobalFlags, RunFlags, RunArgs](args, config)
if errors.Is(err, yargs.ErrShown) {
return nil // Help was shown, exit successfully
}
if err != nil {
return err // Actual error
}
// Use result.GlobalFlags, result.SubCommandFlags, and result.Args
func ParseWithCommand ¶
ParseWithCommand parses command-line arguments and returns typed structs for global flags, subcommand flags, and positional args. The generic type parameters define which flags are global vs subcommand-specific via struct tags. Panics if the same flag name appears in both G and S types.
func ParseWithCommandAndHelp ¶
func ParseWithCommandAndHelp[G any, S any, A any](args []string, config HelpConfig) (*TypedParseResult[G, S, A], error)
ParseWithCommandAndHelp parses command-line arguments with automatic help generation. If help is requested (via --help, -h, or help subcommand), it generates the help text and returns it in the HelpText field along with the appropriate error (ErrHelp or ErrSubCommandHelp).