This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Build & Test Commands
This project uses the Core CLI (`core` binary), not `go` directly.
```bash
core go test # run all tests
core go test --run TestConfig_Get_Good # run a single test
core go cov # test with coverage
core go cov --open # coverage + open HTML report
core go qa # format, vet, lint, test
core go qa full # adds race detector, vuln scan, security audit
core go fmt # format
core go vet # vet
core go lint # lint
```
This is a library package — there is no binary to build or run.
## Architecture
**Dual-Viper pattern**: `Config` holds two `*viper.Viper` instances:
-`v` (full) — file + env + defaults; used for all reads (`Get`, `All`)
-`f` (file-only) — file + explicit `Set()` calls; used for persistence (`Commit`)
This prevents environment variables from leaking into saved config files. When implementing new features, maintain this invariant: writes go to both `v` and `f`; reads come from `v`; persistence comes from `f`.
**Service wrapper**: `Service` in `service.go` wraps `Config` with framework lifecycle (`core.Startable`). Both `Config` and `Service` satisfy `core.Config`, enforced by compile-time assertions.
**Storage abstraction**: All file I/O goes through `coreio.Medium` (from `go-io`). Tests use `coreio.NewMockMedium()` with an in-memory `Files` map — never touch the real filesystem.