
Golang Spf13 Viper
Apply spf13/viper patterns in Go services so env vars, nested keys, and sub-config trees behave correctly in production.
Overview
golang-spf13-viper is an agent skill for the Build phase that teaches correct spf13/viper env mapping, nested keys, and Sub() nil-handling in Go services.
Install
npx skills add https://github.com/samber/cc-skills-golang --skill golang-spf13-viperWhat is this skill?
- Diagnoses missing SetEnvKeyReplacer when dotted keys (e.g. database.host) fail under APP_ prefix + AutomaticEnv
- Documents full stack: env prefix, replacer, and AutomaticEnv together
- Covers viper.Sub() returning nil for missing keys and mandatory nil checks
- Steers away from renaming config keys to dodge dots when replacer is the fix
- Eval-oriented traps mirror real production misreads of env var names
- Eval scenarios include env-key-replacer-nested-keys and sub-returns-nil assertion suites
Adoption & trust: 1.9k installs on skills.sh; 2k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your Go service reads defaults while env vars look set because dotted Viper keys do not map to the underscore names your platform exports.
Who is it for?
Indie Go backend developers debugging env override issues or structuring shared config packages with nested keys.
Skip if: Greenfield projects standardizing on Koanf, envconfig only, or platforms where Viper is not in the stack.
When should I use this skill?
When debugging or implementing Viper in Go: env overrides for dotted keys, env prefix, AutomaticEnv, or Sub() nil behavior.
What do I get? / Deliverables
You get the correct prefix, AutomaticEnv, SetEnvKeyReplacer, and nil-safe Sub() usage so nested config resolves from the environment as intended.
- Correct Viper init snippet (prefix, replacer, AutomaticEnv)
- Nil-safe Sub() access pattern
- Explanation of env var name Viper actually looks up
Recommended Skills
Journey fit
Configuration loading is core backend build work before ship—errors here surface as silent misconfig in operate. Backend subphase covers service config, twelve-factor env mapping, and library-specific footguns like Sub() nil returns.
How it compares
Use for Viper-specific Go fixes instead of generic "read os.Getenv in main" snippets that ignore nested key semantics.
Common Questions / FAQ
Who is golang-spf13-viper for?
Solo builders and small teams maintaining Go services or CLIs that already depend on github.com/spf13/viper for configuration.
When should I use golang-spf13-viper?
Use it in Build/backend work when env vars with APP_DATABASE_HOST style names fail against database.host keys, or when Sub() returns unexpected nil subtrees.
Is golang-spf13-viper safe to install?
It guides code changes only; review the Security Audits panel on this page and treat third-party skill packages like any dependency you vet before agent write access.
SKILL.md
READMESKILL.md - Golang Spf13 Viper
[ { "id": 1, "name": "env-key-replacer-nested-keys", "description": "Tests SetEnvKeyReplacer for nested keys with dots mapping to underscore env vars", "prompt": "I'm using viper in my Go service. I have a config key 'database.host' that should be configurable via an env var. I've set AutomaticEnv() and SetEnvPrefix('APP'). My env var APP_DATABASE_HOST is set but viper returns the default. What's wrong?", "trap": "Without the skill, the model may suggest checking the env var name, case sensitivity, or re-reading the config. The root cause is the missing SetEnvKeyReplacer — viper looks for APP_DATABASE.HOST (dot preserved), not APP_DATABASE_HOST.", "assertions": [ { "id": "1.1", "text": "Identifies the root cause as missing SetEnvKeyReplacer" }, { "id": "1.2", "text": "Explains that viper preserves the dot in 'database.host' when looking up the env var" }, { "id": "1.3", "text": "Provides the fix: viper.SetEnvKeyReplacer(strings.NewReplacer(\".\", \"_\"))" }, { "id": "1.4", "text": "Shows that the full setup requires prefix + replacer + AutomaticEnv together" }, { "id": "1.5", "text": "Does NOT suggest renaming the config key to avoid dots" } ] }, { "id": 2, "name": "sub-returns-nil", "description": "Tests that viper.Sub() returns nil when the key doesn't exist and must be nil-checked", "prompt": "I'm using viper.Sub('database') in my Go service to get a sub-viper for database config, then calling sub.Unmarshal(&dbCfg). Occasionally the service panics with a nil pointer dereference. What's happening?", "trap": "Without the skill, the model may suggest checking the config file format or adding error handling to Unmarshal. The root cause is Sub() returning nil when the 'database' key doesn't exist, and nil.Unmarshal panics.", "assertions": [ { "id": "2.1", "text": "Identifies that viper.Sub() returns nil when the key doesn't exist" }, { "id": "2.2", "text": "Shows adding a nil check: if sub := viper.Sub(\"database\"); sub != nil { ... }" }, { "id": "2.3", "text": "Suggests returning a clear error or using defaults when sub is nil" }, { "id": "2.4", "text": "Does NOT suggest checking err from Sub() (it returns no error, only nil)" }, { "id": "2.5", "text": "Optionally suggests UnmarshalKey(\"database\", &dbCfg) as an alternative that avoids Sub() entirely" } ] }, { "id": 3, "name": "config-file-not-found-graceful", "description": "Tests graceful handling of ConfigFileNotFoundError for optional config files", "prompt": "My Go service uses viper to read a config file. When users run it without a config file, it crashes with 'Config File config not found in ...'. The config file should be optional. How do I fix this?", "trap": "Without the skill, the model may suggest pre-checking if the file exists before calling ReadInConfig, or using os.Stat. The correct pattern is errors.As with viper.ConfigFileNotFoundError.", "assertions": [ { "id": "3.1", "text": "Uses errors.As(err, ¬Found) with *viper.ConfigFileNotFoundError" }, { "id": "3.2", "text": "Only propagates errors that are NOT ConfigFileNotFoundError" }, { "id": "3.3", "text": "Continues execution normally when the config file is not found" }, { "id": "3.4", "text": "Does NOT use os.Stat or file existence check as the solution" }, { "id": "3.5", "text": "Does NOT ignore all errors from ReadInConfig (real errors like bad YAML should still propagate)" } ] }, { "id": 4, "name": "global-viper-test-pollution", "description": "Tests viper.New() for test isolation