env-audit
Skill7 starsChanged 27 days agoMITView on GitHub
Environment variable and configuration audit. 8 dimensions (ENV1-ENV8): variable completeness, unused vars, startup validation, secret exposure, environment parity, type safety, default values, and documentation. Supports Node.js (.env/process.env), Python (os.environ/settings), and framework-specific patterns (Vite import.meta.env, Next.js NEXT_PUBLIC_). Switches: zuvo:env-audit full | [path] | --secrets-only | --parity
- Reads credentials
2 other projects use a version of this.
Adopted by
Most recently taken up by
- latuconsinafr/claude-code-configtheir own version, first seen Oct 13, 2026
- aemerson-commits/shareable-skillstheir own version, first seen Mar 30, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- aemerson-commits/shareable-skills★ 1same name
- latuconsinafr/claude-code-config★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository58 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- a11y-auditSkill
- agent-benchmarkSkill
- api-auditSkill
- architectureSkill
- backlogSkill
- benchmarkSkill
- brainstormSkill
- buildSkill
- canarySkill
- ci-auditSkill
- code-auditSkill
- container-auditSkill
- content-auditSkill
- content-expandSkill
- content-fixSkill
- content-migrationSkill
- context-auditSkill
- db-auditSkill
- debugSkill
- dependency-auditSkill
- deploySkill
- design-reviewSkill
- designSkill
- docsSkill
- executeSkill
- fix-testsSkill
- geo-auditSkill
- geo-fixSkill
- incidentSkill
- infra-auditSkill
- leadsSkill
- mutation-testSkill
- pentestSkill
- performance-auditSkill
- planSkill
- presentationSkill
- profile-sessionSkill
- receive-reviewSkill
- refactor-radarSkill
- refactorSkill
- release-docsSkill
- retroSkill
- reviewSkill
- security-auditSkill
- seo-auditSkill
- seo-fixSkill
- shipSkill
- skill-evalSkill
- structure-auditSkill
- test-auditSkill
- tests-performanceSkill
- ui-design-teamSkill
- using-zuvoSkill
- worktreeSkill
- write-articleSkill
- write-e2eSkill
- write-testsSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
19 rules. About 0 are common, 7 are distinctive, and 12 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈7
Distinctive · estimate
This author's own choices. Worth a look.
12
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 56
When to use: After adding new env vars, before production deploy, when debugging config-related incidents, onboarding new environments, …
- Distinctive: line 63
Read every file below before starting.
- Distinctive: line 73
If any file is MISSING, STOP.
- Distinctive: line 101
When including env var values in the report:
- Very specific: line 128
Use the deterministic preload helper FIRST: Run ~/.zuvo/compute-preload env-audit "$PWD".
- Very specific: line 206
Detection approach: Check each var in .env.example against code access patterns.
- Very specific: line 240
Check .gitignore for .env patterns
- Very specific: line 242
Search for NEXT_PUBLIC_*KEY, NEXT_PUBLIC_*SECRET, VITE_*KEY etc.
- Very specific: line 243
Search for hardcoded secrets: (api_key|secret|password|token)\s*[:=]\s*['"][^'"{}$] excluding test/mock/example files
- Very specific: line 245
Check .dockerignore for .env
- Very specific: line 285
Search for ?? and || operators after env access (Node.js)
- Very specific: line 286
Search for os.getenv('VAR', 'default') patterns (Python)
- Distinctive: line 406
No actual secret values appear anywhere in the report (Gate 2)
- Very specific: line 451
If gate_status = FAIL → VERDICT = INCOMPLETE.
- Distinctive: line 459
Run: <ISO-8601-Z> env-audit <project> <N-critical> <N-total> <VERDICT> - <N>-dimensions <NOTES> <BRANCH> <SHA7> <INCLUDES> <TIER>
- Very specific: line 464
Follow the retrospective protocol from retrospective.md.
- Distinctive: line 466
If gate check skips: print "RETRO: skipped (trivial session)" and proceed.
- Very specific: line 468
After printing this block, append the Run: line value (without the Run: prefix) to the log file path resolved per run-logger.md.
- Very specific: line 477
All commands use the resolved TARGET_ROOT from argument parsing
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
zuvo:env-audit
Audit environment variable management for completeness, safety, and consistency across development, staging, and production environments. Single-pass execution.
When to use: After adding new env vars, before production deploy, when
debugging config-related incidents, onboarding new environments, periodic check.
When NOT to use: Secret scanning in source code (/security-audit), CI
pipeline config (zuvo:ci-audit), infrastructure (/security-audit).
Mandatory File Loading
Read every file below before starting. Print the checklist.
CORE FILES LOADED:
1. ../../shared/includes/codesift-setup.md -- [READ | MISSING -> STOP]
2. ../../shared/includes/env-compat.md -- [READ | MISSING -> STOP]
3. ../../shared/includes/run-logger.md -- [READ | MISSING -> STOP]
4. ../../shared/includes/retrospective.md -- [READ | MISSING -> STOP]If any file is MISSING, STOP. Do not proceed from memory.
Argument Parsing
| Token | Behavior |
(empty) or full | All 8 dimensions, scope = project root |
[path] | Scope to a directory (monorepo package, module) |
--secrets-only | ENV4 only -- focus on secret exposure |
--parity | ENV5 only -- compare environment configurations |
Safety Gates
GATE 1 -- Read-Only
This audit is read-only. The only write target is zuvo/audits/.
FORBIDDEN:
- Modifying any
.env, config, or source file - Creating or deleting environment variables
- Accessing external secret managers (analyze config references only)
GATE 2 -- PII and Secret Censorship
When including env var values in the report:
- Replace actual values with
*** - Show only variable names, never values
- Exception:
.env.exampleplaceholder values can be shown as-is
MANDATORY TOOL CALLS — Env Audit Validity Gate
INVALID if any tool below is skipped. "DEFERRED", "N/A", "--secrets-only" NOT valid reasons.
| Tool | Trigger | Skip allowed? |
scan_secrets | Always | NO — KEY: ENV4 secret exposure |
search_text | Always | NO — process.env / os.environ / import.meta.env scan |
search_patterns | Always | NO — ENV2/ENV3/ENV6 anti-patterns |
find_references | Always | NO — ENV2 unused detection |
audit_scan | Always | NO — compound check |
Forbidden: scan_secrets: skipped, codesift: unavailable (when deferred), retrospective: skipped — all REJECTED.
POSTAMBLE: report on disk → retro appended → ~/.zuvo/append-runlog exit 0. Every ENV finding needs path/to/file.ext:LINE (verify-audit gate).
Mandatory-tools-acknowledgment: I will run scan_secrets + search_text + search_patterns + find_references + audit_scan for this env audit. Every ENV finding will cite a `path/to/file.ext:LINE` resolving in the current tree.Use the deterministic preload helper FIRST. Run ~/.zuvo/compute-preload env-audit "$PWD". Copy [CodeSift matching trace] verbatim, issue printed ToolSearch(query="select:..."). Math gate enforced.
Phase 0: Detect and Scope
0.1 Target Resolution
Set TARGET_ROOT from arguments. All subsequent commands use this path.
0.2 Stack Detection
Detect which env access patterns to search for:
| Signal | Stack | Access Pattern |
package.json | Node.js | process.env.VAR, process.env['VAR'] |
vite.config.* | Vite | import.meta.env.VITE_VAR |
next.config.* | Next.js | process.env.NEXT_PUBLIC_VAR (client-safe) |
requirements.txt, pyproject.toml | Python | os.environ['VAR'], os.getenv('VAR'), os.environ.get('VAR') |
wrangler.toml | Cloudflare Workers | env.VAR (binding) |
docker-compose.* | Docker Compose | environment: / env_file: directives |
0.3 Variable Name Extraction
Build a comprehensive inventory by scanning code for all env access patterns detected in 0.2. Collect unique variable names (not values).
0.4 Inventory
Cross-reference all sources:
- Variables defined in
.env*files (names only) - Variables accessed in code (from extraction)
- Variables in Docker Compose, CI config, or cloud deployment files
Print:
ENV VAR INVENTORY
------------------------------------
Target: [TARGET_ROOT]
Config sources: [.env, .env.example, .env.local, ...]
Stack: [Node.js / Python / Vite / Next.js]
Vars defined: [N]
Vars used in code: [N]
------------------------------------Phase 1: Dimension Analysis (ENV1-ENV8)
Single-pass inline execution. No sub-agents required.
ENV1: Variable Completeness -- Weight 15, Max 15, Critical Gate
Are all required env vars defined and documented?
| Check | Good | Bad | Severity |
| Code vs example coverage | All used vars listed in .env.example | Var used in code but missing from .env.example | CRITICAL |
| Required vars guarded | Startup fails fast on missing required var | App starts, crashes later when var accessed | CRITICAL |
| .env.example exists | Yes, with all vars and placeholder values | No .env.example at all | HIGH |
| Stale vars | No vars in .env.example that are unused in code | Accumulated dead config | MEDIUM |
Detection approach: Compare the set of variables found in code against the
set defined in .env.example. Report both directions: used-but-undocumented
and documented-but-unused.
Critical gate: no .env.example OR multiple critical vars undocumented → triggers FAIL. The gate fires on that FINDING; an ENV1 score of 0 also fires it but is not required.
ENV2: Unused Variables -- Weight 5, Max 5
| Check | Good | Bad | Severity |
| Defined but never used | All defined vars referenced in code | Stale vars accumulate | MEDIUM |
| Dead config sections | Removed features cleaned up | Config references removed features | LOW |
Detection approach: Check each var in .env.example against code access
patterns. A var referenced only in comments or documentation counts as unused.
ENV3: Startup Validation -- Weight 15, Max 15, Critical Gate
Does the app fail fast on missing or invalid configuration?
| Check | Good | Bad | Severity |
| Schema validation | Zod/Joi/Pydantic/envalid validates all vars at startup | No validation, raw access everywhere | CRITICAL |
| Fail-fast behavior | App throws before serving requests on missing var | Starts, breaks when var first accessed | CRITICAL |
| Type coercion | Parsed and validated (parseInt, Number, schema) | Port used as string in numeric context | HIGH |
What to search for:
- Validation libraries:
z.object,Joi.object,BaseSettings,envalid,envsafe,convict,cleanEnv,ConfigModule,@IsString - Fail-fast patterns:
throwwith env/config message,process.exiton missing env - Raw usage:
process.env.VARwithout validation wrapper - NestJS:
ConfigModule.forRoot()withvalidationSchema
Critical gate: no validation anywhere → triggers FAIL. The gate fires on that FINDING; an ENV3 score of 0 also fires it but is not required.
ENV4: Secret Exposure -- Weight 15, Max 15, Critical Gate
| Check | Good | Bad | Severity |
| .env in .gitignore | .env and .env.local listed in .gitignore | .env committed to repository | CRITICAL |
| Client-side exposure | Only NEXT_PUBLIC_/VITE_ vars are non-sensitive | API keys in NEXT_PUBLIC_* variables | CRITICAL |
| Hardcoded secrets | Secrets only in env vars or secret manager | API keys hardcoded in config files | CRITICAL |
| Docker image leakage | .env listed in .dockerignore | .env copied into Docker image | HIGH |
| Git history | No .env files in git history | Past .env commits (secrets may still be in history) | HIGH |
Detection approach:
- Check
.gitignorefor.envpatterns git ls-filesfor committed.envfiles- Search for
NEXT_PUBLIC_*KEY,NEXT_PUBLIC_*SECRET,VITE_*KEYetc. - Search for hardcoded secrets:
(api_key|secret|password|token)\s*[:=]\s*['"][^'"{}$]excluding test/mock/example files - Check
.dockerignorefor.env
Critical gate: secrets committed or API keys in client-side vars → triggers FAIL. The gate fires on that FINDING; an ENV4 score of 0 also fires it but is not required.
ENV5: Environment Parity -- Weight 10, Max 10
Are dev/staging/production environments consistent?
| Check | Good | Bad | Severity |
| Same var set across envs | All environments define the same variables | Prod has vars dev lacks | HIGH |
| Docker Compose alignment | docker-compose env matches app config | Docker sets vars not in .env.example | MEDIUM |
| Feature flag documentation | Feature flags documented per environment | Undocumented per-env behavior | MEDIUM |
Detection approach: Compare variable sets across all .env* files found
at the target root. Check Docker Compose environment: sections against the
.env.example inventory.
ENV6: Type Safety -- Weight 8, Max 8
| Check | Good | Bad | Severity |
| Central config module | Typed config with validated accessors | Raw process.env.X scattered across 50+ files | HIGH |
| Boolean parsing | === 'true' or schema-parsed | if (process.env.FLAG) (any string is truthy) | HIGH |
| Number parsing | parseInt with NaN check or schema | Port used as string | MEDIUM |
| Access centralization | < 3 files access process.env directly | 20+ files with raw env access | MEDIUM |
Detection approach: Count per-file occurrences of raw env access. Search
for boolean truthy gotchas (if (process.env.VAR)). Check for number
conversion patterns.
ENV7: Default Values -- Weight 7, Max 7
| Check | Good | Bad | Severity |
| Dev-friendly defaults | PORT ?? 3000 for local development | App crashes without complete .env | MEDIUM |
| No secret defaults | Secret vars always required, no fallback | JWT_SECRET ?? 'default-secret' | CRITICAL |
| Documented defaults | .env.example shows which vars have defaults | Developer cannot tell required vs optional | LOW |
Detection approach:
- Search for
??and||operators after env access (Node.js) - Search for
os.getenv('VAR', 'default')patterns (Python) - Flag any default on SECRET/KEY/PASSWORD/TOKEN variables
ENV8: Documentation -- Weight 5, Max 5
| Check | Good | Bad | Severity |
| Inline comments | Each var in .env.example has a comment explaining purpose | Bare variable names only | MEDIUM |
| Required vs optional | Marked with # Required / # Optional (default: 3000) | No indication which vars are needed | MEDIUM |
| Setup instructions | README covers env setup | New developer has to guess | LOW |
Phase 2: Scoring
ENV1 = [0-15] Variable Completeness (critical gate)
ENV2 = [0-5] Unused Variables
ENV3 = [0-15] Startup Validation (critical gate)
ENV4 = [0-15] Secret Exposure (critical gate)
ENV5 = [0-10] Environment Parity
ENV6 = [0-8] Type Safety
ENV7 = [0-7] Default Values
ENV8 = [0-5] DocumentationScore = sum / 80 x 100
Critical gates — any ONE of these findings triggers FAIL, whatever the numeric score:
| Gate | Fires on |
| ENV1 | no .env.example, OR multiple critical vars undocumented |
| ENV3 | no startup validation anywhere |
| ENV4 | any secret committed to the repo, OR an API key in a client-side (NEXT_PUBLIC_/VITE_) var, OR a hardcoded secret |
These gates fire on the FINDING, not on an aggregate score of zero. Read as "the dimension
scored 0" they are nearly unreachable, because every one of them spreads several checks over its
weight: ENV4 carries five checks across 15 points, so a repo with a committed .env but a correct .gitignore, no client-side leak and no hardcoded key still scores about 12/15 — and the committed secret never blocks the audit. The named condition in each parenthesis IS the trigger — a dimension score of 0
remains sufficient to fire the gate, it is simply not necessary.
| Grade | Percentage |
| HEALTHY | >= 80% |
| NEEDS ATTENTION | >= 60% and < 80% |
| AT RISK | >= 40% and < 60% |
| CRITICAL | < 40% |
Phase 3: Report
Save to: zuvo/audits/env-audit-[YYYY-MM-DD].md — at the project root (zuvo/ resolves via git rev-parse --show-toplevel; override $ZUVO_OUTPUT_DIR. See ../../shared/includes/report-output-location.md).
Report Structure
# Environment & Configuration Audit Report
## Metadata
| Field | Value |
|-------|-------|
| Project | [name] |
| Date | [YYYY-MM-DD] |
| Scope | [TARGET_ROOT or full project] |
| Stack | [Node.js / Python / Vite / Next.js] |
| Config sources | [.env, .env.example, config.ts, ...] |
| Vars defined | [N] |
| Vars used in code | [N] |
## Executive Summary
**Score: [N] / 100** -- [HEALTHY / NEEDS ATTENTION / AT RISK / CRITICAL]
| Metric | Count |
|--------|-------|
| CRITICAL findings | N |
| HIGH findings | N |
| MEDIUM findings | N |
[2-3 sentence summary]
## Dimension Scores
| # | Dimension | Score | Max | Notes |
|---|-----------|-------|-----|-------|
| ENV1 | Variable Completeness | [N] | 15 | |
| ENV2 | Unused Variables | [N] | 5 | |
| ENV3 | Startup Validation | [N] | 15 | |
| ENV4 | Secret Exposure | [N] | 15 | |
| ENV5 | Environment Parity | [N] | 10 | |
| ENV6 | Type Safety | [N] | 8 | |
| ENV7 | Default Values | [N] | 7 | |
| ENV8 | Documentation | [N] | 5 | |
| **Total** | | **[N]** | **80** | |
## Variable Coverage Matrix
| Variable | .env.example | Code Usage | Validated | Type | Default | Secret? |
|----------|-------------|------------|-----------|------|---------|---------|
| DATABASE_URL | Y | Y (3 files) | Y (Zod) | string | none (required) | Y |
| PORT | Y | Y (1 file) | N (raw) | number | 3000 | N |
| ... | | | | | | |
## Findings (sorted by severity)
[Per finding: dimension, severity, file:line, description, fix]
## Remediation Roadmap
### Quick Wins (< 1 hour)
### Short-term (1 day)
### Medium-term (1 week)Report Validation
After writing, verify:
- Dimension scores sum to total
- Finding counts match Executive Summary
- Variable Coverage Matrix includes all discovered vars
- No actual secret values appear anywhere in the report (Gate 2)
Phase 4: Next-Step Routing
RECOMMENDED NEXT ACTION
------------------------------------
ENV4 CRITICAL (secrets exposed) -> /security-audit --static
ENV3 = 0 (no validation) -> add config schema (Zod/Joi/Pydantic)
ENV1 = 0 (no .env.example) -> create .env.example from code usage
ENV7 secret defaults -> remove default values from secret vars
Score < 60% -> fix critical gates, re-audit
Score >= 80% -> schedule next audit in 3 months
------------------------------------ENV-AUDIT COMPLETE
Score: [N] / 100 -- [grade] Stack: [Node.js / Python / Vite / Next.js] Dimensions: [N scored] | Critical gates: [PASS/FAIL] Findings: [N critical] / [N total]
Validity Gate (REQUIRED — print BEFORE Run line, AFTER retro append + append-runlog)
VALIDITY GATE
triggers_held: language=<X> framework=<X>
required_tool_calls:
scan_secrets: [<N> hits | NOT_CALLED — VIOLATES_TRIGGER]
search_text: [<N> env-var refs | NOT_CALLED — VIOLATES_TRIGGER]
search_patterns: [<N> hits | NOT_CALLED — VIOLATES_TRIGGER]
find_references: [<N> ref-checks | NOT_CALLED — VIOLATES_TRIGGER]
audit_scan: [<N> findings | NOT_CALLED — VIOLATES_TRIGGER]
postamble:
retros_log_appended: [yes(bytes_added=N) | NOT_APPENDED]
retros_md_appended: [yes(entry_count=N) | NOT_APPENDED]
verify_audit_pass: [yes(<verified>/<total>) | NOT_RUN | REJECTED]
gate_status: [PASS | FAIL — <which gates missing>]If gate_status = FAIL → VERDICT = INCOMPLETE.
Append the Run line via the retro-gated wrapper (NOT direct >> runs.log):
printf '%b\n' "$RUN_LINE" | ~/.zuvo/append-runlogRun: <ISO-8601-Z> env-audit <project> <N-critical> <N-total> <VERDICT> - <N>-dimensions <NOTES> <BRANCH> <SHA7> <INCLUDES> <TIER>
Retrospective (REQUIRED)
Follow the retrospective protocol from retrospective.md.
Gate check → structured questions → TSV emit → markdown append.
If gate check skips: print "RETRO: skipped (trivial session)" and proceed.
After printing this block, append the Run: line value (without the Run: prefix) to the log file path resolved per run-logger.md.
VERDICT: PASS (0 critical findings), WARN (1-3 critical), FAIL (4+ critical).
Execution Notes
- Single-pass inline execution, no sub-agents required
- All commands use the resolved
TARGET_ROOTfrom argument parsing - Stack detection auto-selects the correct env access patterns (Node.js, Python, Vite, Next.js)
- NestJS projects: check
ConfigModule.forRoot()andConfigServiceusage patterns specifically - Docker Compose: check both
environment:andenv_file:directives - Monorepos: use
[path]argument to scope to a specific package - CodeSift is minimally used in this skill (env patterns are best found via
grep), but
codesift-setup.mdis loaded for consistency - The boolean truthy gotcha (
if (process.env.FLAG)-- always true for any non-empty string) is a common source of production bugs; flag it prominently
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

