agentsclimarketplace

Configuration management

Skill ats4321/claude-engineering-skills/skills/configuration-management

26 repository-agnostic engineering skills for Claude Code — debugging, design, review, validation, and AI engineering as operational runbooks.

Install
npx -y skills add ats4321/claude-engineering-skills --skill configuration-management

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Discovering and designing configuration in any repo. Load when asking "where does this value come from?", when adding a new setting, when wiring env vars / .env files / CLI flags / config files, when deciding setting-vs-constant, or when handling secrets (tokens, webhook secrets, API keys). Covers config-source discovery and precedence, immutable/frozen settings objects, startup validation, .env.example documentation, secrets hygiene (never commit .env), and when NOT to add config at all.

SKILL.md

12.6 KB, as published. Nobody here has run it

Configuration Management

Purpose

Find every source of configuration in an unfamiliar repo, understand their precedence, and design new configuration that is discoverable, validated at startup, and immutable at runtime. The doctrine: a value becomes a setting only when someone will actually change it per-deployment — otherwise it is a constant, and constants are simpler.

When to Use / When NOT to Use

Use when:

  • You need to know where a runtime value comes from (env var? file? flag? hardcoded default?).
  • Adding, renaming, or re-defaulting any setting.
  • Touching secrets: tokens, webhook secrets, API keys, .env files.
  • Behavior differs between environments and you don't know why.
  • Designing config for a new service/CLI from scratch.

Do NOT use when:

  • The value never changes per-deployment → it's a constant; if you're tempted to make it configurable "for later", load engineering-minimalism instead.
  • The question is about dependency versions → load dependency-management.
  • The config controls the build/publish pipeline (dist-tags, package.json scripts) → load build-and-release.
  • The setting is a secret whose HANDLING (not location) is in question — e.g. how to validate a webhook secret → load security-review-playbook.
  • You're just getting oriented in a new repo → load codebase-onboarding first; come back here for the config layer.

Core Methodology

Step 1 — Inventory every config source

Search the repo for ALL of these, in order (see Discovery Commands):

  1. Environment variable reads (os.environ, os.getenv, process.env, env::var).
  2. Dotenv machinery (.env, .env.example, python-dotenv, dotenv imports).
  3. Config files (config.py, settings.py, config/, *.toml, *.yaml, *.json under repo root or config/).
  4. CLI flags (argparse/typer/click definitions, --flag handling, commander/yargs).
  5. Hardcoded defaults and paths (~/.appname/, literal hosts/ports, magic numbers near I/O).

Write the inventory down. A config source you didn't find is a debugging session you'll have later.

Step 2 — Determine precedence

Establish which source wins when two disagree. Typical (verify, never assume): CLI flag > env var > .env file > config file > hardcoded default. Confirm by reading the load order in the config module — e.g. does dotenv load before or after os.environ is read? Does the code use setdefault (env wins) or assignment (file wins)?

Step 3 — Decide: setting or constant?

Is the value ever different per deployment/user/environment?
├── NO, and no concrete request to change it → CONSTANT.
│   Hardcode it, name it, done. (No config for a value that never changes.)
├── NO, but it tunes behavior you expect to calibrate
│   (batch sizes, chunk limits, timeouts) → SETTING with a default.
│   Document the default in .env.example or --help.
├── YES, and it is NOT secret (hosts, model names, ports)
│   → SETTING via env var with a sane default; document in .env.example.
└── YES, and it IS secret (tokens, webhook secrets, keys)
    → SETTING via env var with NO default, NEVER committed.
    ├── Add the NAME (not value) to .env.example with a comment.
    ├── Ensure .env is in .gitignore.
    └── Decide startup behavior: fail-fast, or degrade gracefully
        with an explicit warning (see Step 5).

Also valid: NO config system at all. A ~700-line local tool with a hardcoded data path and two CLI flags needs zero env plumbing. Minimal config is a feature.

Step 4 — Make settings immutable and centralized

  1. One module owns config (e.g. config.py / config.ts). Everything else imports from it — no scattered os.getenv calls in business logic.
  2. Load once into a frozen structure: Python @dataclass(frozen=True) (add slots=True for small typed codebases), or Object.freeze / readonly types in TS.
  3. Expose via a singleton accessor (get_settings()); construct it at startup, not at import time of every consumer.
  4. Type every field. Parse strings into ints/bools/URLs at load time, not at use time.

Step 5 — Validate at startup

  • Required-and-missing → fail fast with a message naming the env var.
  • Optional-and-missing → either apply the documented default, or degrade gracefully with an explicit warning (e.g. "GITHUB_TOKEN missing: reviews will be computed but not posted") — never silently.
  • Malformed (non-numeric port, bad URL) → fail at startup, not on request N.

Step 6 — Secrets hygiene (non-negotiable)

  • .env (and any file with real secret values) is in .gitignore. Verify with git check-ignore .env.
  • .env.example exists, lists every variable NAME with placeholder values and comments (required scope/permissions, defaults).
  • No secret literal appears in source: grep for token, secret, key =, Bearer before every commit.
  • Secrets never logged; redact them in error messages and debug output.
  • History checked if a secret was EVER committed: git log -S "<VAR_NAME>" --oneline, then git show --stat on hits — avoid git log -p, which prints the secret value into your terminal/log again. If leaked, rotate the secret; deleting the file does not un-leak it.

New-setting checklist

  • Passed the Step 3 decision tree (state which branch).
  • Read in exactly one place (the config module), typed and defaulted there.
  • Documented in .env.example (or --help for flags) with its default.
  • Validated at startup (required → fail fast; optional → default or warn).
  • Settings object still frozen; no runtime mutation introduced.
  • If secret: no default, gitignored, name-only in .env.example.

Discovery Commands

# 1. Env var reads (Python / Node / Rust — adjust per repo language)
grep -rn "os.environ\|os.getenv" --include="*.py" .
grep -rn "process.env" --include="*.ts" --include="*.js" . | grep -v node_modules
grep -rn "env::var" --include="*.rs" .

# 2. Dotenv machinery and example files
ls -a .env .env.example .env.local 2>/dev/null
grep -rn "dotenv\|load_dotenv" --include="*.py" --include="*.ts" . | grep -v node_modules

# 3. Config files and modules
find . -maxdepth 2 \( -name "config*" -o -name "settings*" \) -not -path "*/node_modules/*" -not -path "*/.git/*"
ls config/ 2>/dev/null

# 4. CLI flags
grep -rn "add_argument\|typer.Option\|typer.Argument\|click.option" --include="*.py" .
grep -rn '"--' --include="*.js" --include="*.ts" . | grep -v node_modules | head -20

# 5. Hardcoded paths and hosts (defaults hiding as constants)
grep -rn "~/\.\|Path.home()\|os.path.expanduser\|homedir()" --include="*.py" --include="*.ts" --include="*.js" . | grep -v node_modules
grep -rn "localhost:\|127.0.0.1\|0.0.0.0" --include="*.py" --include="*.ts" . | grep -v node_modules

# Secrets hygiene checks
git check-ignore .env && echo "OK: .env ignored" || echo "DANGER: .env not ignored"
git log --all --oneline -- .env            # should print NOTHING
grep -rliE "api[_-]?key|secret|token" --include="*.py" --include="*.ts" . | grep -v node_modules   # -l: FILENAMES only — never print matched secret values into logs; open flagged files and inspect by eye

Failure Modes & Anti-patterns

SymptomMistakeCorrection
"Works in dev, broken in prod"Undocumented config source; precedence never establishedRun the Step 1 inventory; write down the precedence order; document every var in .env.example.
Secret in git historyCommitting .env "just once" or a token literalGitignore .env BEFORE creating it; if leaked, rotate the secret — deletion is not revocation.
Crash on request N, hours after bootConfig parsed lazily at point of useValidate and type-convert ALL config at startup (Step 5).
os.getenv scattered across 12 filesNo single config ownerCentralize into one frozen settings module; everything imports from it.
Setting nobody has ever changedConfig added "for flexibility"Setting-vs-constant tree (Step 3): no per-deployment variation and no request → constant. Delete the knob.
Service silently does nothing when token missingMissing-secret path unhandled or silentFail fast for required secrets; for optional ones, warn explicitly and degrade visibly.
Test mutates settings, later tests flakeMutable global settings objectFrozen dataclass / Object.freeze; tests construct their own instance.
New contributor can't boot the app.env.example missing or stale.env.example is the setup contract: every var name, placeholder, comment, default.

Repository Examples

prism — the full config pattern (as of 2026-07-04)

~/prism: Python 3.10+ FastAPI self-hosted AI PR reviewer on local Ollama. Config is centralized in prism/config.py: python-dotenv loads .env, values land in a frozen dataclass Settings exposed through a get_settings() singleton — Steps 4–5 exactly. .env.example documents every variable:

  • GITHUB_TOKEN — PAT with pull_requests:write (secret, no default; when missing the app warns and skips the API call — graceful degradation, not silence)
  • GITHUB_WEBHOOK_SECRET — secret, used for HMAC validation
  • OLLAMA_HOST — default http://localhost:11434
  • OLLAMA_MODEL — default llama3.2
  • MAX_FILES_PER_PR — default 10; MAX_LINES_PER_CHUNK — default 120: deliberately settings, not constants, because they tune review behavior per deployment (Step 3, "calibration" branch)

Contrast within the same repo: the GitHub API version is pinned as a hardcoded header value "2022-11-28" — a constant, because it changes with code (API compatibility), not with deployment. Entry point prism = "prism.server:run" boots uvicorn on 0.0.0.0:8000.

agentix — zero-config as a valid design (as of 2026-07-04)

~/agentix: ~700-line local ReAct agent framework. NO env vars, NO config files. Storage path is hardcoded (~/.agentix/memory.db); the only knobs are CLI flags (--context-window, --model). For a single-user local tool this is the correct amount of configuration: the Step 3 tree resolves almost everything to "constant" or "CLI flag". Minimalism doctrine applied to config itself.

ragit — derived path convention (as of 2026-07-04)

~/ragit stores its index at ~/.ragit/<sha256-prefix>/ — a hardcoded convention (constant), not a setting. No one asked to relocate it, so no knob exists.

Validation Criteria

You applied this skill correctly if:

  1. You can list every config source in the repo and state their precedence, backed by the load-order code, not guesses.
  2. Every setting you added appears in .env.example (or --help) with its default, and is read in exactly one module.
  3. The app fails at startup — with a variable-named message — when a required setting is missing or malformed.
  4. git check-ignore .env passes and git log --all -- .env is empty.
  5. For each new knob, you can name the Step 3 branch that justified it; anything on the "constant" branch has no knob.

Provenance & Maintenance

  • Sources: ~/prism, ~/agentix, ~/ragit — investigated 2026-07-04. prism and agentix directories were read-restricted during authoring; their facts come from the 2026-07-04 verified fact pack ("verified 2026-07-04, not re-read"). ragit was partially re-read this session.
  • Assumptions: prism's precedence (dotenv → frozen Settings) inferred from the verified description of prism/config.py; exact load-order nuances (e.g. whether real env vars override .env) were not re-read — "(hypothesis — requires verification)".
  • Re-verification commands:
    cat ~/prism/.env.example
    grep -n "frozen\|load_dotenv\|get_settings" ~/prism/prism/config.py
    grep -rn "getenv\|environ" ~/agentix --include="*.py"   # expect ~zero hits
    grep -rn "\.ragit" ~/ragit/ragit --include="*.py"
    
  • Likely to drift: prism's default values (MAX_FILES_PER_PR, OLLAMA_MODEL); agentix may grow env-var config if it ever needs per-deployment variation; the pinned GitHub API version header.
  • Maintenance checklist: re-run re-verification; confirm .env.example in prism still matches Settings fields one-to-one; confirm agentix is still zero-config before citing it; update defaults quoted here if they change.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.