Source profileQuality 91/100Review permissions

samber/cc-skills-golang/skills/golang-spf13-viper/SKILL.md

golang-spf13-viper

Golang configuration library using spf13/viper — layered precedence (flag > env > file > KV > default), BindPFlag/BindPFlags, SetEnvPrefix + SetEnvKeyReplacer + AutomaticEnv, ReadInConfig + ConfigFileNotFoundError, Unmarshal + mapstructure struct tags, Sub for sub-trees, WatchConfig + OnConfigChange for hot reload, viper.New() for test isolation, and remote KV integration. Apply when using or adopting spf13/viper, or when the codebase imports `github.com/spf13/viper`. For CLI command structure a

Source repository stars
3,074
Declared platforms
2
Static risk flags
2
Last source update
2026-08-23
Source checked
2026-08-26

Decision brief

What it does: where it fits

Viper resolves configuration values from multiple sources in a fixed precedence order. It has no user-facing surface — it doesn't define commands or flags. Its job is to answer "what is the value of key X right now?" by walking its source layers from highest to lowest priority.

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexDeclaredSource recordInstall path and trigger
    Claude CodeDeclaredSource recordInstall path and trigger
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/samber/cc-skills-golang --skill "skills/golang-spf13-viper"
    Safe inspection promptEditorial

    Inspect the Agent Skill "golang-spf13-viper" from https://github.com/samber/cc-skills-golang/blob/a18860b303ef1d3d928f9670631e03210b8698bf/skills/golang-spf13-viper/SKILL.md at commit a18860b303ef1d3d928f9670631e03210b8698bf. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Viper vs. cobra

      Cobra owns the command tree — subcommands, flags, arg validation, completions. Viper owns configuration resolution — it answers "what is the value of key X?" by walking its source layers. Viper has no user-facing surface; it is purely a key-value resolver. Use cobra alone for fl…

      Cobra owns the command tree — subcommands, flags, arg validation, completions. Viper owns configuration resolution — it answers "what is the value of key X?" by walking its source layers. Viper has no user-facing surfac…→ See samber/cc-skills-golang@golang-spf13-cobra for the cobra side of this integration.
    2. 02

      The precedence pipeline

      Viper resolves a key by walking sources in this order (first set value wins):

      Viper resolves a key by walking sources in this order (first set value wins):This pipeline is fixed and cannot be reordered. Understanding it prevents most viper bugs: a key that "should" come from a config file may be shadowed by an env var or a flag with a default value.
    3. 03

      Sources and config files

      ConfigFileNotFoundError must be handled gracefully — config files are usually optional. An unhandled error from a missing file crashes programs that are perfectly valid when run with only flags or env vars.

      ConfigFileNotFoundError must be handled gracefully — config files are usually optional. An unhandled error from a missing file crashes programs that are perfectly valid when run with only flags or env vars.For supported formats (JSON, TOML, YAML, HCL, INI, properties), MergeInConfig, and remote KV, see sources-and-formats.md.
    4. 04

      Env binding and key replacers

      This is the highest-bug-density area in viper. All three settings must be wired together — missing any one breaks nested key resolution:

      This is the highest-bug-density area in viper. All three settings must be wired together — missing any one breaks nested key resolution:For BindEnv, AllowEmptyEnv, and env-vs-default interaction, see binding-and-env.md.
    5. 05

      Flag binding (the cobra seam)

      Bind cobra flags to viper in init() or PersistentPreRunE — never in RunE (config loading in PersistentPreRunE already ran before RunE, so bindings set in RunE are missed):

      Bind cobra flags to viper in init() or PersistentPreRunE — never in RunE (config loading in PersistentPreRunE already ran before RunE, so bindings set in RunE are missed):For AllowEmptyEnv and flag/env interaction details, see binding-and-env.md.

    Permission review

    Static risk signals and limitations

    Runs scripts

    medium · line 15

    The documentation asks the agent to run terminal commands or scripts.

    go get github.com/spf13/viper@latest

    Network access

    medium · line 148

    The documentation includes network, browsing, or remote request actions.

    [sources-and-formats.md](references/sources-and-formats.md) — supported file formats, multi-path search, MergeInConfig, remote KV (etcd/Consul)

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score91/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars3,074SourceRepository attention, not individual Skill quality
    Compatibility2 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    samber/cc-skills-golang
    Skill path
    skills/golang-spf13-viper/SKILL.md
    Commit
    a18860b303ef1d3d928f9670631e03210b8698bf
    License
    MIT
    Collected
    2026-08-26
    Default branch
    main
    View the original SKILL.md

    Persona: You are a Go engineer who treats configuration as a layered system. Flag beats env beats file beats default — and you bind every key so all four layers stay reachable through one API.

    Using spf13/viper for layered configuration in Go

    Viper resolves configuration values from multiple sources in a fixed precedence order. It has no user-facing surface — it doesn't define commands or flags. Its job is to answer "what is the value of key X right now?" by walking its source layers from highest to lowest priority.

    Official Resources:

    This skill is not exhaustive. Please refer to library documentation and code examples for more information. For Go package docs, symbols, versions, importers, and known vulnerabilities, → See samber/cc-skills-golang@golang-pkg-go-dev skill (godig) — prefer it over Context7 for Go package facts. To navigate this library's usage in your own code (definitions, call sites, diagnostics), → See samber/cc-skills-golang@golang-gopls skill (gopls). Context7 remains a fallback for docs not indexed on pkg.go.dev.

    go get github.com/spf13/viper@latest
    

    Viper vs. cobra

    Cobra owns the command tree — subcommands, flags, arg validation, completions. Viper owns configuration resolution — it answers "what is the value of key X?" by walking its source layers. Viper has no user-facing surface; it is purely a key-value resolver. Use cobra alone for flag-only CLIs; viper alone for config-file daemons; both when you need both, binding flags at PersistentPreRunE via BindPFlag.

    → See samber/cc-skills-golang@golang-spf13-cobra for the cobra side of this integration.

    The precedence pipeline

    Viper resolves a key by walking sources in this order (first set value wins):

    1. explicit Set()      — viper.Set("key", val)    highest priority
    2. flag                — bound pflag.Flag
    3. env var             — BindEnv / AutomaticEnv
    4. config file         — ReadInConfig / MergeInConfig
    5. KV remote           — etcd / Consul
    6. default             — viper.SetDefault("key", val)   lowest priority
    

    This pipeline is fixed and cannot be reordered. Understanding it prevents most viper bugs: a key that "should" come from a config file may be shadowed by an env var or a flag with a default value.

    Sources and config files

    viper.SetConfigName("config")
    viper.AddConfigPath("$HOME/.myapp")
    if err := viper.ReadInConfig(); err != nil {
        var notFound *viper.ConfigFileNotFoundError
        if !errors.As(err, &notFound) {
            return fmt.Errorf("reading config: %w", err) // propagate real errors only
        }
    }
    

    ConfigFileNotFoundError must be handled gracefully — config files are usually optional. An unhandled error from a missing file crashes programs that are perfectly valid when run with only flags or env vars.

    For supported formats (JSON, TOML, YAML, HCL, INI, properties), MergeInConfig, and remote KV, see sources-and-formats.md.

    Env binding and key replacers

    This is the highest-bug-density area in viper. All three settings must be wired together — missing any one breaks nested key resolution:

    // ✓ Good — all three wired together at startup
    viper.SetEnvPrefix("MYAPP")                             // prevent collisions: PORT → MYAPP_PORT
    viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))  // database.host → MYAPP_DATABASE_HOST
    viper.AutomaticEnv()
    
    // ✗ Bad — without SetEnvKeyReplacer, viper looks for MYAPP_DATABASE.HOST (dot preserved)
    

    For BindEnv, AllowEmptyEnv, and env-vs-default interaction, see binding-and-env.md.

    Flag binding (the cobra seam)

    Bind cobra flags to viper in init() or PersistentPreRunE — never in RunE (config loading in PersistentPreRunE already ran before RunE, so bindings set in RunE are missed):

    func init() {
        rootCmd.PersistentFlags().Int("port", 8080, "listen port")
        viper.BindPFlag("port", rootCmd.PersistentFlags().Lookup("port"))
        // viper.BindPFlags(cmd.Flags()) — bind an entire FlagSet at once
    }
    

    For AllowEmptyEnv and flag/env interaction details, see binding-and-env.md.

    Unmarshaling into structs

    viper.Unmarshal maps the resolved configuration into a struct using mapstructure:

    type Config struct {
        Port     int `mapstructure:"port"`
        Database struct {
            MaxConn int `mapstructure:"max_conn"` // explicit tag: mapstructure won't convert underscore→camelCase
        } `mapstructure:"database"`
    }
    var cfg Config
    viper.Unmarshal(&cfg)
    

    Always use mapstructure tags — implicit mapping is fragile for nested structs and underscore-named fields. Prefer UnmarshalKey("database", &dbCfg) over Sub("database").Unmarshal — it avoids the nil-check Sub requires when the key is missing.

    For time.Duration / net.IP / slice decoders and custom DecodeHook registration, see unmarshal.md.

    Sub-trees

    viper.Sub("database") returns a new *viper.Viper scoped to the prefix, or nil if the key does not exist — always nil-check before calling methods on the result. Prefer UnmarshalKey("database", &dbCfg) which avoids the nil risk entirely.

    Hot reload

    viper.WatchConfig()
    viper.OnConfigChange(func(e fsnotify.Event) { /* re-apply changed values */ })
    

    WatchConfig uses fsnotify and watches inodes. Editors that write atomically via rename (vim, neovim) replace the inode — the callback may not fire. Test hot-reload with echo >> config.yaml, not editor saves. For race-safe reload patterns, see watch-and-reload.md.

    Test isolation

    Never use the global viper in tests — state leaks across test cases. Use viper.New() per test so each instance is isolated:

    v := viper.New()
    v.SetConfigFile("testdata/config.yaml")
    require.NoError(t, v.ReadInConfig())
    

    For t.Setenv interactions and Reset() limitations, see testing-and-isolation.md.

    Best Practices

    1. Set prefix + key replacer + AutomaticEnv together — missing any one causes nested env keys to silently not resolve (database.hostDATABASE.HOST instead of DATABASE_HOST).
    2. Handle ConfigFileNotFoundError gracefully — a missing config file should not crash a service that runs with only flags and env vars.
    3. Always use mapstructure tags on config structs — implicit mapping silently misses nested and underscore-named fields.
    4. Use viper.New() in tests, never the global — the global accumulates state across test runs; per-test instances are isolated.
    5. Bind flags before Execute() — binding in RunE is too late; cobra parses flags before RunE runs.

    Common Mistakes

    MistakeWhy it failsFix
    AutomaticEnv without SetEnvKeyReplacerdatabase.host looks for MYAPP_DATABASE.HOST (dot preserved) — never matchesAdd SetEnvKeyReplacer(strings.NewReplacer(".", "_")) before AutomaticEnv
    No mapstructure tags on struct fieldsSilently misses nested and underscore-named fieldsAdd mapstructure:"key_name" to every field
    Using global viper in testsState from one test contaminates the next, causing flaky orderingCreate viper.New() per test
    Missing ConfigFileNotFoundError checkMissing config file crashes a service that should run on flags/env aloneerrors.As(err, &notFound) — only propagate non-not-found errors

    Further Reading

    • sources-and-formats.md — supported file formats, multi-path search, MergeInConfig, remote KV (etcd/Consul)
    • binding-and-env.md — BindEnv, AutomaticEnv, SetEnvPrefix, SetEnvKeyReplacer, AllowEmptyEnv, timing rules
    • unmarshal.md — Unmarshal, UnmarshalKey, mapstructure tags, custom DecodeHooks (Duration, IP, slice)
    • watch-and-reload.md — WatchConfig, OnConfigChange, fsnotify caveats, atomic-rename trap, race-safe patterns
    • testing-and-isolation.md — viper.New() per test, t.Setenv interactions, Reset() limitations, snapshot/restore

    Cross-References

    • → See samber/cc-skills-golang@golang-cli skill for general CLI architecture — project layout, exit codes, signal handling, cobra+viper integration
    • → See samber/cc-skills-golang@golang-spf13-cobra skill for the cobra side of this integration (flag definition and binding)
    • → See samber/cc-skills-golang@golang-testing skill for general Go testing patterns

    If you encounter a bug or unexpected behavior in spf13/viper, open an issue at https://github.com/spf13/viper/issues.

    Frequently asked questions

    What to verify before installation and use

    What does the golang-spf13-viper source document cover?

    Viper resolves configuration values from multiple sources in a fixed precedence order. It has no user-facing surface — it doesn't define commands or flags. Its job is to answer "what is the value of key X right now?" by walking its source layers from highest to lowest priority.

    How do I install golang-spf13-viper?

    The source record exposes this install command: npx skills add https://github.com/samber/cc-skills-golang --skill "skills/golang-spf13-viper". Inspect the command and pinned source before running it.

    Which Agent platforms does the source record declare?

    The pinned source record declares support for: codex, claude code.

    Which permission-related actions were detected?

    Static rules flagged exec-script, network in the source; the page lists the matching lines and excerpts.

    Alternatives

    Compare before choosing

    Computed 9981

    vasilyu1983/AI-Agents-public

    qa-testing-ios

    Guides iOS testing with XCTest, XCUITest, Swift Testing, simctl, and xcresult. Use when choosing destinations, controlling flakes, or parsing test artifacts for native apps.

    Computed 973,074

    samber/cc-skills-golang

    golang-testing

    Production-ready Golang tests — table-driven tests, testify suites and mocks, parallel tests, fuzzing, fixtures, goroutine leak detection with goleak, snapshot testing, code coverage, integration tests, idiomatic test naming. Use when writing or reviewing Go tests, choosing a testing approach, setting up Go test CI, or debugging flaky/slow tests. For testify-specific APIs see `samber/cc-skills-golang@golang-stretchr-testify`; for measurement methodology see `samber/cc-skills-golang@golang-benchm

    Computed 973,074

    samber/cc-skills-golang

    golang-troubleshooting

    Troubleshoot Golang programs systematically - find and fix the root cause. Use when encountering bugs, crashes, deadlocks, or unexpected behavior in Go code. Covers debugging methodology, common Go pitfalls, test-driven debugging, pprof setup and capture, Delve debugger, race detection, GODEBUG tracing, and production debugging. Start here for any 'something is wrong' situation. Not for interpreting profiles or benchmarking (→ See `samber/cc-skills-golang@golang-benchmark` skill) or applying opt

    Computed 973,074

    samber/cc-skills-golang

    golang-uber-fx

    Golang application framework using uber-go/fx — fx.New, fx.Provide, fx.Invoke, fx.Module, fx.Lifecycle hooks, fx.Annotate (name/group/As), fx.Decorate, fx.Supply, fx.Replace, fx.WithLogger, and signal-aware Run(). Apply when using or adopting uber-go/fx, when the codebase imports `go.uber.org/fx`, or when wiring services with fx.New. For raw DI without lifecycle, see `samber/cc-skills-golang@golang-uber-dig` skill.