Golang Spf13 ViperSAFE
π§π¨ A collection of Golang agentic skills that works
Overview
π§π¨ A collection of Golang agentic skills that works
3823d8ae0038OBSERVED Β· 2026-10-08Host compatibility
What the documentation claims. We have not run a compatibility test.
| Host | Status | Notes |
|---|---|---|
| claude-code | mentioned | |
| codex | mentioned | |
| openclaw | mentioned |
What it tells the agent
The instruction file, verbatim from the audited commit β this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.
---
name: golang-spf13-viper
description: "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 alongside viper, see the `samber/cc-skills-golang@golang-spf13-cobra` skill. For general CLI architecture, see `samber/cc-skills-golang@golang-cli`."
user-invocable: true
license: MIT
compatibility: Designed for Claude Code, Codex or similar harness, and for projects using Golang.
metadata:
author: samber
version: "1.1.2"
openclaw:
emoji: "π§"
homepage: https://github.com/samber/cc-skills-golang
requires:
bins:
- go
install: []
skill-library-version: "1.21.0"
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent WebFetch mcp__context7__resolve-library-id mcp__context7__query-docs Bash(godig:*) Bash(gopls:*) LSP mcp__gopls__*
paths:
- "**/*.go"
---
**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:**
- [pkg.go.dev/github.com/spf13/viper](https://pkg.go.dev/github.com/spf13/viper)
- [github.com/spf13/viper](https://github.com/spf13/viper)
This skill is not exhaustive β 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`), preferred 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.
```bash
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, with no user-facing surface of its own: it is purely a key-value resolver.
- **Cobra alone** β flag-only CLIs.
- **Viper alone** β config-file daemons.
- **Both** β bind 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
```go
viper.SetConfigName("config")
viper.AddConfigPath("$HOME/.myapp")
if err := viper.ReadInConfig(); err != nil {
var notFound *viper.ConfigFileNotFoundError
if !errors.As(err, ¬Found) {
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](references/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:
```go
// β 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](references/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):
```go
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](references/binding-and-env.md).
## Unmarshaling into structs
`viper.Unmarshal` maps the resolved configuration into a struct using `mapstructure`:
```go
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)
`Trust audit
SAFEgrade B Β· trust 89/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | NA |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- none-observed
- Network
- none-observed
- Shell
- none-observed
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (1)
viper.AddRemoteProvider("etcd3", "http://127.0.0.1:2379", "/config/myapp.yaml")Gates applied: no_behavioural_pass.
3823d8ae0038full audit observations/trust-audit/skill/samber__golang-spf13-viper.json Β· Report an issue / request a re-scanAudit history
Every audit this skill has had.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-08 | 3823d8ae0038 | SAFE | B | 89 | first audit |
Questions
What does the Golang Spf13 Viper skill do?
π§π¨ A collection of Golang agentic skills that works
Is Golang Spf13 Viper safe to install?
The audit found nothing in the source that contradicts what it says it does, and graded it B (89/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean skill reads B.
What can Golang Spf13 Viper access on my machine?
The audit observed no filesystem, network or shell use at all in its source.
Which assistants does Golang Spf13 Viper work with?
Its documentation mentions claude-code, codex and openclaw. That is what the text claims, not a compatibility test we ran.
How current is this page?
The grade is for one exact copy of the source (3823d8ae0038), read on 2026-10-08. The repository is watched, and a new audit runs when it changes β this is the first audit.