Claude-skill-registry go-options-gen
Expert in generating functional options for Go structs using the options-gen library.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/go-options-gen" ~/.claude/skills/majiayu000-claude-skill-registry-go-options-gen && rm -rf "$T"
manifest:
skills/data/go-options-gen/SKILL.mdsource content
go-options-gen
You are an expert in using the
options-gen library (https://github.com/kazhuravlev/options-gen) to create robust, type-safe functional options for Go components. You prioritize unexported option fields to maintain encapsulation while providing a clean, exported API for configuration.
Core Mandates
- File Naming:
- Single Option Set: Struct definition MUST be in
, and generated code MUST be inoptions.go
.options_generated.go - Multiple Option Sets: For a component named
, the struct (e.g.,MyService
) MUST be inMyServiceOptions
, and generated code MUST be inmyservice_options.go
.myservice_options_generated.go
- Single Option Set: Struct definition MUST be in
- Encapsulation:
- Options fields within the struct SHOULD be unexported (start with a lowercase letter) to prevent direct modification from outside the package.
- Tooling:
- Always run the tool using
.go tool options-gen - Install and track the tool in
using:go.modgo get -tool github.com/kazhuravlev/options-gen/cmd/options-gen@latest
- Always run the tool using
- Validation:
- Always include validation tags (using
syntax) for configuration fields.go-playground/validator - ALWAYS call the generated
method within the component's constructor.Validate()
- Always include validation tags (using
- Component Integration:
- Store the resulting options struct in an unexported field named
within your component struct.opts
- Store the resulting options struct in an unexported field named
Developer Workflow
-
Installation: Ensure the tool is tracked in your project:
go get -tool github.com/kazhuravlev/options-gen/cmd/options-gen@latest -
Define Options (
): Define your options struct with unexported fields. Use theoptions.go
directive to specify the output filename and the target struct.//go:generatepackage mypackage import "time" //go:generate go tool options-gen -from-struct=Options -out-filename=options_generated.go type Options struct { timeout time.Duration `option:"mandatory" validate:"required"` maxRetries int `default:"3" validate:"min=1"` endpoints []string `option:"variadic=true"` } -
Generate: Run the generator:
go generate ./options.go -
Integration: Use the generated types in your component's constructor and store them in an
field.optstype Component struct { opts Options } func New(setters ...OptionOptionsSetter) (*Component, error) { opts := NewOptions(setters...) if err := opts.Validate(); err != nil { return nil, fmt.Errorf("invalid options: %w", err) } return &Component{opts: opts}, nil }
Expert Guidance
Mandatory vs. Default
- Use
for fields that have no safe default (e.g., API keys, target URLs). These become required arguments inoption:"mandatory"
.NewOptions() - Use
for sensible defaults.default:"value"
supports basic types andoptions-gen
.time.Duration
Advanced Defaults
For complex types (like maps or nested structs), use
-defaults-from=func in the generate directive and define a provider function:
//go:generate go tool options-gen -from-struct=Options -out-filename=options_generated.go -defaults-from=func func defaultOptions() Options { return Options{ headers: map[string]string{"User-Agent": "my-client"}, } }
Validation Best Practices
- Use
for any field that must not be zero-valued.validate:"required" - Use
for enum-like string fields.validate:"oneof=tcp udp" - Use
for counters or sizes.validate:"min=1"
Variadic Setters
For slice fields, use
option:"variadic=true" to generate a setter that accepts multiple arguments (e.g., WithEndpoints("a", "b")) instead of a single slice (e.g., WithEndpoints([]string{"a", "b"})).
Avoiding Exported Fields
By keeping fields unexported in
options.go, you ensure that the only way to configure the component is through the generated With* setters, which can include validation logic.
Multiple Options in One Package
When a package contains multiple components (e.g.,
Client and Server), use prefixes to avoid name collisions in generated types and functions.
- Filenames: Use
and<prefix>_options.go
.<prefix>_options_generated.go - Generator Flag: Use
to prefix the generated-out-prefix
andNewOptions
types.Option...Setter
Example for
(MyService
):myservice_options.go
//go:generate go tool options-gen -from-struct=MyServiceOptions -out-filename=myservice_options_generated.go -out-prefix=MyService type MyServiceOptions struct { timeout time.Duration `option:"mandatory"` }
This will generate
NewMyServiceOptions and OptionMyServiceOptionsSetter, allowing them to coexist with other options in the same package.
Resources
- Examples: Complete implementations showing unexported fields, validation, and component integration can be found in the assets directory.