{"id":29237719,"url":"https://github.com/leodido/structcli","last_synced_at":"2026-02-15T22:06:33.180Z","repository":{"id":222047034,"uuid":"756107355","full_name":"leodido/structcli","owner":"leodido","description":"Eliminate Cobra boilerplate: build powerful, feature-rich CLIs declaratively from Go structs.","archived":false,"fork":false,"pushed_at":"2025-06-25T23:48:56.000Z","size":801,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-07-22T00:24:53.934Z","etag":null,"topics":["cli","cobra","configuration-files","environment-variables","flags","golang","struct","viper"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leodido.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"leodido"}},"created_at":"2024-02-12T00:15:35.000Z","updated_at":"2025-06-25T23:47:27.000Z","dependencies_parsed_at":"2025-05-23T16:29:52.472Z","dependency_job_id":"d2b8eb4a-c71a-41c0-bbb7-28357f06992c","html_url":"https://github.com/leodido/structcli","commit_stats":null,"previous_names":["leodido/autoflags","leodido/structcli"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/leodido/structcli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leodido%2Fstructcli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leodido%2Fstructcli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leodido%2Fstructcli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leodido%2Fstructcli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leodido","download_url":"https://codeload.github.com/leodido/structcli/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leodido%2Fstructcli/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267213498,"owners_count":24053912,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-26T02:00:08.937Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","cobra","configuration-files","environment-variables","flags","golang","struct","viper"],"created_at":"2025-07-03T18:36:51.424Z","updated_at":"2026-02-15T22:06:33.174Z","avatar_url":"https://github.com/leodido.png","language":"Go","readme":"[![Coverage](https://img.shields.io/codecov/c/github/leodido/structcli.svg?style=for-the-badge)](https://codecov.io/gh/leodido/structcli) [![Documentation](https://img.shields.io/badge/godoc-reference-blue.svg?style=for-the-badge)](https://godoc.org/github.com/leodido/structcli) [![GoReportCard](https://img.shields.io/badge/go%20report-A+-brightgreen.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/leodido/structcli)\n\n\u003e CLI generation from Go structs\n\nTransform your Go structs into fully-featured command-line interfaces with configuration files, environment variables, flags, validation, and beautiful help output.\n\n\u003e Declare your options in a struct, and let structcli do the rest\n\nYou don't need much: just a few struct tags + **structcli**.\n\nStop writing boilerplate. Start building features.\n\n## ⚡ Quick Start\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/leodido/structcli\"\n\t\"github.com/spf13/cobra\"\n\t\"go.uber.org/zap/zapcore\"\n)\n\ntype Options struct {\n\tLogLevel zapcore.Level\n\tPort     int\n}\n\nfunc (o *Options) Attach(c *cobra.Command) error {\n\treturn structcli.Define(c, o) // This is it\n}\n\nfunc main() {\n\tlog.SetFlags(0)\n\topts := \u0026Options{}\n\tcli := \u0026cobra.Command{Use: \"myapp\"}\n\n\t// This single line creates all the options (flags, env vars, config keys)\n\tif err := opts.Attach(cli); err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tcli.PreRunE = func(c *cobra.Command, args []string) error {\n\t\treturn structcli.Unmarshal(c, opts) // Populates struct from config keys, env variables, flags\n\t}\n\n\tcli.RunE = func(c *cobra.Command, args []string) error {\n\t\tfmt.Println(opts)\n\n\t\treturn nil\n\t}\n\n\tif err := cli.Execute(); err != nil {\n\t\tlog.Fatalln(err)\n\t}\n}\n```\n\n**That's it**!\n\n```bash\n❯ go run examples/minimal/main.go --help\n# Usage:\n#   myapp [flags]\n#\n# Flags:\n#       --loglevel zapcore.Level    {debug,info,warn,error,dpanic,panic,fatal} (default info)\n#       --port int\n```\n\nWant automatic environment variables, aliases, shorthand, flag description in usage?\n\nJust annotate your struct with `structcli` tags.\n\n```go\ntype Options struct {\n\tLogLevel zapcore.Level `flag:\"level\" flagdescr:\"Set logging level\" flagenv:\"true\"`\n\tPort     int           `flagshort:\"p\" flagdescr:\"Server port\" flagenv:\"true\" default:\"3000\"`\n}\n```\n\nHere it is.\n\n```bash\n❯ go run examples/simple/main.go -h\n# Usage:\n#   myapp [flags]\n#\n# Flags:\n#       --level zapcore.Level   Set logging level {debug,info,warn,error,dpanic,panic,fatal} (default info)\n#   -p, --port int              Server port (default 3000)\n```\n\nYou got your environment variables.\n\n```bash\n❯ MYAPP_LOGLEVEL=debug go run examples/simple/main.go\n# \u0026{debug 3000}\n```\n\n```bash\n❯ MYAPP_LEVEL=warn go run examples/simple/main.go\n# \u0026{warn 3000}\n```\n\nFlags override environment variables, of course.\n\n```bash\n❯ MYAPP_LOGLEVEL=error MYAPP_PORT=9000 go run examples/simple/main.go --level dpanic\n# \u0026{dpanic 9000}\n```\n\nBuilt-in custom types like `zapcore.LogLevel` comes with automatic validation.\n\n```bash\n❯ MYAPP_LOGLEVEL=debug MYAPP_PORT=9000 go run examples/simple/main.go --level what\n# Error: invalid argument \"what\" for \"--level\" flag: must be 'debug', 'dpanic', 'error', 'fatal', 'info', 'panic', 'warn'\n# Usage:\n#   myapp [flags]\n#\n# Flags:\n#       --level zapcore.Level   Set logging level {debug,info,warn,error,dpanic,panic,fatal} (default info)\n#   -p, --port int              Server port (default 3000)\n#\n# invalid argument \"what\" for \"--level\" flag: must be 'debug', 'dpanic', 'error', 'fatal', 'info', 'panic', 'warn'\n# exit status 1\n```\n\nYour CLI now supports:\n\n- 📝 Command-line flags (`--level info`, `-p 8080`)\n- 🌍 Environment variables (`MYAPP_PORT=8080`)\n- 💦 Options precedence (flags \u003e env vars \u003e config file \u003e defaults)\n- ✅ Automatic validation and type conversion\n- 📚 Beautiful help output with proper grouping\n\n## ⬇️ Install\n\n```bash\ngo get github.com/leodido/structcli\n```\n\n## 📦 Key Features\n\n### 🧩 Declarative Flags Definition\n\nDefine flags once using Go struct tags.\n\nNo more boilerplate for `Flags().StringVarP`, `Flags().IntVar`, `viper.BindPFlag`, etc.\n\nYes, you can _nest_ structs too.\n\n```go\ntype ServerOptions struct {\n\t// Basic flags\n\tHost string `flag:\"host\" flagdescr:\"Server host\" default:\"localhost\"`\n\tPort int    `flagshort:\"p\" flagdescr:\"Server port\" flagrequired:\"true\" flagenv:\"true\"`\n\n\t// Environment variable binding\n\tAPIKey string `flagenv:\"true\" flagdescr:\"API authentication key\"`\n\n\t// Flag grouping for organized help\n\tLogLevel zapcore.Level `flag:\"log-level\" flaggroup:\"Logging\" flagdescr:\"Set log level\"`\n\tLogFile  string        `flag:\"log-file\" flaggroup:\"Logging\" flagdescr:\"Log file path\" flagenv:\"true\"`\n\n\t// Nested structs for organization\n\tDatabase DatabaseConfig `flaggroup:\"Database\"`\n\n\t// Custom type\n\tTargetEnv Environment `flagcustom:\"true\" flag:\"target-env\" flagdescr:\"Set the target environment\"`\n}\n\ntype DatabaseConfig struct {\n\tURL      string `flag:\"db-url\" flagdescr:\"Database connection URL\"`\n\tMaxConns int    `flagdescr:\"Max database connections\" default:\"10\" flagenv:\"true\"`\n}\n```\n\nSee [full example](examples/full/cli/cli.go) for more details.\n\n### 🛠️ Automatic Environment Variable Binding\n\nAutomatically generate environment variables binding them to configuration files (YAML, JSON, TOML, etc.) and flags.\n\nFrom the previous options struct, you get the following env vars automatically:\n\n- `FULL_SRV_PORT`\n- `FULL_SRV_APIKEY`\n- `FULL_SRV_DATABASE_MAXCONNS`\n- `FULL_SRV_LOGFILE`, `FULL_SRV_LOG_FILE`\n\nEvery struct field with the `flagenv:\"true\"` tag gets an environment variable (two if the struct field also has the `flag:\"...\"` tag, see struct field `LogFile`).\n\nThe prefix of the environment variable name is the CLI name plus the command name to which those options are attached to.\n\nEnvironment variables are command-scoped for command-local options.\nFor example, if `Port` is attached to the `srv` command, `FULL_SRV_PORT` is used (not `FULL_PORT`).\n\n### ⚙️ Configuration File Support\n\nEasily set up configuration file discovery (flag, environment variable, and fallback paths) with a single line of code.\n\n```go\nstructcli.SetupConfig(rootCmd, config.Options{AppName: \"full\"})\n```\n\nEnable strict config-key validation with:\n\n```go\nstructcli.SetupConfig(rootCmd, config.Options{\n  AppName:      \"full\",\n  ValidateKeys: true, // opt-in\n})\n```\n\nWhen enabled, `Unmarshal` fails if command-relevant config contains unknown keys.\n\nCall `SetupConfig` before attaching/defining options when you rely on app-prefixed environment variables, so the env prefix is initialized before env annotations are generated.\n\nThe line above:\n\n- creates `--config` global flag\n- creates `FULL_CONFIG` env var\n- sets `/etc/full/`, `$HOME/.full/`, `$PWD/.full/` as fallback paths for `config.yaml`\n\nMagic, isn't it?\n\nWhat's left? Tell your CLI to load the configuration file (if any).\n\n```go\nrootC.PersistentPreRunE = func(c *cobra.Command, args []string) error {\n\t_, configMessage, configErr := structcli.UseConfigSimple(c)\n\tif configErr != nil {\n\t\treturn configErr\n\t}\n\tif configMessage != \"\" {\n\t\tc.Println(configMessage)\n\t}\n\n\treturn nil\n}\n```\n\n`UseConfigSimple(c)` loads config into the root config scope and merges only the relevant section into `c`'s effective scope.\n\n#### 🧠 Viper Model Scopes\n\n`structcli` uses two different viper scopes on purpose:\n\n- `structcli.GetConfigViper(rootOrLeafCmd)` -\u003e root-scoped **config source** (config file data tree)\n- `structcli.GetViper(cmd)` -\u003e command-scoped **effective values** (flags/env/defaults + command-relevant config)\n\nThis separation keeps config-file loading isolated from runtime command state.\n\nIf you need imperative values in tests or application code, write to the right scope:\n\n```go\n// 1) Effective override for one command context\nstructcli.GetViper(cmd).Set(\"timeout\", 60)\n\n// 2) Config-tree style injection (top-level + command section)\nstructcli.GetConfigViper(rootCmd).Set(\"srv\", map[string]any{\n  \"port\": 8443,\n})\n```\n\nGlobal `viper.Set(...)` is not used by `structcli.Unmarshal(...)` resolution.\nUse `GetViper`/`GetConfigViper` instead.\n\n#### 📜 Configuration Is First-Class Citizen\n\nConfiguration can mirror your command hierarchy.\n\nSettings can be global (at the top level) or specific to a command or subcommand. The most specific section always takes precedence.\n\n```yaml\n# Global settings apply to all commands unless overridden by a specific section.\n# `dryrun` matches the `DryRun` struct field name.\ndryrun: true\nverbose: 1 # A default verbosity level for all commands.\n\n# Config for the `srv` command (`full srv`)\nsrv:\n  # `port` matches the `Port` field name.\n  port: 8433\n  # `log-level` matches the `flag:\"log-level\"` tag.\n  log-level: \"warn\"\n  # `logfile` matches the `LogFile` field name.\n  logfile: /var/log/mysrv.log\n\n  # Flattened keys can set options in nested structs.\n  # `db-url` (from `flag:\"db-url\"` tag) maps to ServerOptions.Database.URL.\n  db-url: \"postgres://user:pass@db/prod\"\n\n  # Nested keys are also supported.\n  database:\n    # Struct field key style\n    url: \"postgres://user:pass@db/prod\"\n    # Alias key style (from `flag:\"db-url\"`)\n    db-url: \"postgres://user:pass@db/prod\"\n\n# Config for the `usr` command group.\nusr:\n  # This nested section matches the `usr add` command (`full usr add`).\n  # Its settings are ONLY applied to 'usr add'.\n  add:\n    name: \"Config User\"\n    email: \"config.user@example.com\"\n    age: 42\n    # Command specific override\n    dry: false\n# NOTE: Per the library's design, there is no other fallback other than from the top-level.\n# A command like 'usr delete' would ONLY use the global keys above (if those keys/flags are attached to it),\n# as an exact 'usr.delete' section is not defined.\n```\n\nThis configuration system supports:\n\n- **Hierarchical Structure**: Nest keys to match your command path (e.g., `usr: { add: { ... } }`).\n- **Strict Precedence**: Only settings from the global scope and the exact command path section are merged. There is no automatic fallback to parent command sections.\n- **Flexible Keys**: You can use struct field names and aliases (`flag:\"...\"`) in both flattened and nested forms.\n- **Supported Forms for Nested Fields**: `db-url`, `database.url`, `database: { url: ... }`, and `database: { db-url: ... }`.\n\n### ✅ Built-in Validation \u0026 Transformation\n\nSupports validation, transformation, and custom flag type definitions through simple interfaces.\n\nYour struct must implement `Options` (via `Attach`) and can optionally implement `ValidatableOptions` and `TransformableOptions`.\n\n```go\ntype UserConfig struct {\n\tEmail string `flag:\"email\" flagdescr:\"User email\" validate:\"email\"`\n\tAge   int    `flag:\"age\" flagdescr:\"User age\" validate:\"min=18,max=120\"`\n\tName  string `flag:\"name\" flagdescr:\"User name\" mod:\"trim,title\"`\n}\n\nfunc (o *ServerOptions) Validate(ctx context.Context) []error {\n    // Automatic validation\n}\n\nfunc (o *ServerOptions) Transform(ctx context.Context) error {\n    // Automatic transformation\n}\n```\n\nSee a full working example [here](examples/full/cli/cli.go).\n\n### 🚧 Automatic Debugging Support\n\nCreate a `--debug-options` flag (plus a `FULL_DEBUG_OPTIONS` env var) for troubleshooting config/env/flags resolution.\n\n```go\nstructcli.SetupDebug(rootCmd, debug.Options{})\n```\n\n```bash\n❯ go run examples/full/main.go srv --debug-options --config examples/full/config.yaml -p 3333\n#\n# Aliases:\n# map[string]string{\"database.url\":\"db-url\", \"logfile\":\"log-file\", \"loglevel\":\"log-level\", \"targetenv\":\"target-env\"}\n# Override:\n# map[string]interface {}{}\n# PFlags:\n# map[string]viper.FlagValue{\"apikey\":viper.pflagValue{flag:(*pflag.Flag)(0x14000109ea0)}, \"database.maxconns\":viper.pflagValue{flag:(*pflag.Flag)(0x140002181e0)}, \"db-url\":viper.pflagValue{flag:(*pflag.Flag)(0x14000218140)}, \"host\":viper.pflagValue{flag:(*pflag.Flag)(0x14000109d60)}, \"log-file\":viper.pflagValue{flag:(*pflag.Flag)(0x140002180a0)}, \"log-level\":viper.pflagValue{flag:(*pflag.Flag)(0x14000218000)}, \"port\":viper.pflagValue{flag:(*pflag.Flag)(0x14000109e00)}, \"target-env\":viper.pflagValue{flag:(*pflag.Flag)(0x14000218320)}}\n# Env:\n# map[string][]string{\"apikey\":[]string{\"SRV_APIKEY\"}, \"database.maxconns\":[]string{\"SRV_DATABASE_MAXCONNS\"}, \"log-file\":[]string{\"SRV_LOGFILE\", \"SRV_LOG_FILE\"}}\n# Key/Value Store:\n# map[string]interface {}{}\n# Config:\n# map[string]interface {}{\"apikey\":\"secret-api-key\", \"database\":map[string]interface {}{\"maxconns\":3}, \"db-url\":\"postgres://user:pass@localhost/mydb\", \"host\":\"production-server\", \"log-file\":\"/var/log/mysrv.log\", \"log-level\":\"debug\", \"port\":8443}\n# Defaults:\n# map[string]interface {}{\"database\":map[string]interface {}{\"maxconns\":\"10\"}, \"host\":\"localhost\"}\n# Values:\n# map[string]interface {}{\"apikey\":\"secret-api-key\", \"database\":map[string]interface {}{\"maxconns\":3, \"url\":\"postgres://user:pass@localhost/mydb\"}, \"db-url\":\"postgres://user:pass@localhost/mydb\", \"host\":\"production-server\", \"log-file\":\"/var/log/mysrv.log\", \"log-level\":\"debug\", \"logfile\":\"/var/log/mysrv.log\", \"loglevel\":\"debug\", \"port\":3333, \"target-env\":\"dev\", \"targetenv\":\"dev\"}\n```\n\n### ↪️ Sharing Options Between Commands\n\nIn complex CLIs, multiple commands often need access to the same global configuration and shared resources (like a logger or a database connection). `structcli` provides a powerful pattern using the [ContextOptions](/contract.go) interface to achieve this without resorting to global variables, by propagating a single \"source of truth\" through the command context.\n\nThe pattern allows you to:\n\n- Populate a shared options struct once from flags, environment variables, or a config file.\n- Initialize \"computed state\" (like a logger) based on those options.\n- Share this single, fully-prepared \"source of truth\" with any subcommand that needs it.\n\n#### 🍩 In a Nutshell\n\nCreate a shared struct that implements the `ContextOptions` interface. This struct will hold both the configuration flags and the computed state (e.g., the logger).\n\n```go\n// This struct holds our shared state.\ntype CommonOptions struct {\n    LogLevel zapcore.Level `flag:\"loglevel\" flagdescr:\"Logging level\" default:\"info\"`\n    Logger   *zap.Logger   `flagignore:\"true\"` // This field is computed, not a flag.\n}\n\n// The Context/FromContext methods enable the propagation pattern.\nfunc (o *CommonOptions) Context(ctx context.Context) context.Context { /* ... */ }\nfunc (o *CommonOptions) FromContext(ctx context.Context) error { /* ... */ }\n\n// Initialize is a custom method to create the computed state.\nfunc (o *CommonOptions) Initialize() error { /* ... */ }\n```\n\nInitialize the state in the root command. Use a `PersistentPreRunE` hook on your root command to populate your struct and initialize any resources.\nInvoking `structcli.Unmarshal` will automatically inject the prepared object into the context for all subcommands to use.\n\n```go\nrootC.PersistentPreRunE = func(c *cobra.Command, args []string) error {\n\t// Populate the master `commonOpts` from flags, env, and config file.\n\tif err := structcli.Unmarshal(c, commonOpts); err != nil {\n\t\treturn err\n\t}\n\t// Use the populated values to initialize the computed state (the logger).\n\tif err := commonOpts.Initialize(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n```\n\nFinally, retrieve the state in subcommands. In your subcommand's `RunE`, simply call `.FromContext()` to retrieve the shared, initialized object.\n\n```go\nfunc(c *cobra.Command, args []string) error {\n    // Create a receiver and retrieve the master state from the context.\n    config := \u0026CommonOptions{}\n    if err := config.FromContext(c.Context()); err != nil {\n        return err\n    }\n    config.Logger.Info(\"Executing subcommand...\")\n\n    return nil\n},\n```\n\nThis pattern ensures that subcommands remain decoupled while having access to a consistent, centrally-managed state.\n\nFor a complete, runnable implementation of this pattern, see the loginsvc example located in the [/examples/loginsvc](/examples/loginsvc/) directory.\n\n### 🪃 Custom Type Handlers\n\nDeclare options (flags, env vars, config file keys) with custom types by implementing two methods on your options struct.\n\nJust implement two methods on your options structs:\n\n- `Define\u003cFieldName\u003e`: return a `pflag.Value` that knows how to handle your custom type, along with an enhanced description.\n- `Decode\u003cFieldName\u003e`: decode the input into your custom type.\n\n```go\ntype Environment string\n\nconst (\n\tEnvDevelopment Environment = \"dev\"\n\tEnvStaging     Environment = \"staging\"\n\tEnvProduction  Environment = \"prod\"\n)\n\ntype ServerOptions struct {\n\t...\n\t// Custom type\n\tTargetEnv Environment `flagcustom:\"true\" flag:\"target-env\" flagdescr:\"Set the target environment\"`\n}\n\n// DefineTargetEnv returns a pflag.Value for the custom Environment type.\nfunc (o *ServerOptions) DefineTargetEnv(name, short, descr string, structField reflect.StructField, fieldValue reflect.Value) (pflag.Value, string) {\n    enhancedDesc := descr + \" {dev,staging,prod}\"\n    fieldPtr := fieldValue.Addr().Interface().(*Environment)\n    *fieldPtr = \"dev\" // Set default\n\n    return structclivalues.NewString((*string)(fieldPtr)), enhancedDesc\n}\n\n// DecodeTargetEnv converts the string input to the Environment type.\nfunc (o *ServerOptions) DecodeTargetEnv(input any) (any, error) {\n\t// ... (validation and conversion logic)\n    return EnvDevelopment, nil\n}\n\n// Attach handles flag definition and shell completion for our custom type.\nfunc (o *ServerOptions) Attach(c *cobra.Command) error {\n\tif err := structcli.Define(c, o); err != nil {\n        return err\n    }\n\n    // Register shell completion after the flag has been defined.\n    c.RegisterFlagCompletionFunc(\"target-env\", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {\n        return []string{\"dev\", \"staging\", \"prod\"}, cobra.ShellCompDirectiveNoFileComp\n    })\n\n    return nil\n}\n```\n\nIn [values](/values/values.go) we provide `pflag.Value` implementations for standard types.\n\nSee [full example](examples/full/cli/cli.go) for more details.\n\n### 🧱 Built-in Custom Types\n\n| Type            | Description                     | Example Values                                               | Special Features                   |\n| --------------- | ------------------------------- | ------------------------------------------------------------ | ---------------------------------- |\n| `zapcore.Level` | Zap logging levels              | `debug`, `info`, `warn`, `error`, `dpanic`, `panic`, `fatal` | Enum validation                    |\n| `slog.Level`    | Standard library logging levels | `debug`, `info`, `warn`, `error`, `error+2`, ...             | Level offsets: `ERROR+2`, `INFO-4` |\n| `time.Duration` | Time durations                  | `30s`, `5m`, `2h`, `1h30m`                                   | Go duration parsing                |\n| `[]string`      | String slices                   | `item1,item2,item3`                                          | Comma-separated                    |\n| `[]int`         | Integer slices                  | `1,2,3,42`                                                   | Comma-separated                    |\n\nAll built-in types support:\n\n- Command-line flags with validation and help text\n- Environment variables with automatic binding\n- Configuration files (YAML, JSON, TOML)\n- Type validation with helpful error messages\n\n### 🎨 Beautiful, Organized Help Output\n\nOrganize your `--help` output into logical groups for better readability.\n\n```bash\n❯ go run examples/full/main.go --help\n# A demonstration of the structcli library with beautiful CLI features\n#\n# Usage:\n#   full [flags]\n#   full [command]\n#\n# Available Commands:\n#   completion  Generate the autocompletion script for the specified shell\n#   help        Help about any command\n#   srv         Start the server\n#   usr         User management\n#\n# Global Flags:\n#       --config string   config file (fallbacks to: {/etc/full,{executable_dir}/.full,$HOME/.full}/config.{yaml,json,toml})\n#       --debug-options   enable debug output for options\n#\n# Utility Flags:\n#       --dry-run\n#   -v, --verbose count\n```\n\n```bash\n❯ go run examples/full/main.go srv --help\n# Start the server with the specified configuration\n#\n# Usage:\n#   full srv [flags]\n#   full srv [command]\n#\n# Available Commands:\n#   version     Print version information\n#\n# Flags:\n#       --apikey string       API authentication key\n#       --host string         Server host (default \"localhost\")\n#   -p, --port int            Server port\n#       --target-env string   Set the target environment {dev,staging,prod} (default \"dev\")\n#\n# Database Flags:\n#       --database.maxconns int   Max database connections (default 10)\n#       --db-url string           Database connection URL\n#\n# Logging Flags:\n#       --log-file string           Log file path\n#       --log-level zapcore.Level   Set log level {debug,info,warn,error,dpanic,panic,fatal} (default info)\n#\n# Global Flags:\n#       --config string   config file (fallbacks to: {/etc/full,{executable_dir}/.full,$HOME/.full}/config.{yaml,json,toml})\n#       --debug-options   enable debug output for options\n#\n# Use \"full srv [command] --help\" for more information about a command.\n```\n\n## 🏷️ Available Struct Tags\n\nUse these tags in your struct fields to control the behavior:\n\n| Tag            | Description                                                                                                                             | Example                     |\n| -------------- | --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- |\n| `flag`         | Sets a custom name for the flag (otherwise, generated from the field name)                                                              | `flag:\"log-level\"`          |\n| `flagshort`    | Sets a single-character shorthand for the flag                                                                                          | `flagshort:\"l\"`             |\n| `flagdescr`    | Provides the help text for the flag                                                                                                     | `flagdescr:\"Logging level\"` |\n| `default`      | Sets the default value for the flag                                                                                                     | `default:\"info\"`            |\n| `flagenv`      | Enables binding to an environment variable (`\"true\"`/`\"false\"`)                                                                         | `flagenv:\"true\"`            |\n| `flagrequired` | Marks the flag as required (`\"true\"`/`\"false\"`)                                                                                         | `flagrequired:\"true\"`       |\n| `flaggroup`    | Assigns the flag to a group in the help message                                                                                         | `flaggroup:\"Database\"`      |\n| `flagignore`   | Skips creating a flag for this field (`\"true\"`/`\"false\"`)                                                                               | `flagignore:\"true\"`         |\n| `flagcustom`   | Uses a custom `Define\u003cFieldName\u003e` method for advanced flag creation and a custom `Decode\u003cFieldName\u003e` method for advanced value decoding | `flagcustom:\"true\"`         |\n| `flagtype`     | Specifies a special flag type. Currently supports `count`                                                                               | `flagtype:\"count\"`          |\n\n## 📖 Documentation\n\nFor comprehensive documentation and advanced usage patterns, visit the [documentation](https://pkg.go.dev/github.com/leodido/structcli).\n\nOr take a look at the [examples](examples/).\n\n## 🤝 Contributing\n\nContributions are welcome!\n\nPlease feel free to submit a Pull Request.\n","funding_links":["https://github.com/sponsors/leodido"],"categories":["Command Line","命令行","Build Automation"],"sub_categories":["Standard CLI","标准CLI"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleodido%2Fstructcli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleodido%2Fstructcli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleodido%2Fstructcli/lists"}